webp.html 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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 = 5, minQuality = 0.01) {
  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.8; // 每次迭代降低质量的百分比
  86. blobFile = compressedBlob; // 使用上一次压缩的结果作为下一次的输入
  87. iteration++; // 增加迭代次数
  88. attemptCompression().then(resolve).catch(reject);
  89. } else {
  90. // 如果已经达到最大迭代次数或者质量已经很低,拒绝Promise
  91. reject(new Error("Unable to compress the image to the target size."));
  92. }
  93. }).catch(reject);
  94. });
  95. }
  96. // 启动压缩过程
  97. return new Promise((resolve, reject) => {
  98. attemptCompression().then(resolve).catch(reject);
  99. });
  100. }
  101. // 处理粘贴板或拖拽项
  102. function handleClipboardItems(items) {
  103. if (!items) {
  104. return;
  105. }
  106. // 查找图片数据
  107. for (let i = 0; i < items.length; i++) {
  108. if (items[i].type.indexOf("image") !== -1) {
  109. document.getElementById("preSize").innerText = "";
  110. document.getElementById("afterSize").innerText = "";
  111. // 获取图片文件或URL
  112. const blobFile = items[i].getAsFile();
  113. // 将图片展示
  114. document.getElementById("status").innerText = " 压缩中……";
  115. document.getElementById("preSize").innerText = formatSize(blobFile.size);
  116. // 压缩为webp格式
  117. compressImageToSize(blobFile).then(webpBlob => {
  118. // 将压缩后的webp图片展示在页面上
  119. // imageDisplay.src = URL.createObjectURL(webpBlob);
  120. const reader = new FileReader();
  121. reader.onloadend = () => {
  122. imageDisplay.src = reader.result;
  123. // toWebP();
  124. toPng();
  125. };
  126. reader.readAsDataURL(webpBlob);
  127. showSize(webpBlob);
  128. });
  129. // 防止页面跳转
  130. event.preventDefault();
  131. break
  132. }
  133. }
  134. }
  135. function showSize(webpBlob) {
  136. document.getElementById("status").innerText = " 已压缩 ☺";
  137. document.getElementById("afterSize").innerText = formatSize(webpBlob.size);
  138. }
  139. // 选择90度旋转
  140. function rotateImage() {
  141. const image = document.getElementById("image-display");
  142. const canvas = document.createElement("canvas");
  143. const context = canvas.getContext("2d");
  144. // 旋转90度
  145. canvas.width = image.height;
  146. canvas.height = image.width;
  147. context.rotate(90 * Math.PI / 180);
  148. context.drawImage(image, 0, -canvas.width);
  149. // 将旋转后的图片展示在页面上
  150. const rotatedImageUrl = canvas.toDataURL();
  151. image.src = rotatedImageUrl;
  152. }
  153. function base64ToPng(base64Data, callBack) {
  154. // 创建一个新的 Image 对象
  155. const img = new Image();
  156. // 当图像加载完成时执行转换逻辑
  157. img.onload = function () {
  158. // 创建一个新的 Canvas 元素
  159. const canvas = document.createElement('canvas');
  160. const ctx = canvas.getContext('2d');
  161. // 设置 Canvas 的尺寸与图像一样
  162. canvas.width = img.width;
  163. canvas.height = img.height;
  164. // 将 base64 图像绘制到 Canvas 上
  165. ctx.drawImage(img, 0, 0);
  166. // 将 Canvas 转换为 PNG 格式的 Blob 对象
  167. canvas.toBlob(function (blob) {
  168. // 将 Blob 对象传递给其他地方使用,比如保存到本地或上传到服务器
  169. // 这里我们简单地打印 Blob 对象的大小和类型
  170. console.log("生成的 PNG Blob 大小:", blob.size, "类型:", blob.type);
  171. callBack(blob);
  172. }, 'image/png');
  173. };
  174. // 设置图像的 src 为 base64 数据
  175. img.src = base64Data;
  176. }
  177. function toPng() {
  178. // 将base64图片转为本地路径
  179. const image = document.getElementById("image-display");
  180. base64ToPng(image.src, function (blob) {
  181. imageConversion.compressAccurately(blob, 300).then(res => {
  182. console.log(res);
  183. document.getElementById("image-display3").src = URL.createObjectURL(res);
  184. })
  185. })
  186. }
  187. </script>
  188. </body>
  189. </html>