@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.
263 lines (260 loc) • 7.55 kB
JavaScript
import { __esm, __export } from "./chunk-BaU5PcSi.js";
//#region src/utils/lruCache.ts
var LRUCache;
var init_lruCache = __esm({ "src/utils/lruCache.ts"() {
LRUCache = class {
cache;
maxSize;
constructor(maxSize = 50) {
this.cache = /* @__PURE__ */ new Map();
this.maxSize = maxSize;
}
/**
* 获取缓存项,如果存在则将其移到最新位置
*/
get(key) {
const value = this.cache.get(key);
if (value !== void 0) {
this.cache.delete(key);
this.cache.set(key, value);
}
return value;
}
/**
* 设置缓存项,如果超过最大容量则淘汰最久未使用的项
*/
set(key, value) {
if (this.cache.has(key)) this.cache.delete(key);
else if (this.cache.size >= this.maxSize) {
const firstKey = this.cache.keys().next().value;
if (firstKey !== void 0) {
this.cache.delete(firstKey);
console.log(`LRU Cache: Removed least recently used entry for key: ${String(firstKey)}`);
}
}
this.cache.set(key, value);
}
/**
* 检查缓存中是否存在指定的key
*/
has(key) {
return this.cache.has(key);
}
/**
* 清空所有缓存
*/
clear() {
this.cache.clear();
}
/**
* 获取当前缓存大小
*/
get size() {
return this.cache.size;
}
/**
* 获取最大缓存大小
*/
get maxCapacity() {
return this.maxSize;
}
/**
* 设置新的最大缓存大小
*/
setMaxSize(newMaxSize) {
this.maxSize = newMaxSize;
while (this.cache.size > this.maxSize) {
const firstKey = this.cache.keys().next().value;
if (firstKey !== void 0) {
this.cache.delete(firstKey);
console.log(`LRU Cache: Removed entry due to size reduction: ${String(firstKey)}`);
}
}
}
/**
* 获取所有缓存条目的迭代器
*/
entries() {
return this.cache.entries();
}
/**
* 获取所有缓存的key
*/
keys() {
return this.cache.keys();
}
/**
* 获取所有缓存的value
*/
values() {
return this.cache.values();
}
/**
* 删除指定的缓存项
*/
delete(key) {
return this.cache.delete(key);
}
/**
* 获取缓存统计信息
*/
getStats() {
return {
size: this.cache.size,
maxSize: this.maxSize,
usageRate: this.cache.size / this.maxSize * 100
};
}
};
} });
//#endregion
//#region src/tools/compressWithTinyPng.ts
var compressWithTinyPng_exports = {};
__export(compressWithTinyPng_exports, {
clearTinyPngCache: () => clearTinyPngCache,
compressWithTinyPng: () => compressWithTinyPng,
configureTinyPngCache: () => configureTinyPngCache,
getTinyPngCacheInfo: () => getTinyPngCacheInfo,
getTinyPngCacheSize: () => getTinyPngCacheSize
});
function generateFileKey(file, options) {
const relevantOptions = {
targetWidth: options.targetWidth,
targetHeight: options.targetHeight,
maxWidth: options.maxWidth,
maxHeight: options.maxHeight,
mode: options.mode === "keepQuality" ? options.mode : void 0
};
return `${file.name}_${file.size}_${file.lastModified}_${JSON.stringify(relevantOptions)}`;
}
function compressWithTinyPng(file, options) {
return new Promise(async (resolve, reject) => {
try {
const cacheKey = generateFileKey(file, options);
if (compressionCache.has(cacheKey)) {
console.log("TinyPNG: Using cached result for file:", file.name);
resolve(compressionCache.get(cacheKey));
return;
}
const apiKey = options.key;
if (!apiKey) {
reject("TinyPNG API key is required. Please set TINYPNG_API_KEY environment variable or window.TINYPNG_API_KEY");
return;
}
const supportedTypes = [
"image/jpeg",
"image/jpg",
"image/png",
"image/webp"
];
if (!supportedTypes.includes(file.type)) {
reject(`Unsupported file type: ${file.type}. TinyPNG supports JPEG, PNG, and WebP images.`);
return;
}
const uploadResponse = await fetch("https://api.tinify.com/shrink", {
method: "POST",
headers: {
Authorization: `Basic ${btoa(`api:${apiKey}`)}`,
"Content-Type": file.type
},
body: file
});
if (!uploadResponse.ok) {
const errorText = await uploadResponse.text();
reject(`TinyPNG upload failed: ${uploadResponse.status} - ${errorText}`);
return;
}
const outputUrl = uploadResponse.headers.get("Location");
if (!outputUrl) {
reject("No output URL received from TinyPNG");
return;
}
let resizeOptions = null;
if (options.mode === "keepQuality" && (options.targetWidth || options.targetHeight || options.maxWidth || options.maxHeight)) {
resizeOptions = {};
if (options.targetWidth && options.targetHeight) {
resizeOptions.method = "fit";
resizeOptions.width = options.targetWidth;
resizeOptions.height = options.targetHeight;
} else if (options.maxWidth && options.maxHeight) {
resizeOptions.method = "scale";
resizeOptions.width = options.maxWidth;
resizeOptions.height = options.maxHeight;
} else if (options.targetWidth) {
resizeOptions.method = "scale";
resizeOptions.width = options.targetWidth;
} else if (options.targetHeight) {
resizeOptions.method = "scale";
resizeOptions.height = options.targetHeight;
}
}
let finalUrl = outputUrl;
if (resizeOptions) {
const resizeResponse = await fetch(outputUrl, {
method: "POST",
headers: {
Authorization: `Basic ${btoa(`api:${apiKey}`)}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ resize: resizeOptions })
});
if (!resizeResponse.ok) {
const errorText = await resizeResponse.text();
reject(`TinyPNG resize failed: ${resizeResponse.status} - ${errorText}`);
return;
}
finalUrl = resizeResponse.headers.get("Location") || outputUrl;
}
const downloadResponse = await fetch(finalUrl, { headers: { Authorization: `Basic ${btoa(`api:${apiKey}`)}` } });
if (!downloadResponse.ok) {
reject(`Failed to download compressed image: ${downloadResponse.status}`);
return;
}
const compressedBlob = await downloadResponse.blob();
if (compressedBlob.size >= file.size * .98) {
console.warn("TinyPNG compression did not significantly reduce file size, returning original file");
compressionCache.set(cacheKey, file);
resolve(file);
} else {
const finalBlob = new Blob([compressedBlob], { type: file.type });
compressionCache.set(cacheKey, finalBlob);
resolve(finalBlob);
}
} catch (error) {
console.error("TinyPNG compression error:", error);
reject(error);
}
});
}
function clearTinyPngCache() {
compressionCache.clear();
console.log("TinyPNG cache cleared");
}
function getTinyPngCacheSize() {
return compressionCache.size;
}
function getTinyPngCacheInfo() {
const cacheEntries = Array.from(compressionCache.entries()).map(([key, blob]) => ({
key,
size: blob.size,
type: blob.type
}));
const stats = compressionCache.getStats();
return {
totalEntries: stats.size,
maxSize: stats.maxSize,
usageRate: stats.usageRate,
entries: cacheEntries
};
}
function configureTinyPngCache(maxSize = 50) {
compressionCache.setMaxSize(maxSize);
console.log(`TinyPNG cache reconfigured with max size: ${maxSize}`);
}
var compressionCache;
var init_compressWithTinyPng = __esm({ "src/tools/compressWithTinyPng.ts"() {
init_lruCache();
compressionCache = new LRUCache(50);
} });
//#endregion
export { LRUCache, clearTinyPngCache, compressWithTinyPng, compressWithTinyPng_exports, configureTinyPngCache, getTinyPngCacheInfo, getTinyPngCacheSize, init_compressWithTinyPng, init_lruCache };