webp.html 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>webp</title>
  6. <style>
  7. #image-display {
  8. max-width: 100%;
  9. max-height: 100%;
  10. border: 1px solid gray;
  11. }
  12. </style>
  13. </head>
  14. <body>
  15. <h1>粘贴图片并展示</h1>
  16. <p>右键粘贴图片,本地图片或网络图片地址都可以,将被压缩为webp格式并展示,压缩前:<span id="preSize"></span>, 压缩后:<span id="afterSize"></span><span id="status"></span>&nbsp;。&nbsp;<button onclick="rotateImage()">旋转90度</button>
  17. </p>
  18. <div id="image-container">
  19. <img id="image-display" src="" alt="Image Display">
  20. </div>
  21. <script>
  22. const imageDisplay = document.getElementById("image-display");
  23. function formatSize(sizeInBytes) {
  24. const sizeInKb = sizeInBytes / 1024;
  25. const sizeInMb = sizeInBytes / 1048576;
  26. if (sizeInMb >= 1) {
  27. return `${sizeInMb.toFixed(2)} MB`;
  28. } else {
  29. return `${sizeInKb.toFixed(2)} KB`;
  30. }
  31. }
  32. // 监听粘贴事件
  33. document.addEventListener("paste", (event) => {
  34. handleClipboardItems(event.clipboardData.items);
  35. });
  36. // 监听拖拽事件
  37. document.addEventListener("dragover", (event) => {
  38. event.preventDefault();
  39. });
  40. document.addEventListener("drop", (event) => {
  41. event.preventDefault();
  42. handleClipboardItems(event.dataTransfer.items);
  43. });
  44. function compressImageToSize(blobFile, targetSize = 300 * 1024, maxIterations = 5, minQuality = 0.01) {
  45. let currentQuality = 0.8; // 初始压缩质量
  46. let iteration = 0; // 当前迭代次数
  47. function compressImage(blobFile, quality = 0.8) {
  48. // 返回一个Promise对象
  49. return new Promise((resolve, reject) => {
  50. // 创建一个Image对象
  51. const image = new Image();
  52. // 当Image对象加载完成时,执行以下操作
  53. image.onload = () => {
  54. const canvas = document.createElement("canvas");
  55. canvas.width = image.naturalWidth;
  56. canvas.height = image.naturalHeight;
  57. const context = canvas.getContext("2d");
  58. context.drawImage(image, 0, 0);
  59. canvas.toBlob((webpBlob) => {
  60. // 解决Promise,并传递压缩后的Blob对象
  61. resolve(webpBlob);
  62. }, "image/webp", quality);
  63. // 如果在转换过程中发生错误,拒绝Promise
  64. };
  65. image.src = URL.createObjectURL(blobFile);
  66. });
  67. }
  68. function attemptCompression() {
  69. return new Promise((resolve, reject) => {
  70. // 递归调用compressImage函数进行压缩
  71. compressImage(blobFile, currentQuality).then(compressedBlob => {
  72. // 检查压缩后的文件大小是否满足条件
  73. if (compressedBlob.size <= targetSize) {
  74. // 如果压缩后的文件大小小于或等于目标大小,则解决Promise
  75. resolve(compressedBlob);
  76. } else if (iteration < maxIterations && currentQuality > minQuality) {
  77. // 如果还未达到最大迭代次数且质量还可以降低,则递减质量并再次尝试压缩
  78. currentQuality *= 0.8; // 每次迭代降低质量的百分比
  79. blobFile = compressedBlob; // 使用上一次压缩的结果作为下一次的输入
  80. iteration++; // 增加迭代次数
  81. attemptCompression().then(resolve).catch(reject);
  82. } else {
  83. // 如果已经达到最大迭代次数或者质量已经很低,拒绝Promise
  84. reject(new Error("Unable to compress the image to the target size."));
  85. }
  86. }).catch(reject);
  87. });
  88. }
  89. // 启动压缩过程
  90. return new Promise((resolve, reject) => {
  91. attemptCompression().then(resolve).catch(reject);
  92. });
  93. }
  94. // 处理粘贴板或拖拽项
  95. function handleClipboardItems(items) {
  96. if (!items) {
  97. return;
  98. }
  99. // 查找图片数据
  100. for (let i = 0; i < items.length; i++) {
  101. if (items[i].type.indexOf("image") !== -1) {
  102. document.getElementById("preSize").innerText = "";
  103. document.getElementById("afterSize").innerText = "";
  104. // 获取图片文件或URL
  105. const blobFile = items[i].getAsFile();
  106. // 将图片展示
  107. document.getElementById("status").innerText = " 压缩中……";
  108. document.getElementById("preSize").innerText = formatSize(blobFile.size);
  109. // 压缩为webp格式
  110. compressImageToSize(blobFile).then(webpBlob => {
  111. // 将压缩后的webp图片展示在页面上
  112. imageDisplay.src = URL.createObjectURL(webpBlob);
  113. showSize(webpBlob);
  114. });
  115. // 防止页面跳转
  116. event.preventDefault();
  117. break
  118. }
  119. }
  120. }
  121. function showSize(webpBlob) {
  122. document.getElementById("status").innerText = " 已压缩 ☺";
  123. document.getElementById("afterSize").innerText = formatSize(webpBlob.size);
  124. }
  125. // 选择90度旋转
  126. function rotateImage() {
  127. const image = document.getElementById("image-display");
  128. const canvas = document.createElement("canvas");
  129. const context = canvas.getContext("2d");
  130. // 旋转90度
  131. canvas.width = image.height;
  132. canvas.height = image.width;
  133. context.rotate(90 * Math.PI / 180);
  134. context.drawImage(image, 0, -canvas.width);
  135. // 将旋转后的图片展示在页面上
  136. const rotatedImageUrl = canvas.toDataURL();
  137. image.src = rotatedImageUrl;
  138. }
  139. </script>
  140. </body>
  141. </html>