webp.html 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>webp</title>
  6. <style>
  7. #image-display, #image-display2, #image-display3 {
  8. max-width: 45%;
  9. max-height: 45%;
  10. border: 1px solid gray;
  11. }
  12. </style>
  13. <script src="js/conversion.js"></script>
  14. </head>
  15. <body>
  16. <h1>粘贴图片并展示</h1>
  17. <p>右键粘贴图片,本地图片或网络图片地址都可以,将被压缩为webp格式并展示,压缩前:<span id="preSize"></span>, 压缩后:<span id="afterSize"></span><span id="status"></span>&nbsp;。&nbsp;
  18. <button onclick="rotateImage()">旋转90度</button> &nbsp;。&nbsp;
  19. <!-- <button onclick="bigImage()">放大</button> &nbsp;。&nbsp;-->
  20. <!-- <button onclick="smallImage()">缩小</button> &nbsp;。&nbsp;-->
  21. </p>
  22. <div id="image-container">
  23. <div>base64 webp</div>
  24. <img id="image-display" src="" alt="Image Display">
  25. <div>本地 png < 300k</div>
  26. <img id="image-display3" src="" alt="Image Display">
  27. </div>
  28. <script>
  29. const imageDisplay = document.getElementById("image-display");
  30. function formatSize(sizeInBytes) {
  31. const sizeInKb = sizeInBytes / 1024;
  32. const sizeInMb = sizeInBytes / 1048576;
  33. if (sizeInMb >= 1) {
  34. return `${sizeInMb.toFixed(2)} MB`;
  35. } else {
  36. return `${sizeInKb.toFixed(2)} KB`;
  37. }
  38. }
  39. // 监听粘贴事件
  40. document.addEventListener("paste", (event) => {
  41. handleClipboardItems(event.clipboardData.items);
  42. });
  43. // 监听拖拽事件
  44. document.addEventListener("dragover", (event) => {
  45. event.preventDefault();
  46. });
  47. document.addEventListener("drop", (event) => {
  48. event.preventDefault();
  49. handleClipboardItems(event.dataTransfer.items);
  50. });
  51. function compressImageToSize(blobFile, targetSize = 300 * 1024, maxIterations = 15, minQuality = 0.001) {
  52. let currentQuality = 0.8; // 初始压缩质量
  53. let iteration = 0; // 当前迭代次数
  54. function compressImage(blobFile, quality = 0.8) {
  55. // 返回一个Promise对象
  56. return new Promise((resolve, reject) => {
  57. // 创建一个Image对象
  58. const image = new Image();
  59. // 当Image对象加载完成时,执行以下操作
  60. image.onload = () => {
  61. const canvas = document.createElement("canvas");
  62. canvas.width = image.naturalWidth;
  63. canvas.height = image.naturalHeight;
  64. const context = canvas.getContext("2d");
  65. context.drawImage(image, 0, 0);
  66. canvas.toBlob((webpBlob) => {
  67. // 解决Promise,并传递压缩后的Blob对象
  68. resolve(webpBlob);
  69. }, "image/webp", quality);
  70. // 如果在转换过程中发生错误,拒绝Promise
  71. };
  72. image.src = URL.createObjectURL(blobFile);
  73. });
  74. }
  75. function attemptCompression() {
  76. return new Promise((resolve, reject) => {
  77. // 递归调用compressImage函数进行压缩
  78. compressImage(blobFile, currentQuality).then(compressedBlob => {
  79. // 检查压缩后的文件大小是否满足条件
  80. if (compressedBlob.size <= targetSize) {
  81. // 如果压缩后的文件大小小于或等于目标大小,则解决Promise
  82. resolve(compressedBlob);
  83. } else if (iteration < maxIterations && currentQuality > minQuality) {
  84. // 如果还未达到最大迭代次数且质量还可以降低,则递减质量并再次尝试压缩
  85. currentQuality *= 0.7; // 每次迭代降低质量的百分比
  86. blobFile = compressedBlob; // 使用上一次压缩的结果作为下一次的输入
  87. iteration++; // 增加迭代次数
  88. // 打印当前大小和迭代次数
  89. console.log(`Current Size: ${formatSize(compressedBlob.size)} | Iteration: ${iteration}`);
  90. attemptCompression().then(resolve).catch(reject);
  91. } else {
  92. // 如果已经达到最大迭代次数或者质量已经很低,拒绝Promise
  93. alert("压缩失败,图片太大。");
  94. reject(new Error("Unable to compress the image to the target size."));
  95. }
  96. }).catch(reject);
  97. });
  98. }
  99. // 启动压缩过程
  100. return new Promise((resolve, reject) => {
  101. attemptCompression().then(resolve).catch(reject);
  102. });
  103. }
  104. // 处理粘贴板或拖拽项
  105. function handleClipboardItems(items) {
  106. if (!items) {
  107. return;
  108. }
  109. // 查找图片数据
  110. for (let i = 0; i < items.length; i++) {
  111. if (items[i].type.indexOf("image") !== -1) {
  112. document.getElementById("preSize").innerText = "";
  113. document.getElementById("afterSize").innerText = "";
  114. // 获取图片文件或URL
  115. const blobFile = items[i].getAsFile();
  116. // 将图片展示
  117. document.getElementById("status").innerText = " 压缩中……";
  118. document.getElementById("preSize").innerText = formatSize(blobFile.size);
  119. // 压缩为webp格式
  120. compressImageToSize(blobFile).then(webpBlob => {
  121. // 将压缩后的webp图片展示在页面上
  122. // imageDisplay.src = URL.createObjectURL(webpBlob);
  123. const reader = new FileReader();
  124. reader.onloadend = () => {
  125. imageDisplay.src = reader.result;
  126. // toWebP();
  127. toPng();
  128. };
  129. reader.readAsDataURL(webpBlob);
  130. showSize(webpBlob);
  131. });
  132. // 防止页面跳转
  133. event.preventDefault();
  134. break
  135. }
  136. }
  137. }
  138. function showSize(webpBlob) {
  139. document.getElementById("status").innerText = " 已压缩 ☺";
  140. document.getElementById("afterSize").innerText = formatSize(webpBlob.size);
  141. }
  142. // 选择90度旋转
  143. function rotateImage() {
  144. const image = document.getElementById("image-display");
  145. const canvas = document.createElement("canvas");
  146. const context = canvas.getContext("2d");
  147. // 旋转90度
  148. canvas.width = image.height;
  149. canvas.height = image.width;
  150. context.rotate(90 * Math.PI / 180);
  151. context.drawImage(image, 0, -canvas.width);
  152. // 将旋转后的图片展示在页面上
  153. const rotatedImageUrl = canvas.toDataURL();
  154. image.src = rotatedImageUrl;
  155. }
  156. function base64ToPng(base64Data, callBack) {
  157. // 创建一个新的 Image 对象
  158. const img = new Image();
  159. // 当图像加载完成时执行转换逻辑
  160. img.onload = function () {
  161. // 创建一个新的 Canvas 元素
  162. const canvas = document.createElement('canvas');
  163. const ctx = canvas.getContext('2d');
  164. // 设置 Canvas 的尺寸与图像一样
  165. canvas.width = img.width;
  166. canvas.height = img.height;
  167. // 将 base64 图像绘制到 Canvas 上
  168. ctx.drawImage(img, 0, 0);
  169. // 将 Canvas 转换为 PNG 格式的 Blob 对象
  170. canvas.toBlob(function (blob) {
  171. // 将 Blob 对象传递给其他地方使用,比如保存到本地或上传到服务器
  172. // 这里我们简单地打印 Blob 对象的大小和类型
  173. console.log("生成的 PNG Blob 大小:", blob.size, "类型:", blob.type);
  174. callBack(blob);
  175. }, 'image/png');
  176. };
  177. // 设置图像的 src 为 base64 数据
  178. img.src = base64Data;
  179. }
  180. function toPng() {
  181. // 将base64图片转为本地路径
  182. const image = document.getElementById("image-display");
  183. base64ToPng(image.src, function (blob) {
  184. imageConversion.compressAccurately(blob, 300).then(res => {
  185. console.log(res);
  186. document.getElementById("image-display3").src = URL.createObjectURL(res);
  187. })
  188. })
  189. }
  190. </script>
  191. </body>
  192. </html>