|
6 | 6 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
7 | 7 | <title>图片压缩工具</title> |
8 | 8 | <link rel="canonical" href="https://www.htmls.dev/tools/image-compressor/app.html"> |
| 9 | + <script src="https://cdn.jsdelivr.net/npm/pako@2.1.0/dist/pako.min.js" onerror="this.onerror=null;this.src='/assets/vendor/pako/pako.min.js';"></script> |
| 10 | + <script src="https://cdn.jsdelivr.net/npm/upng-js@2.1.0/UPNG.min.js" onerror="this.onerror=null;this.src='/assets/vendor/upng-js/UPNG.min.js';"></script> |
9 | 11 | <style> |
10 | 12 | :root { |
11 | 13 | --accent: #22c55e; |
@@ -220,6 +222,7 @@ <h1>图片压缩工具</h1> |
220 | 222 | const downloadLink = document.getElementById('download'); |
221 | 223 | let image = new Image(); |
222 | 224 | let originalSize = 0; |
| 225 | + let currentBlobUrl = null; |
223 | 226 |
|
224 | 227 | function formatBytes(bytes) { |
225 | 228 | if (!bytes) return '--'; |
@@ -263,18 +266,35 @@ <h1>图片压缩工具</h1> |
263 | 266 | ctx.drawImage(image, 0, 0); |
264 | 267 | const format = formatSelect.value; |
265 | 268 | const quality = parseFloat(qualityInput.value); |
266 | | - canvas.toBlob((blob) => { |
267 | | - if (!blob) return; |
| 269 | + |
| 270 | + const compressedUrlPromise = new Promise((resolve, reject) => { |
| 271 | + if (format === 'image/png' && typeof UPNG !== 'undefined') { |
| 272 | + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data; |
| 273 | + const cnum = Math.floor(quality * 256); |
| 274 | + const compressed = UPNG.encode([imageData.buffer], canvas.width, canvas.height, cnum); |
| 275 | + const blob = new Blob([compressed], { type: 'image/png' }); |
| 276 | + resolve(blob); |
| 277 | + } else { |
| 278 | + canvas.toBlob((blob) => { |
| 279 | + if (!blob) return; |
| 280 | + resolve(blob); |
| 281 | + }, format, quality); |
| 282 | + } |
| 283 | + }).then((blob) => { |
| 284 | + // 释放之前的 blob URL |
| 285 | + if (currentBlobUrl) { |
| 286 | + URL.revokeObjectURL(currentBlobUrl); |
| 287 | + } |
268 | 288 | const url = URL.createObjectURL(blob); |
| 289 | + currentBlobUrl = url; |
269 | 290 | const previewImg = new Image(); |
270 | | - previewImg.onload = () => URL.revokeObjectURL(url); |
271 | 291 | previewImg.src = url; |
272 | 292 | preview.innerHTML = ''; |
273 | 293 | preview.appendChild(previewImg); |
274 | 294 | downloadLink.href = url; |
275 | 295 | downloadLink.download = `compressed.${format.split('/')[1]}`; |
276 | 296 | sizeInfo.textContent = `原图大小:${formatBytes(originalSize)} / 压缩后:${formatBytes(blob.size)}`; |
277 | | - }, format, format === 'image/png' ? undefined : quality); |
| 297 | + }); |
278 | 298 | }); |
279 | 299 | </script> |
280 | 300 | <script src="/assets/clicks.js" defer></script> |
|
0 commit comments