webp.html 6.4 KB

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