compressPhoto.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. //通过canvas将图片压缩至指定大小
  2. //判断图片大小是否满足需求,limitSize的单位是kb
  3. function imageSizeIsLessLimitSize(
  4. imagePath,
  5. limitSize,
  6. lessCallback,
  7. moreCallback
  8. ) {
  9. //获取文件信息
  10. wx.getFileSystemManager().getFileInfo({
  11. filePath: imagePath,
  12. success: (res) => {
  13. console.log("压缩前图片大小", res, res.size / 1024, "kb");
  14. if (res.size > limitSize) {
  15. moreCallback();
  16. } else {
  17. lessCallback();
  18. }
  19. },
  20. });
  21. }
  22. //将图片画在画布上并获取画好之后的图片的路径
  23. function getCanvasImage(canvasId, imagePath, imageW, imageH, getImgSuccess) {
  24. //创建画布内容
  25. const ctx = wx.createCanvasContext(canvasId);
  26. //图片画上去,imageW和imageH是画上去的尺寸,图像和画布间隔都是0
  27. ctx.drawImage(imagePath, 0, 0, imageW, imageH);
  28. //这里一定要加定时器,给足够的时间去画(所以每次递归最少要耗时200ms,多次递归很耗时!)
  29. ctx.draw(
  30. false,
  31. setTimeout(() => {
  32. //把当前画布指定区域的内容导出生成指定大小的图片,并返回文件路径
  33. wx.canvasToTempFilePath({
  34. canvasId: canvasId,
  35. x: 0,
  36. y: 0,
  37. width: imageW,
  38. height: imageH,
  39. quality: 1, // 取0-1,1最高质量
  40. fileType: "jpg",
  41. success: (res) => {
  42. console.log(res, 989898);
  43. //将取出的图片路径通过回调函数返回
  44. getImgSuccess(res.tempFilePath);
  45. },
  46. });
  47. }, 200)
  48. );
  49. }
  50. //主函数,默认限制大小2048kb即2mb,drawWidth是绘画区域的大小
  51. //初始值传入为画布自身的边长(我们这是一个正方形的画布)
  52. function getLessLimitSizeImage(
  53. canvasId,
  54. imagePath,
  55. limitSize = 1024,
  56. drawWidth,
  57. callback
  58. ) {
  59. //判断图片尺寸是否满足要求
  60. imageSizeIsLessLimitSize(
  61. imagePath,
  62. limitSize,
  63. (lessRes) => {
  64. //满足要求走callback,将压缩后的文件路径返回
  65. console.log("满足要求走callback:", imagePath);
  66. callback(imagePath);
  67. },
  68. (moreRes) => {
  69. //不满足要求需要压缩的时候
  70. wx.getImageInfo({
  71. src: imagePath,
  72. success: (imageInfo) => {
  73. let maxSide = Math.max(imageInfo.width, imageInfo.height);
  74. let windowW = drawWidth;
  75. let scale = 1;
  76. /*
  77. 这里的目的是当绘画区域缩小的比图片自身尺寸还要小的时候
  78. 取图片长宽的最大值,然后和当前绘画区域计算出需要放缩的比例
  79. 然后再画经过放缩后的尺寸,保证画出的一定是一个完整的图片。由于每次递归绘画区域都会缩小,
  80. 所以不用担心scale永远都是1绘画尺寸永远不变的情况,只要不满足压缩后体积的要求
  81. 就会缩小绘画区域,早晚会有绘画区域小于图片尺寸的情况发生
  82. */
  83. if (maxSide > windowW) {
  84. scale = windowW / maxSide;
  85. }
  86. //trunc是去掉小数
  87. let imageW = Math.trunc(imageInfo.width * scale);
  88. let imageH = Math.trunc(imageInfo.height * scale);
  89. // console.log('调用压缩',imageW,imageH);
  90. //图片在规定绘画区域上画并获取新的图片的path
  91. getCanvasImage(
  92. canvasId,
  93. imagePath,
  94. imageW,
  95. imageH,
  96. (pressImgPath) => {
  97. /*
  98. 再去检查是否满足要求,始终缩小绘画区域,让图片适配绘画区域
  99. 这里乘以0.95是必须的,如果不缩小绘画区域,会出现尺寸比绘画区域小,
  100. 而体积比要求压缩体积大的情况出现,就会无穷递归下去,因为scale的值永远是1
  101. 但0.95不是固定的,你可以根据需要自己改,0到1之间,越小则绘画区域缩小的越快
  102. 但不建议取得太小,绘画区域缩小的太快,压出来的将总是很糊的
  103. */
  104. getLessLimitSizeImage(
  105. canvasId,
  106. pressImgPath,
  107. limitSize,
  108. drawWidth * 0.95,
  109. callback
  110. );
  111. }
  112. );
  113. },
  114. });
  115. }
  116. );
  117. }
  118. function compressWx(url, quality, cb) {
  119. //不满足要求需要压缩的时候
  120. wx.getImageInfo({
  121. src: url,
  122. success: (imageInfo) => {
  123. let maxSide = Math.max(imageInfo.width, imageInfo.height);
  124. let windowW = drawWidth;
  125. let scale = 1;
  126. if (maxSide > windowW) {
  127. scale = windowW / maxSide;
  128. }
  129. //trunc是去掉小数
  130. let imageW = Math.trunc(imageInfo.width * scale);
  131. let imageH = Math.trunc(imageInfo.height * scale);
  132. //创建画布内容
  133. const ctx = wx.createCanvasContext(canvasId);
  134. //图片画上去,imageW和imageH是画上去的尺寸,图像和画布间隔都是0
  135. ctx.drawImage(imagePath, 0, 0, imageW, imageH);
  136. //这里一定要加定时器,给足够的时间去画(所以每次递归最少要耗时200ms,多次递归很耗时!)
  137. ctx.draw(
  138. false,
  139. setTimeout(() => {
  140. //把当前画布指定区域的内容导出生成指定大小的图片,并返回文件路径
  141. wx.canvasToTempFilePath({
  142. canvasId: canvasId,
  143. x: 0,
  144. y: 0,
  145. width: imageW,
  146. height: imageH,
  147. quality: quality, // 取0-1,1最高质量
  148. fileType: "jpg",
  149. success: (res) => {
  150. cb(res.tempFilePath);
  151. },
  152. });
  153. }, 200)
  154. );
  155. },
  156. });
  157. }
  158. function compressH5(url, quality, cb) {
  159. let image = new Image();
  160. image.onload = function () {
  161. var h = this.height * (quality / 1); // 默认按比例压缩
  162. var w = this.width * (quality / 1);
  163. var canvas = document.createElement("canvas");
  164. var ctx = canvas.getContext("2d");
  165. var anw = document.createAttribute("width");
  166. anw.nodeValue = w;
  167. var anh = document.createAttribute("height");
  168. anh.nodeValue = h;
  169. canvas.setAttributeNode(anw);
  170. canvas.setAttributeNode(anh);
  171. ctx.drawImage(image, 0, 0, w, h); //压缩比例
  172. var base64 = canvas.toDataURL("image/jpeg", quality);
  173. cb(base64);
  174. };
  175. image.src = url;
  176. image.setAttribute("crossOrigin", "Anonymous");
  177. image.onerror = () => {
  178. reject(new Error("urlToBase64 error"));
  179. };
  180. }
  181. function myCompressImage(url, limitSize = 2048, cb) {
  182. limitSize = limitSize * 1024;
  183. const size = url.size;
  184. if (size < limitSize) {
  185. return cb(url);
  186. }
  187. const quality = limitSize / size;
  188. // #ifdef MP-WEIXIN
  189. let canvasId = "zipCanvas";
  190. let drawWidth = wx.getSystemInfoSync().windowWidth;
  191. getLessLimitSizeImage(canvasId, url.path, limitSize, drawWidth, cb);
  192. // #endif
  193. // #ifdef H5
  194. compressH5(url.path, quality, cb);
  195. // #endif
  196. }
  197. export default myCompressImage;