@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.
85 lines (72 loc) • 32 kB
JavaScript
import{__esmMin as e,__export as t,__toCommonJS as n}from"./chunk-BFNP_Rck.js";import{compress as r,compressWithStats as i,convertBlobToType as a,init_abort as o,init_convertBlobToType as s,runWithAbortAndTimeout as c}from"./compress-DM3q3gNt.js";import{init_logger as l,logger_default as u,resetLogger as d,setLogger as f}from"./logger-C7b05YKe.js";import{LRUCache as p,init_lruCache as m}from"./lruCache-B8iebN31.js";import{compressWithBrowserImageCompression as h,compressWithBrowserImageCompression_exports as g,init_compressWithBrowserImageCompression as _}from"./compressWithBrowserImageCompression-95e0QVEL.js";import{compressWithCompressorJS as v,compressWithCompressorJS_exports as y,init_compressWithCompressorJS as b}from"./compressWithCompressorJS-Dmmwb6qA.js";import{compressWithCanvas as x,compressWithCanvas_exports as S,init_compressWithCanvas as C}from"./compressWithCanvas-D2jIiuDw.js";import{compressWithGifsicle as w,compressWithGifsicle_exports as T,init_compressWithGifsicle as E}from"./compressWithGifsicle-D2NslzRe.js";import{compressWithJsquash as ee,compressWithJsquash_exports as D,configureWasmLoading as te,diagnoseJsquashAvailability as ne,downloadWasmFiles as re,ensureWasmLoaded as ie,init_compressWithJsquash as O}from"./compressWithJsquash-g9pU8MHz.js";import{clearTinyPngCache as ae,compressWithTinyPng as oe,compressWithTinyPng_exports as se,configureTinyPngCache as ce,getTinyPngCacheInfo as le,getTinyPngCacheSize as ue,init_compressWithTinyPng as k}from"./compressWithTinyPng-t0_T4fOM.js";var A=class e{static instance;deviceInfo=null;constructor(){}static getInstance(){return e.instance||=new e,e.instance}detectDevice(){if(this.deviceInfo)return this.deviceInfo;let e=typeof navigator<`u`,t=typeof window<`u`,n=e&&navigator.userAgent?navigator.userAgent:``,r=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(n)||(t?window.innerWidth<=768:!1),i=e&&navigator.hardwareConcurrency||(r?4:8),a=e?navigator.deviceMemory:void 0,o=a||(r?2:8),s=`medium`;return r||i<=2||o<=2?s=`low`:i>=8&&o>=8&&(s=`high`),this.deviceInfo={isMobile:r,cpuCores:i,memoryGB:o,estimatedPerformance:s},import(`./logger-CgmUrs0d.js`).then(e=>e.default.log(`Device detected:`,this.deviceInfo)).catch(()=>{}),this.deviceInfo}calculateOptimalConcurrency(){let e=this.detectDevice();if(e.isMobile)return 2;switch(e.estimatedPerformance){case`low`:return 2;case`medium`:return 3;case`high`:return Math.min(5,Math.max(2,Math.floor(e.cpuCores/2)));default:return 3}}},j=class e{static instance;queue=[];running=new Map;completed=0;failed=0;maxConcurrency;performanceDetector;constructor(){this.performanceDetector=A.getInstance(),this.maxConcurrency=this.performanceDetector.calculateOptimalConcurrency(),import(`./logger-CgmUrs0d.js`).then(e=>e.default.log(`Compression queue initialized with concurrency: ${this.maxConcurrency}`)).catch(()=>{})}static getInstance(){return e.instance||=new e,e.instance}addTask(e){e.priority===void 0&&(e.priority=Math.max(1,100-Math.floor(e.file.size/(1024*1024))));let t=this.queue.findIndex(t=>(t.priority||0)<e.priority);t===-1?this.queue.push(e):this.queue.splice(t,0,e),this.processQueue()}removeTask(e){let t=this.queue.findIndex(t=>t.id===e);return t===-1?!1:(this.queue.splice(t,1),!0)}getStats(){return{pending:this.queue.length,running:this.running.size,completed:this.completed,failed:this.failed,maxConcurrency:this.maxConcurrency}}setMaxConcurrency(e){this.maxConcurrency=Math.max(1,Math.min(10,e)),import(`./logger-CgmUrs0d.js`).then(e=>e.default.log(`Concurrency updated to: ${this.maxConcurrency}`)).catch(()=>{}),this.processQueue()}clearQueue(){this.queue.forEach(e=>{e.reject(Error(`Task cancelled: queue cleared`))}),this.queue=[]}async processQueue(){for(;this.running.size<this.maxConcurrency&&this.queue.length>0;){let e=this.queue.shift();this.running.set(e.id,e),this.executeTask(e).catch(e=>{import(`./logger-CgmUrs0d.js`).then(t=>t.default.error(`Task execution error:`,e)).catch(()=>{})})}}async executeTask(e){try{if(import(`./logger-CgmUrs0d.js`).then(t=>t.default.log(`Starting compression task: ${e.id}`)).catch(()=>{}),e.cancelListener){try{e.cancelListener()}catch{}e.cancelListener=void 0}let{compress:t}=await import(`./compress-BH56hcdG.js`),n=await t(e.file,{...e.options,type:`blob`}),r=typeof n==`object`&&`bestResult`in n?n.bestResult:n;this.running.delete(e.id),this.completed++,import(`./logger-CgmUrs0d.js`).then(t=>t.default.log(`Task completed: ${e.id}`)).catch(()=>{}),e.resolve(r)}catch(t){this.running.delete(e.id),this.failed++,import(`./logger-CgmUrs0d.js`).then(n=>n.default.error(`Task failed: ${e.id}`,t)).catch(()=>{}),e.reject(t instanceof Error?t:Error(`Compression failed`))}this.processQueue()}compress(e,t,n){return new Promise((r,i)=>{let a=`${e.name}_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,o={id:a,file:e,options:t,resolve:r,reject:i,priority:n};if(t&&t.signal){let e=t.signal,n=()=>{import(`./logger-CgmUrs0d.js`).then(e=>e.default.log(`compressionQueue: abort signal received for task`,a)).catch(()=>{});let e=this.removeTask(a);if(e){import(`./logger-CgmUrs0d.js`).then(e=>e.default.log(`compressionQueue: task removed from queue due to abort`,a)).catch(()=>{});try{i(Error(`Task cancelled`))}catch{}}else import(`./logger-CgmUrs0d.js`).then(e=>e.default.log(`compressionQueue: abort received but task already started or not in queue`,a)).catch(()=>{})};e.addEventListener(`abort`,n,{once:!0}),o.cancelListener=()=>{try{e.removeEventListener(`abort`,n)}catch{}}}this.addTask(o)})}};const M=j.getInstance(),de=[`browser-image-compression`,`compressorjs`,`gifsicle`,`tinypng`],fe=[`canvas`,`jsquash`];var N=class e{static instance;workers=[];workerTasks=new Map;workerPool=[];isWorkerSupported=!1;workerScript=null;initPromise=null;constructor(){this.initPromise=this.initializeWorkerSupport()}static getInstance(){return e.instance||=new e,e.instance}async initializeWorkerSupport(){try{if(typeof Worker>`u`){import(`./logger-CgmUrs0d.js`).then(e=>e.default.log(`Web Workers not supported in this environment`)).catch(()=>{});return}this.workerScript=this.createWorkerScript(),await this.testWorkerSupport(),this.isWorkerSupported=!0,import(`./logger-CgmUrs0d.js`).then(e=>e.default.log(`Compression workers initialized successfully`)).catch(()=>{})}catch(e){import(`./logger-CgmUrs0d.js`).then(t=>t.default.warn(`Worker support initialization failed:`,e)).catch(()=>{}),this.isWorkerSupported=!1}}createWorkerScript(){return`
// Compression worker script
let compressionFunctions = null;
// Import compression tools dynamically
async function initializeTools() {
try {
// Note: In a real implementation, you'd need to properly bundle and load the tools
// For now, we'll simulate the import structure
// These would be the actual tool imports
// const browserImageCompression = await import('browser-image-compression');
// const compressorjs = await import('compressorjs');
console.log('Compression tools initialized in worker');
return true;
} catch (error) {
console.error('Failed to initialize compression tools in worker:', error);
return false;
}
}
// Handle compression requests
async function compressFile(fileData, options) {
try {
// Reconstruct File object from transferred data
const file = new File([fileData.buffer], fileData.name, { type: fileData.type });
// For worker-compatible tools, we need to implement compression logic here
// This is a simplified version - in production you'd import and use actual tools
// Fallback to basic compression if advanced tools aren't available
return await basicCompress(file, options);
} catch (error) {
throw new Error('Worker compression failed: ' + error.message);
}
}
// Basic compression fallback (simplified implementation)
async function basicCompress(file, options) {
// This is a placeholder - real implementation would use proper compression
// For now, just return the original file data
const arrayBuffer = await file.arrayBuffer();
return {
buffer: arrayBuffer,
size: arrayBuffer.byteLength,
type: file.type
};
}
// Worker message handler
self.onmessage = async function(e) {
const { id, type, data } = e.data;
try {
if (type === 'compress') {
const result = await compressFile(data.file, data.options);
// Send result back to main thread
self.postMessage({
id,
type: 'result',
data: result
}, [result.buffer]); // Transfer the buffer
} else if (type === 'init') {
const initialized = await initializeTools();
self.postMessage({
id,
type: 'result',
data: { initialized }
});
}
} catch (error) {
self.postMessage({
id,
type: 'error',
data: { message: error.message }
});
}
};
console.log('Compression worker ready');
`}async testWorkerSupport(){return new Promise((e,t)=>{if(!this.workerScript){t(Error(`Worker script not created`));return}let n=new Blob([this.workerScript],{type:`application/javascript`}),r=URL.createObjectURL(n);try{let n=new Worker(r),i=`test_${Date.now()}`,a=setTimeout(()=>{n.terminate(),URL.revokeObjectURL(r),t(Error(`Worker test timeout`))},5e3);n.onmessage=t=>{let{id:o,type:s,data:c}=t.data;o===i&&s===`result`&&(clearTimeout(a),n.terminate(),URL.revokeObjectURL(r),e())},n.onerror=e=>{clearTimeout(a),n.terminate(),URL.revokeObjectURL(r),t(e)},n.postMessage({id:i,type:`init`,data:{}})}catch(e){URL.revokeObjectURL(r),t(e)}})}async waitForInitialization(){this.initPromise&&await this.initPromise}isSupported(){return this.isWorkerSupported}isToolWorkerCompatible(e){return de.includes(e)}getDOMDependentTools(){return[...fe]}async compressInWorker(e,t){if(!this.isSupported())throw Error(`Workers not supported`);return new Promise((n,r)=>{let i=`worker_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,a={id:i,file:e,options:t,resolve:n,reject:r};this.workerTasks.set(i,a);try{let a=this.getAvailableWorker(),o=e=>{let{id:t,type:s,data:c}=e.data;if(t===i)if(a.removeEventListener(`message`,o),this.workerTasks.delete(i),s===`result`){let e=new Blob([c.buffer],{type:c.type});n(e)}else s===`error`&&r(Error(c.message))};a.addEventListener(`message`,o);let s={buffer:e.arrayBuffer(),name:e.name,type:e.type,size:e.size};s.buffer.then(n=>{a.postMessage({id:i,type:`compress`,data:{file:{buffer:n,name:e.name,type:e.type,size:e.size},options:t}},[n])})}catch(e){this.workerTasks.delete(i),r(e)}})}getAvailableWorker(){if(!this.workerScript)throw Error(`Worker script not available`);let e=new Blob([this.workerScript],{type:`application/javascript`}),t=URL.createObjectURL(e),n=new Worker(t);return n.addEventListener(`error`,()=>{URL.revokeObjectURL(t)}),n}destroy(){this.workers.forEach(e=>e.terminate()),this.workers=[],this.workerTasks.clear()}};const P=N.getInstance();l();var F=class e{static instance;objectUrls=new Set;imageElements=new Set;canvasElements=new Set;thresholds;constructor(){this.thresholds={warning:70,critical:85,maxFileSize:100*1024*1024,maxTotalSize:500*1024*1024},this.setupPeriodicCleanup(),this.setupMemoryMonitoring()}static getInstance(){return e.instance||=new e,e.instance}getMemoryStats(){if(typeof performance<`u`&&performance.memory){let e=performance.memory;return{usedJSHeapSize:e.usedJSHeapSize,totalJSHeapSize:e.totalJSHeapSize,jsHeapSizeLimit:e.jsHeapSizeLimit,memoryUsagePercentage:e.usedJSHeapSize/e.jsHeapSizeLimit*100}}return{usedJSHeapSize:0,totalJSHeapSize:0,jsHeapSizeLimit:0,memoryUsagePercentage:0}}isMemoryCritical(){let e=this.getMemoryStats();return e.memoryUsagePercentage>this.thresholds.critical}isFileSizeAcceptable(e){return e<=this.thresholds.maxFileSize}isTotalSizeAcceptable(e){return e<=this.thresholds.maxTotalSize}registerObjectUrl(e){this.objectUrls.add(e)}registerImageElement(e){this.imageElements.add(e)}registerCanvasElement(e){this.canvasElements.add(e)}cleanupObjectUrl(e){if(this.objectUrls.has(e))try{URL.revokeObjectURL(e),this.objectUrls.delete(e)}catch(e){u.warn(`Failed to revoke object URL:`,e)}}cleanupImageElement(e){if(this.imageElements.has(e))try{e.src=``,e.onload=null,e.onerror=null,this.imageElements.delete(e)}catch(e){u.warn(`Failed to cleanup image element:`,e)}}cleanupCanvasElement(e){if(this.canvasElements.has(e))try{let t=e.getContext(`2d`);t&&t.clearRect(0,0,e.width,e.height),e.width=0,e.height=0,this.canvasElements.delete(e)}catch(e){u.warn(`Failed to cleanup canvas element:`,e)}}performCleanup(){if(u.log(`Performing memory cleanup...`),this.objectUrls.forEach(e=>{try{URL.revokeObjectURL(e)}catch(e){u.warn(`Failed to revoke URL during cleanup:`,e)}}),this.objectUrls.clear(),this.imageElements.forEach(e=>{try{e.src=``,e.onload=null,e.onerror=null}catch(e){u.warn(`Failed to cleanup image during cleanup:`,e)}}),this.imageElements.clear(),this.canvasElements.forEach(e=>{try{let t=e.getContext(`2d`);t&&t.clearRect(0,0,e.width,e.height),e.width=0,e.height=0}catch(e){u.warn(`Failed to cleanup canvas during cleanup:`,e)}}),this.canvasElements.clear(),typeof window<`u`&&window.gc&&typeof window.gc==`function`)try{window.gc()}catch(e){u.warn(`Manual garbage collection failed:`,e)}u.log(`Memory cleanup completed`)}setupPeriodicCleanup(){setInterval(()=>{let e=this.getMemoryStats();typeof process<`u`&&process.env&&process.env.NODE_ENV===`development`&&u.log(`Memory Stats:`,e),e.memoryUsagePercentage>this.thresholds.critical&&(u.warn(`Memory usage critical, performing cleanup`),this.performCleanup())},3e4)}setupMemoryMonitoring(){if(typeof PerformanceObserver<`u`)try{let e=new PerformanceObserver(e=>{let t=e.getEntries();t.forEach(e=>{e.entryType===`measure`&&e.name.includes(`memory`)&&u.log(`Memory measurement:`,e)})});e.observe({entryTypes:[`measure`]})}catch(e){u.warn(`Memory monitoring setup failed:`,e)}}updateThresholds(e){this.thresholds={...this.thresholds,...e},u.log(`Memory thresholds updated:`,this.thresholds)}getThresholds(){return{...this.thresholds}}createManagedObjectUrl(e){let t=URL.createObjectURL(e);return this.registerObjectUrl(t),setTimeout(()=>{this.cleanupObjectUrl(t)},10*60*1e3),t}createManagedImage(){let e;return e=typeof Image<`u`?new Image:typeof document<`u`?document.createElement(`img`):{src:``,onload:null,onerror:null},this.registerImageElement(e),setTimeout(()=>{try{this.cleanupImageElement(e)}catch{}},5*60*1e3),e}createManagedCanvas(){let e;return e=typeof document<`u`&&document.createElement?document.createElement(`canvas`):{width:0,height:0,getContext:()=>({clearRect:()=>{}})},this.registerCanvasElement(e),setTimeout(()=>{try{this.cleanupCanvasElement(e)}catch{}},5*60*1e3),e}destroy(){this.performCleanup()}};const I=F.getInstance();function pe(e=0){let t=I,n=t.getMemoryStats();return t.isMemoryCritical()?(u.warn(`Memory usage is critical, consider reducing concurrent operations`),!1):e>0&&!t.isFileSizeAcceptable(e)?(u.warn(`File size ${e} bytes exceeds limit`),!1):!0}async function me(e){return new Promise((t,n)=>{let r=new Image;if(r.crossOrigin=`anonymous`,r.onload=()=>t(r),r.onerror=()=>n(Error(`Failed to load image`)),e instanceof Blob){let n=URL.createObjectURL(e);r.onload=()=>{URL.revokeObjectURL(n),t(r)},r.src=n}else r.src=e})}function he(e,t,n){if(!n)return{width:e,height:t};let{targetWidth:r,targetHeight:i,maxWidth:a,maxHeight:o,fit:s=`contain`}=n;if(r&&i)return{width:r,height:i};if(r&&!i){let n=r/e;return{width:r,height:Math.round(t*n)}}if(!r&&i){let n=i/t;return{width:Math.round(e*n),height:i}}let c=e,l=t;if(a||o){let n=a??1/0,r=o??1/0,i=Math.min(n/e,r/t,1);if(s===`scale-down`)i<1&&(c=Math.round(e*i),l=Math.round(t*i));else if(s===`contain`)c=Math.round(e*i),l=Math.round(t*i);else if(s===`cover`){let i=Math.min(n/e,r/t,1);c=Math.round(e*i),l=Math.round(t*i)}}return{width:c,height:l}}async function L(e,t){let n=await me(e),r=n.naturalWidth,i=n.naturalHeight,a=t.crop??{x:0,y:0,width:r,height:i},o=Math.max(0,Math.min(a.x,r)),s=Math.max(0,Math.min(a.y,i)),c=Math.max(1,Math.min(a.width,r-o)),l=Math.max(1,Math.min(a.height,i-s)),u=((t.rotate??0)%360+360)%360,d=!!t.flipHorizontal,f=!!t.flipVertical,p=u*Math.PI/180,m=Math.cos(p),h=Math.sin(p),g=Math.abs(c*m)+Math.abs(l*h),_=Math.abs(c*h)+Math.abs(l*m),v=he(Math.round(g),Math.round(_),t.resize),y=I.createManagedCanvas(),b=y.getContext(`2d`);if(!b)throw Error(`Failed to get 2D context`);y.width=v.width,y.height=v.height,b.save();let x=I.createManagedCanvas(),S=x.getContext(`2d`);if(!S)throw Error(`Failed to get temp 2D context`);x.width=Math.round(g),x.height=Math.round(_),S.clearRect(0,0,x.width,x.height),S.save(),S.translate(x.width/2,x.height/2),u!==0&&S.rotate(p),S.scale(d?-1:1,f?-1:1),S.drawImage(n,o,s,c,l,-c/2,-l/2,c,l),S.restore(),b.clearRect(0,0,y.width,y.height),b.drawImage(x,0,0,y.width,y.height),b.restore();let C=t.outputType||(e instanceof Blob?e.type:`image/png`)||`image/png`,w=t.outputQuality,T=await new Promise((e,t)=>{y.toBlob(n=>n?e(n):t(Error(`Failed to export canvas`)),C,w)});return I.cleanupCanvasElement(x),I.cleanupCanvasElement(y),{blob:T,width:y.width,height:y.height,mimeType:T.type}}s(),l();async function R(e,t={}){let{useWorker:n=!0,useQueue:r=!0,priority:i,timeout:o=3e4,type:s=`blob`,preprocess:c,...l}=t;if(!e||!(e instanceof File))throw Error(`Invalid file input`);let d=e;if(c)try{let t=`image/png`;c.outputType?t=c.outputType:/jpe?g/i.test(e.type)?t=`image/jpeg`:/png/i.test(e.type)?t=`image/png`:/webp/i.test(e.type)&&(t=`image/webp`);let n=await L(e,{...c,outputType:t});d=n.blob}catch(e){u.warn(`Preprocess failed, fallback to original file:`,e)}if(!r)return await ge(d instanceof File?d:new File([d],e.name,{type:d.type}),l,n,s);let f=M.compress(d instanceof File?d:new File([d],e.name,{type:d.type}),{...l,useWorker:n,type:`blob`},i),p=new Promise((e,t)=>{setTimeout(()=>{t(Error(`Compression timeout after ${o}ms`))},o)});try{let e=await Promise.race([f,p]);return await a(e,s)}catch(e){throw e instanceof Error?e:Error(`Compression failed`)}}async function ge(e,t,n,r){let i,o=n&&P.isSupported()&&_e(e,t);if(o)try{i=await P.compressInWorker(e,t),u.log(`Used worker compression for`,e.name)}catch(n){u.warn(`Worker compression failed, falling back to main thread:`,n),i=await z(e,t)}else i=await z(e,t);return await a(i,r)}async function z(e,t){let{compress:n}=await import(`./compress-BH56hcdG.js`),r=await n(e,{...t,type:`blob`,returnAllResults:!1});return r}function _e(e,t){let n=50*1024*1024;return e.size>n?(u.log(`File too large for worker, using main thread`),!1):(t.preserveExif&&u.log(`EXIF preservation required, may use main thread for better compatibility`),!0)}async function ve(e,t={}){if(!e||e.length===0)return[];let n=e.map((n,r)=>{let i=Math.max(1,100-Math.floor(n.size/(1024*1024))),a=Math.max(1,e.length-r),o=t.priority||Math.floor((i+a)/2);return R(n,{...t,priority:o,type:`blob`})}),r=await Promise.allSettled(n);return r.map((t,n)=>{if(t.status===`fulfilled`)return t.value;throw u.error(`Compression failed for file ${e[n].name}:`,t.reason),t.reason})}async function ye(){await P.waitForInitialization()}function be(){return{queue:M.getStats(),worker:{supported:P.isSupported(),domDependentTools:P.getDOMDependentTools()}}}function xe(e){e.maxConcurrency!==void 0&&M.setMaxConcurrency(e.maxConcurrency)}function B(){M.clearQueue()}var V={};t(V,{ToolRegistry:()=>W,compressWithTools:()=>U,globalToolRegistry:()=>G});function H(e,t){return t.find(t=>t.name===e)}async function U(e,t){let{quality:n=.6,mode:r=`keepSize`,targetWidth:i,targetHeight:o,maxWidth:s,maxHeight:c,preserveExif:l=!1,returnAllResults:u=!1,type:d=`blob`,toolConfigs:f=[],toolRegistry:p=G,signal:m,timeoutMs:h}=t,g={quality:n,mode:r,targetWidth:i,targetHeight:o,maxWidth:s,maxHeight:c,preserveExif:l,toolConfigs:f,signal:m,timeoutMs:h},_=p.getToolsForFileType(e.type),v=f.some(e=>e.name===`tinypng`);if(v&&p.isToolRegistered(`tinypng`)&&[`png`,`webp`,`jpeg`,`jpg`].some(t=>e.type.includes(t))&&(_.includes(`tinypng`)||(_=[..._,`tinypng`])),_=_.filter(e=>p.isToolRegistered(e)),_.length===0)throw Error(`No compression tools available. Please register at least one compression tool.`);if(u)return await Ce(e,g,_,d,p);let y=await Se(e,g,_,p);return a(y,d,e.name)}async function Se(e,t,n,r){let i=performance.now();if(t.preserveExif){if(n=n.filter(e=>K.includes(e)),n.length===0)throw Error(`No EXIF-supporting tools available for this file type. Please disable preserveExif or use a different file format.`);u.log(`preserveExif=true, filtered tools:`,n)}let a=[],o=new AbortController,s=o.signal;if(t.signal){let e=t.signal;e.aborted?o.abort():e.addEventListener(`abort`,()=>o.abort(),{once:!0})}let l=n.map(async n=>{let i=performance.now();try{let a=r.getTool(n);if(!a)throw Error(`Tool ${n} not registered`);let o=H(n,t.toolConfigs||[]),l={quality:t.quality,mode:t.mode,targetWidth:t.targetWidth,targetHeight:t.targetHeight,maxWidth:t.maxWidth,maxHeight:t.maxHeight,preserveExif:t.preserveExif,...o},u=()=>a(e,l),d=await c(u,s,t.timeoutMs),f=performance.now(),p=Math.round(f-i);return{tool:n,blob:d,size:d.size,success:!0,duration:p}}catch(t){try{o.abort()}catch{}let r=performance.now(),a=Math.round(r-i);return{tool:n,blob:e,size:e.size,success:!1,error:t instanceof Error?t.message:String(t),duration:a}}}),d=await Promise.allSettled(l);d.forEach(e=>{e.status===`fulfilled`?a.push(e.value):u.warn(`Compression tool failed:`,e.reason)});let f=a.filter(e=>e.success);if(f.length===0)return u.warn(`All compression attempts failed, returning original file`),e;let p=f.reduce((e,t)=>t.size<e.size?t:e);if(p.size>=e.size*.98&&t.quality>.85){let t=performance.now(),n=Math.round(t-i);return u.log(`Best compression (${p.tool}) size: ${p.size}, original: ${e.size}, using original (total: ${n}ms)`),e}let m=performance.now(),h=Math.round(m-i);return u.log(`Best compression result: ${p.tool} (${p.size} bytes, ${((e.size-p.size)/e.size*100).toFixed(1)}% reduction, ${p.duration}ms) - Total time: ${h}ms`),f.length>1&&u.table(f.map(t=>({Tool:t.tool,"Size (bytes)":t.size,"Reduction (%)":`${((e.size-t.size)/e.size*100).toFixed(1)}%`,"Duration (ms)":t.duration,"Speed (MB/s)":`${(e.size/1024/1024/(t.duration/1e3)).toFixed(2)}`}))),p.blob}async function Ce(e,t,n,r,i){let o=performance.now();if(t.preserveExif){if(n=n.filter(e=>K.includes(e)),n.length===0)throw Error(`No EXIF-supporting tools available for this file type. Please disable preserveExif or use a different file format.`);u.log(`preserveExif=true, filtered tools:`,n)}let s=[],l=new AbortController,d=l.signal;if(t.signal){let e=t.signal;e.aborted?l.abort():e.addEventListener(`abort`,()=>l.abort(),{once:!0})}let f=n.map(async n=>{let r=performance.now();try{let a=i.getTool(n);if(!a)throw Error(`Tool ${n} not registered`);let o=H(n,t.toolConfigs||[]),s={quality:t.quality,mode:t.mode,targetWidth:t.targetWidth,targetHeight:t.targetHeight,maxWidth:t.maxWidth,maxHeight:t.maxHeight,preserveExif:t.preserveExif,...o||{},signal:d},l=await c(()=>a(e,s),d,t.timeoutMs),u=performance.now(),f=Math.round(u-r);return{tool:n,blob:l,size:l.size,success:!0,duration:f}}catch(t){try{l.abort()}catch{}let i=performance.now(),a=Math.round(i-r);return{tool:n,blob:e,size:e.size,success:!1,error:t instanceof Error?t.message:String(t),duration:a}}}),p=await Promise.allSettled(f);if(p.forEach(e=>{e.status===`fulfilled`?s.push(e.value):u.warn(`Compression tool failed:`,e.reason)}),s.length===0)throw Error(`All compression attempts failed`);let m=performance.now(),h=Math.round(m-o),g=await Promise.all(s.map(async t=>{let n=await a(t.blob,r,e.name);return{tool:t.tool,result:n,originalSize:e.size,compressedSize:t.size,compressionRatio:(e.size-t.size)/e.size*100,duration:t.duration,success:t.success,error:t.error}})),_=s.filter(e=>e.success),v;_.length>0?(v=_.reduce((e,t)=>t.size<e.size?t:e),v.size>=e.size*.98&&t.quality>.85&&(v={tool:`original`,blob:e,size:e.size,success:!0,duration:0})):v={tool:`original`,blob:e,size:e.size,success:!0,duration:0};let y=await a(v.blob,r,e.name);return u.log(`Best compression result: ${v.tool} (${v.size} bytes, ${((e.size-v.size)/e.size*100).toFixed(1)}% reduction) - Total time: ${h}ms`),{bestResult:y,bestTool:v.tool,allResults:g,totalDuration:h}}var W,G,K,q=e(()=>{s(),o(),l(),W=class{tools=new Map;toolsCollections={png:[],gif:[],webp:[],jpeg:[],others:[]};registerTool(e,t,n){this.tools.set(e,t),n&&n.length>0?n.forEach(t=>{this.toolsCollections[t]&&(this.toolsCollections[t].includes(e)||this.toolsCollections[t].push(e))}):Object.keys(this.toolsCollections).forEach(t=>{t!==`gif`&&!this.toolsCollections[t].includes(e)&&this.toolsCollections[t].push(e)})}getTool(e){return this.tools.get(e)}getRegisteredTools(){return Array.from(this.tools.keys())}getToolsForFileType(e){return e.includes(`png`)?[...this.toolsCollections.png]:e.includes(`gif`)?[...this.toolsCollections.gif]:e.includes(`webp`)?[...this.toolsCollections.webp]:e.includes(`jpeg`)||e.includes(`jpg`)?[...this.toolsCollections.jpeg]:[...this.toolsCollections.others]}setToolPriority(e,t){if(this.toolsCollections[e]){let n=t.filter(e=>this.tools.has(e));this.toolsCollections[e]=n}}isToolRegistered(e){return this.tools.has(e)}},G=new W,K=[`browser-image-compression`,`compressorjs`]});_(),b(),C(),E(),O(),k(),q();function we(){let{globalToolRegistry:e}=(q(),n(V));e.registerTool(`browser-image-compression`,(_(),n(g)).default,[`png`,`jpeg`,`webp`,`others`]),e.registerTool(`compressorjs`,(b(),n(y)).default,[`jpeg`,`others`]),e.registerTool(`canvas`,(C(),n(S)).default,[`png`,`jpeg`,`webp`,`others`]),e.registerTool(`gifsicle`,(E(),n(T)).default,[`gif`]),e.registerTool(`jsquash`,(O(),n(D)).default,[`png`,`jpeg`,`webp`,`others`])}function Te(){let{globalToolRegistry:e}=(q(),n(V));e.registerTool(`browser-image-compression`,(_(),n(g)).default,[`png`,`jpeg`,`webp`,`others`])}function Ee(){let{globalToolRegistry:e}=(q(),n(V));e.registerTool(`compressorjs`,(b(),n(y)).default,[`jpeg`,`others`])}function De(){let{globalToolRegistry:e}=(q(),n(V));e.registerTool(`canvas`,(C(),n(S)).default,[`png`,`jpeg`,`webp`,`others`])}function Oe(){let{globalToolRegistry:e}=(q(),n(V));e.registerTool(`gifsicle`,(E(),n(T)).default,[`gif`])}function ke(){let{globalToolRegistry:e}=(q(),n(V));e.registerTool(`jsquash`,(O(),n(D)).default,[`png`,`jpeg`,`webp`,`others`])}function Ae(){let{globalToolRegistry:e}=(q(),n(V));e.registerTool(`tinypng`,(k(),n(se)).compressWithTinyPng,[`png`,`jpeg`,`webp`])}const je={png:`image/png`,jpeg:`image/jpeg`,webp:`image/webp`,ico:`image/x-icon`};async function Me(e,t,n){try{return await J(e,t,n)}catch(e){throw Error(`JSQuash encoding fallback failed: ${e}`)}}async function J(e,t,n){return new Promise((r,i)=>{let a=new Image,o=document.createElement(`canvas`),s=o.getContext(`2d`);if(!s){i(Error(`Canvas context not available`));return}a.onload=()=>{o.width=a.width,o.height=a.height,s.drawImage(a,0,0);let e,c;switch(t){case`jpeg`:e=`image/jpeg`,c=n||.8;break;case`webp`:e=`image/webp`,c=n||.8;break;case`png`:e=`image/png`;break;default:i(Error(`Canvas does not support ${t} encoding`));return}o.toBlob(e=>{e?r(e):i(Error(`Canvas toBlob failed`))},e,c)},a.onerror=()=>i(Error(`Failed to load image`)),a.src=URL.createObjectURL(e)})}async function Y(e,t){try{let t=await J(e,`png`),n=new Uint8Array(await t.arrayBuffer()),r=new Uint8Array([0,0,1,0,1,0]),i=256,a=256,o=n.length,s=new Uint8Array([i===256?0:i,a===256?0:a,0,0,1,0,32,0,o&255,o>>8&255,o>>16&255,o>>24&255,22,0,0,0]),c=new Blob([r,s,n],{type:`image/x-icon`});return c}catch(e){try{let t=await import(`./logger-CgmUrs0d.js`).then(e=>e.default);t.error(`ICO encoding failed:`,e)}catch{}throw Error(`ICO encoding failed: ${e instanceof Error?e.message:String(e)}`)}}async function X(e,t,n){return new Promise((r,i)=>{let a=new Blob([e],{type:`image/svg+xml`}),o=URL.createObjectURL(a),s=new Image,c=document.createElement(`canvas`),l=c.getContext(`2d`);if(!l){i(Error(`Canvas context not available`));return}s.onload=()=>{try{let e=t||s.naturalWidth||s.width||300,i=n||s.naturalHeight||s.height||150;c.width=e,c.height=i,l.clearRect(0,0,e,i),l.drawImage(s,0,0,e,i),URL.revokeObjectURL(o),r(c)}catch(e){URL.revokeObjectURL(o),i(e)}},s.onerror=()=>{URL.revokeObjectURL(o),i(Error(`Failed to load SVG image`))},s.src=o})}async function Z(e,t,n){try{let{quality:r,width:i,height:a}=n||{},o=await X(e,i,a);return new Promise((e,i)=>{let a,s;switch(t){case`jpeg`:a=`image/jpeg`,s=r||.8;break;case`webp`:a=`image/webp`,s=r||.8;break;case`png`:a=`image/png`;break;case`ico`:o.toBlob(async t=>{if(!t){i(Error(`Canvas toBlob failed for ICO conversion`));return}try{let r=new File([t],`temp.png`,{type:`image/png`}),i=await Y(r,n);e(i)}catch(e){i(e)}},`image/png`);return;default:i(Error(`Unsupported target format: ${t}`));return}o.toBlob(t=>{t?e(t):i(Error(`Canvas toBlob failed`))},a,s)})}catch(e){try{let t=await import(`./logger-CgmUrs0d.js`).then(e=>e.default);t.error(`SVG encoding failed:`,e)}catch{}throw Error(`SVG encoding failed: ${e instanceof Error?e.message:String(e)}`)}}function Q(e){let t=e.trim();return t.startsWith(`<svg`)||t.includes(`<svg`)}function $(e){let t=e.type.toLowerCase(),n=e.name.toLowerCase();if(t===`image/svg+xml`||n.endsWith(`.svg`))return`svg`;if(t===`image/png`||n.endsWith(`.png`))return`png`;if(t===`image/jpeg`||t===`image/jpg`||n.endsWith(`.jpg`)||n.endsWith(`.jpeg`))return`jpeg`;if(t===`image/webp`||n.endsWith(`.webp`))return`webp`;if(t===`image/gif`||n.endsWith(`.gif`))return`gif`;if(t===`image/bmp`||n.endsWith(`.bmp`))return`bmp`;if(t===`image/x-icon`||t===`image/vnd.microsoft.icon`||n.endsWith(`.ico`))return`ico`;if(n.includes(`.`)){let e=n.split(`.`).pop();switch(e){case`svg`:return`svg`;case`png`:return`png`;case`jpg`:case`jpeg`:return`jpeg`;case`webp`:return`webp`;case`gif`:return`gif`;case`bmp`:return`bmp`;case`ico`:return`ico`}}return`png`}l();async function Ne(e,t){let n=performance.now();try{let r=e instanceof File?e:new File([e],`image`,{type:e.type}),{targetFormat:i,quality:a}=t,o=$(r);u.debug(`Detected source format: ${o}, target format: ${i}`);let s;if(o===`svg`)try{let e=await r.text();if(!Q(e))throw Error(`File detected as SVG but does not contain valid SVG content`);s=await Z(e,i,t)}catch(e){throw u.error(`SVG conversion failed:`,e),Error(`SVG conversion failed: ${e instanceof Error?e.message:String(e)}`)}else switch(i){case`png`:case`jpeg`:case`webp`:try{s=await Me(r,i,a)}catch(e){u.warn(`JSQuash failed for ${i}, falling back to Canvas:`,e),s=await J(r,i,a)}break;case`ico`:s=await Y(r,t);break;default:throw Error(`Unsupported target format: ${i}`)}let c=performance.now()-n;return{blob:s,mime:je[i],duration:c}}catch(e){throw u.error(`Image conversion failed:`,e),e instanceof Error?Error(`Image conversion failed: ${e.message}`):Error(`Image conversion failed: ${String(e)}`)}}q(),k(),m(),l(),O();export{j as CompressionQueue,N as CompressionWorkerManager,p as LRUCache,F as MemoryManager,A as PerformanceDetector,W as ToolRegistry,pe as checkMemoryBeforeOperation,B as clearCompressionQueue,ae as clearTinyPngCache,r as compress,R as compressEnhanced,ve as compressEnhancedBatch,h as compressWithBrowserImageCompression,x as compressWithCanvas,v as compressWithCompressorJS,w as compressWithGifsicle,ee as compressWithJsquash,i as compressWithStats,oe as compressWithTinyPng,U as compressWithTools,M as compressionQueue,P as compressionWorkerManager,xe as configureCompression,ce as configureTinyPngCache,te as configureWasmLoading,Ne as convertImage,$ as detectFileFormat,ne as diagnoseJsquashAvailability,re as downloadWasmFiles,Z as encodeSvgToFormat,ie as ensureWasmLoaded,be as getCompressionStats,le as getTinyPngCacheInfo,ue as getTinyPngCacheSize,G as globalToolRegistry,Q as isSvgContent,u as logger,I as memoryManager,L as preprocessImage,we as registerAllTools,Te as registerBrowserImageCompression,De as registerCanvas,Ee as registerCompressorJS,Oe as registerGifsicle,ke as registerJsquash,Ae as registerTinyPng,X as renderSvgToCanvas,d as resetLogger,f as setLogger,ye as waitForCompressionInitialization};