helang-compress.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. <template>
  2. <view class="compress" v-if="canvasId">
  3. <canvas :canvas-id="canvasId" :style="{ width: canvasSize.width,height: canvasSize.height}"></canvas>
  4. </view>
  5. </template>
  6. <script>
  7. export default {
  8. data() {
  9. return {
  10. pic:'',
  11. canvasSize: {
  12. width: 0,
  13. height: 0
  14. },
  15. canvasId:""
  16. }
  17. },
  18. mounted() {
  19. if(!uni || !uni._helang_compress_canvas){
  20. uni._helang_compress_canvas = 1;
  21. }else{
  22. uni._helang_compress_canvas++;
  23. }
  24. this.canvasId = `compress-canvas${uni._helang_compress_canvas}`;
  25. },
  26. methods: {
  27. // 压缩
  28. compressFun(params) {
  29. return new Promise(async (resolve, reject) => {
  30. // 等待图片信息
  31. let info = await this.getImageInfo(params.src).then(info=>info).catch(()=>null);
  32. if(!info){
  33. reject('获取图片信息异常');
  34. return;
  35. }
  36. // 设置最大 & 最小 尺寸
  37. const maxSize = params.maxSize || 1080;
  38. const minSize = params.minSize || 640;
  39. // 当前图片尺寸
  40. let {width,height} = info;
  41. // 非 H5 平台进行最小尺寸校验
  42. // #ifndef H5
  43. if(width <= minSize && height <= minSize){
  44. resolve(params.src);
  45. return;
  46. }
  47. // #endif
  48. // 最大尺寸计算
  49. if (width > maxSize || height > maxSize) {
  50. if (width > height) {
  51. height = Math.floor(height / (width / maxSize));
  52. width = maxSize;
  53. } else {
  54. width = Math.floor(width / (height / maxSize));
  55. height = maxSize;
  56. }
  57. }
  58. // 设置画布尺寸
  59. this.$set(this,"canvasSize",{
  60. width: `${width}px`,
  61. height: `${height}px`
  62. });
  63. // Vue.nextTick 回调在 App 有异常,则使用 setTimeout 等待DOM更新
  64. setTimeout(() => {
  65. const ctx = uni.createCanvasContext(this.canvasId, this);
  66. ctx.clearRect(0,0,width, height)
  67. ctx.drawImage(info.path, 0, 0, width, height);
  68. ctx.draw(false, () => {
  69. uni.canvasToTempFilePath({
  70. x: 0,
  71. y: 0,
  72. width: width,
  73. height: height,
  74. destWidth: width,
  75. destHeight: height,
  76. canvasId: this.canvasId,
  77. fileType: params.fileType || 'png',
  78. quality: params.quality || 0.9,
  79. success: (res) => {
  80. // 在H5平台下,tempFilePath 为 base64
  81. resolve(res.tempFilePath);
  82. },
  83. fail:(err)=>{
  84. reject(null);
  85. }
  86. },this);
  87. });
  88. }, 300);
  89. });
  90. },
  91. // 获取图片信息
  92. getImageInfo(src){
  93. return new Promise((resolve, reject)=>{
  94. uni.getImageInfo({
  95. src,
  96. success: (info)=> {
  97. resolve(info);
  98. },
  99. fail: () => {
  100. reject(null);
  101. }
  102. });
  103. });
  104. },
  105. // 批量压缩
  106. compress(params){
  107. // index:进度,done:成功,fail:失败
  108. let [index,done,fail] = [0,0,0];
  109. // 压缩完成的路径集合
  110. let paths = [];
  111. // 待压缩的图片
  112. let waitList = [];
  113. if(typeof params.src == 'string'){
  114. waitList = [params.src];
  115. }else{
  116. waitList = params.src;
  117. }
  118. // 批量压缩方法
  119. let batch = ()=>{
  120. return new Promise((resolve, reject)=>{
  121. // 开始
  122. let start = async ()=>{
  123. // 等待图片压缩方法返回
  124. let path = await next().catch(()=>null);
  125. if(path){
  126. done++;
  127. paths.push(path);
  128. }else{
  129. fail++;
  130. }
  131. params.progress && params.progress({
  132. done,
  133. fail,
  134. count:waitList.length
  135. });
  136. index++;
  137. // 压缩完成
  138. if(index >= waitList.length){
  139. resolve(true);
  140. }else{
  141. start();
  142. }
  143. }
  144. start();
  145. });
  146. }
  147. // 依次调用压缩方法
  148. let next = ()=>{
  149. return this.compressFun({
  150. src:waitList[index],
  151. maxSize:params.maxSize,
  152. fileType:params.fileType,
  153. quality:params.quality,
  154. minSize:params.minSize
  155. })
  156. }
  157. // 全部压缩完成后调用
  158. return new Promise(async (resolve, reject)=>{
  159. // 批量压缩方法回调
  160. let res = await batch();
  161. if(res){
  162. if(typeof params.src == 'string'){
  163. resolve(paths[0]);
  164. }else{
  165. resolve(paths);
  166. }
  167. }else{
  168. reject(null);
  169. }
  170. });
  171. }
  172. }
  173. }
  174. </script>
  175. <style lang="scss" scoped>
  176. .compress{
  177. position: fixed;
  178. width: 12px;
  179. height: 12px;
  180. overflow: hidden;
  181. top: -99999px;
  182. left: 0;
  183. }
  184. </style>