@awesome-compressor/browser-compress-image
Version:
🚀 A powerful, lightweight browser image compression library with TypeScript support. Compress JPEG, PNG, GIF images with multiple output formats (Blob, File, Base64, ArrayBuffer) and zero dependencies.
104 lines (102 loc) • 3.84 kB
JavaScript
import { __esm, __export } from "./chunk-BaU5PcSi.js";
//#region src/tools/compressWithCanvas.ts
var compressWithCanvas_exports = {};
__export(compressWithCanvas_exports, { default: () => compressWithCanvas });
async function compressWithCanvas(file, options) {
const { quality, targetWidth, targetHeight, maxWidth, maxHeight } = options;
let finalWidth = targetWidth || maxWidth, finalHeight = targetHeight || maxHeight;
if (!finalWidth && !finalHeight) {
const { width, height } = await getImageDimensions(file);
finalWidth = width;
finalHeight = height;
}
return await smartCanvasCompress(file, finalWidth, finalHeight, quality);
}
async function smartCanvasCompress(file, targetWidth, targetHeight, quality) {
const originalSize = file.size;
const { width: originalWidth, height: originalHeight } = await getImageDimensions(file);
if (targetWidth === originalWidth && targetHeight === originalHeight && originalSize < 100 * 1024) return file;
if (file.type.includes("png")) {
const pngResult = await canvasCompressWithFormat(file, targetWidth, targetHeight, "image/png", void 0);
if (pngResult.size < originalSize * .98) return pngResult;
if (quality < .8) {
const jpegResult = await canvasCompressWithFormat(file, targetWidth, targetHeight, "image/jpeg", Math.max(.7, quality));
if (jpegResult.size < Math.min(pngResult.size, originalSize * .98)) return jpegResult;
}
if (pngResult.size >= originalSize * .98) return file;
return pngResult;
}
if (file.type.includes("jpeg") || file.type.includes("jpg")) {
const qualities = [
quality,
Math.max(.5, quality - .2),
Math.max(.3, quality - .4)
];
for (const q of qualities) {
const result$1 = await canvasCompressWithFormat(file, targetWidth, targetHeight, file.type, q);
if (result$1.size < originalSize * .98) return result$1;
}
return file;
}
const result = await canvasCompressWithFormat(file, targetWidth, targetHeight, file.type, quality);
if (result.size >= originalSize * .98) return file;
return result;
}
async function canvasCompressWithFormat(file, targetWidth, targetHeight, outputType, quality) {
return new Promise((resolve, reject) => {
const img = new Image();
const url = URL.createObjectURL(file);
img.onload = () => {
URL.revokeObjectURL(url);
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d", {
alpha: outputType.includes("png"),
willReadFrequently: false
});
if (!ctx) {
reject(/* @__PURE__ */ new Error("Failed to get canvas context"));
return;
}
canvas.width = targetWidth;
canvas.height = targetHeight;
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";
if (outputType.includes("jpeg") && !file.type.includes("jpeg")) {
ctx.fillStyle = "#FFFFFF";
ctx.fillRect(0, 0, targetWidth, targetHeight);
}
ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
canvas.toBlob((blob) => {
if (blob) resolve(blob);
else reject(/* @__PURE__ */ new Error("Failed to create blob"));
}, outputType, quality);
};
img.onerror = () => {
URL.revokeObjectURL(url);
reject(/* @__PURE__ */ new Error("Failed to load image"));
};
img.crossOrigin = "anonymous";
img.src = url;
});
}
function getImageDimensions(file) {
return new Promise((resolve, reject) => {
const img = new Image();
const url = URL.createObjectURL(file);
img.onload = () => {
URL.revokeObjectURL(url);
resolve({
width: img.width,
height: img.height
});
};
img.onerror = () => {
URL.revokeObjectURL(url);
reject(/* @__PURE__ */ new Error("Failed to load image"));
};
img.src = url;
});
}
var init_compressWithCanvas = __esm({ "src/tools/compressWithCanvas.ts"() {} });
//#endregion
export { compressWithCanvas, compressWithCanvas_exports, init_compressWithCanvas };