vue3-image-compressor 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/assets/imageWorker-B_HCdCy9.js +24 -0
- package/dist/vue-image-compressor.js +98 -100
- package/dist/vue-image-compressor.umd.cjs +1 -1
- package/package.json +1 -1
- package/src/composables/useWorker.ts +1 -2
- package/src/utils/compressFile.ts +1 -2
- package/src/workers/imageWorker.ts +1 -1
- package/dist/assets/imageWorker-Qv3pCULy.js +0 -1042
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(u,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(u=typeof globalThis<"u"?globalThis:u||self,e(u.VueImageCompressor={},u.Vue))})(this,function(u,e){"use strict";var I=typeof document<"u"?document.currentScript:null;const B={mozJPEG:{label:"MozJPEG",mimeType:"image/jpeg",extension:"jpg"},webP:{label:"WebP",mimeType:"image/webp",extension:"webp"},avif:{label:"AVIF",mimeType:"image/avif",extension:"avif"},jxl:{label:"JPEG XL",mimeType:"image/jxl",extension:"jxl"},oxiPNG:{label:"OxiPNG",mimeType:"image/png",extension:"png"},browserJPEG:{label:"Browser JPEG",mimeType:"image/jpeg",extension:"jpg"},browserPNG:{label:"Browser PNG",mimeType:"image/png",extension:"png"},browserGIF:{label:"Browser GIF",mimeType:"image/gif",extension:"gif"},qoi:{label:"QOI",mimeType:"image/qoi",extension:"qoi"},wp2:{label:"WebP2",mimeType:"image/webp2",extension:"wp2"}},x={mozJPEG:{quality:75,baseline:!1,arithmetic:!1,progressive:!0,optimize_coding:!0,smoothing:0,color_space:3,quant_table:3,trellis_multipass:!1,trellis_opt_zero:!1,trellis_opt_table:!1,trellis_loops:1,auto_subsample:!0,chroma_subsample:2,separate_chroma_quality:!1,chroma_quality:75},webP:{quality:75,target_size:0,target_PSNR:0,method:4,sns_strength:50,filter_strength:60,filter_sharpness:0,filter_type:1,partitions:0,segments:4,pass:1,show_compressed:0,preprocessing:0,autofilter:0,partition_limit:0,alpha_compression:1,alpha_filtering:1,alpha_quality:100,lossless:0,exact:0,use_delta_palette:0,vlnr:0,near_lossless:60},avif:{cqLevel:33,denoiseLevel:0,cqAlphaLevel:-1,tileRows:0,tileCols:0,speed:6,subsample:1,chromaDeltaQ:!1,sharpness:0,tune:0},jxl:{effort:7,quality:75,progressive:!1,targetPsize:0},oxiPNG:{level:2},browserJPEG:{quality:.75},browserPNG:{},browserGIF:{},qoi:{},wp2:{quality:75}},A=Object.keys(B);async function q(r){const n=await createImageBitmap(r),a=document.createElement("canvas");a.width=n.width,a.height=n.height;const o=a.getContext("2d");return o.drawImage(n,0,0),o.getImageData(0,0,a.width,a.height)}async function N(r,n,a){const o=document.createElement("canvas");return o.width=r.width,o.height=r.height,o.getContext("2d").putImageData(r,0,0),new Promise(i=>{o.toBlob(s=>i(s),n,a)})}function Z(r){return new Promise((n,a)=>{const o=new Image;o.onload=()=>{n({width:o.width,height:o.height}),URL.revokeObjectURL(o.src)},o.onerror=a,o.src=URL.createObjectURL(r)})}async function W(r){const n=new Uint8Array(await r.slice(0,4).arrayBuffer());return n[0]===137&&n[1]===80?"image/png":n[0]===255&&n[1]===216?"image/jpeg":n[0]===71&&n[1]===73?"image/gif":n[0]===82&&n[1]===73?"image/webp":n[0]===0&&n[1]===0?"image/avif":r.type||"image/jpeg"}function J(r){return new Promise(n=>{const a=new Image;a.onload=()=>n(!0),a.onerror=()=>n(!1),a.src=`data:${r};base64,`})}function L(r,n,a){return new File([r],n,{type:a})}function M(r,n=2){if(r===0)return"0 Bytes";const a=1024,o=n<0?0:n,t=["Bytes","KB","MB","GB"],i=Math.floor(Math.log(r)/Math.log(a));return parseFloat((r/Math.pow(a,i)).toFixed(o))+" "+t[i]}function S(r,n){if(r===0)return 0;const a=Math.round((r-n)/r*100);return Math.max(0,a)}function G(r,n){return`${r.replace(/\.[^.]+$/,"")}_compressed.${n}`}function V(r){return URL.createObjectURL(r)}function $(r){URL.revokeObjectURL(r)}const X=1e4;function ee(r){let n=0;const a=new Map;r.addEventListener("message",t=>{const{id:i,result:s,error:p}=t.data,m=a.get(i);m&&(a.delete(i),p?m.reject(new Error(p)):m.resolve(s))}),r.addEventListener("error",t=>{console.error("Worker error:",{message:t.message,filename:t.filename,lineno:t.lineno,colno:t.colno,error:t.error}),a.forEach(i=>i.reject(t)),a.clear()});function o(t,...i){return new Promise((s,p)=>{const m=++n;a.set(m,{resolve:s,reject:p}),r.postMessage({id:m,method:t,args:i})})}return{avifDecode:t=>o("avifDecode",t),jxlDecode:t=>o("jxlDecode",t),qoiDecode:t=>o("qoiDecode",t),webpDecode:t=>o("webpDecode",t),wp2Decode:t=>o("wp2Decode",t),avifEncode:(t,i)=>o("avifEncode",t,i),jxlEncode:(t,i)=>o("jxlEncode",t,i),mozjpegEncode:(t,i)=>o("mozjpegEncode",t,i),oxipngEncode:(t,i)=>o("oxipngEncode",t,i),qoiEncode:(t,i)=>o("qoiEncode",t,i),webpEncode:(t,i)=>o("webpEncode",t,i),wp2Encode:(t,i)=>o("wp2Encode",t,i),rotate:(t,i)=>o("rotate",t,i),quantize:(t,i)=>o("quantize",t,i),resize:(t,i)=>o("resize",t,i)}}function H(){const r=e.ref(!1),n=e.ref(!1),a=e.ref(null);let o=null,t=null;function i(){if(!o)try{n.value=!0,o=new Worker(new URL("/assets/imageWorker-Qv3pCULy.js",typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:I&&I.tagName.toUpperCase()==="SCRIPT"&&I.src||new URL("vue-image-compressor.umd.cjs",document.baseURI).href),{type:"module"}),r.value=!0,a.value=null}catch(h){a.value=h instanceof Error?h:new Error("Failed to start worker"),console.error("Worker start failed:",h)}finally{n.value=!1}}function s(){t&&(clearTimeout(t),t=null),o&&(o.terminate(),o=null,r.value=!1)}function p(){t&&clearTimeout(t),t=window.setTimeout(()=>{s()},X)}async function m(){if(o||i(),!o)throw new Error("Worker failed to initialize");return ee(o)}async function y(h,T){if(h.aborted)throw new DOMException("AbortError","AbortError");return clearTimeout(t),new Promise((C,O)=>{const D=()=>{s(),O(new DOMException("AbortError","AbortError"))};h.addEventListener("abort",D),T().then(C).catch(O).finally(()=>{h.removeEventListener("abort",D),p()})})}return e.onUnmounted(()=>{s()}),{isReady:r,isLoading:n,error:a,worker:o,getWorkerApi:m,executeTask:y,terminateWorker:s}}function Q(){const r=e.ref(!1),n=e.ref(0),a=e.ref(null),o=e.ref(null),t=e.ref(null),{getWorkerApi:i,executeTask:s}=H(),p=e.computed(()=>r.value&&!!t.value);async function m(E,l){const c=await W(l),f=await J(c),w=await i();if(!f){if(c==="image/avif")return s(E,()=>w.avifDecode(l));if(c==="image/webp")return s(E,()=>w.webpDecode(l));if(c==="image/jxl")return s(E,()=>w.jxlDecode(l));if(c==="image/webp2")return s(E,()=>w.wp2Decode(l));if(c==="image/qoi")return s(E,()=>w.qoiDecode(l))}return q(l)}async function y(E,l,c){if(c===0)return l;const f=await i();return s(E,()=>f.rotate(l,{rotate:c}))}async function h(E,l,c){var b,k;let f=l;const w=await i();return(b=c.resize)!=null&&b.enabled&&(f=await s(E,()=>w.resize(f,{width:c.resize.width||f.width,height:c.resize.height||f.height,method:c.resize.method||"lanczos3",fitMethod:c.resize.fitMethod||"stretch",premultiply:!0,linearRGB:!0}))),(k=c.quantize)!=null&&k.enabled&&(f=await s(E,()=>w.quantize(f,{numColors:c.quantize.numColors||256,dither:c.quantize.dither||1}))),f}async function T(E,l,c){const f=await i(),w=c.encoder;if(w==="browserJPEG")return(await N(l,"image/jpeg",c.encoderOptions.quality)).arrayBuffer();if(w==="browserPNG")return(await N(l,"image/png")).arrayBuffer();if(w==="browserGIF")throw new Error("Browser GIF encoding not supported directly");const k={mozJPEG:f.mozjpegEncode,webP:f.webpEncode,avif:f.avifEncode,jxl:f.jxlEncode,oxiPNG:f.oxipngEncode,qoi:f.qoiEncode,wp2:f.wp2Encode}[w];if(!k)throw new Error(`Unknown encoder: ${w}`);return(await s(E,()=>k.call(f,l,c.encoderOptions))).buffer}async function C(E,l){var w;t.value=new AbortController;const c=t.value.signal;r.value=!0,n.value=0,a.value=null;const f=o.value;o.value=null,(w=f==null?void 0:f.compressed)!=null&&w.blobUrl&&$(f.compressed.blobUrl);try{n.value=10;const b={file:E,size:E.size,width:0,height:0,blobUrl:V(E)},k=await m(c,E);b.width=k.width,b.height=k.height,n.value=25;const P=await y(c,k,l.rotate||0);n.value=35;const z=await h(c,P,l);n.value=50;const F=await T(c,z,l);n.value=80;const v=B[l.encoder],j=G(E.name,(v==null?void 0:v.extension)||"bin"),R=L(F,j,(v==null?void 0:v.mimeType)||"application/octet-stream"),U={file:R,size:R.size,width:z.width,height:z.height,blobUrl:V(R)},g={original:b,compressed:U,savingsBytes:b.size-U.size,savingsPercent:S(b.size,U.size),encoderType:l.encoder,encoderOptions:l.encoderOptions};return o.value=g,n.value=100,g}catch(b){if(b instanceof DOMException&&b.name==="AbortError")throw a.value="已取消",b;const k=b instanceof Error?b.message:"压缩失败";throw a.value=k,console.error("Compression error:",b),b}finally{r.value=!1,t.value=null}}function O(){t.value&&t.value.abort()}function D(){if(!o.value)return;const{compressed:E}=o.value,l=document.createElement("a");l.href=E.blobUrl,l.download=E.file.name,document.body.appendChild(l),l.click(),document.body.removeChild(l)}return{compress:C,cancel:O,downloadResult:D,isCompressing:r,progress:n,error:a,result:o,canCancel:p}}function K(){const r=e.ref("mozJPEG"),n=e.ref({}),a=e.computed(()=>B[r.value]),o=e.computed(()=>x[r.value]),t=e.computed(()=>A.map(m=>({type:m,label:B[m].label,mimeType:B[m].mimeType,extension:B[m].extension})));function i(m){r.value=m,n.value={...x[m]}}function s(m,y){n.value={...n.value,[m]:y}}function p(){n.value={...o.value}}return p(),{selectedEncoder:r,encoderOptions:n,currentMeta:a,currentDefaults:o,availableEncoders:t,selectEncoder:i,updateOption:s,resetOptions:p}}const te={class:"image-compressor"},oe={key:0,class:"preview-area"},ne={class:"preview-item"},re=["src"],ae={class:"preview-item"},ie=["src"],se={key:1,class:"compressing"},le=["value"],ce={key:2},de={key:1,class:"encoder-settings"},me=["value"],ue={key:0,class:"quality-control"},fe=["value"],pe={key:2,class:"actions"},ge=["disabled"],Ee={key:3,class:"error"},we=((r,n)=>{const a=r.__vccOpts||r;for(const[o,t]of n)a[o]=t;return a})(e.defineComponent({__name:"ImageCompressor",props:{defaultEncoder:{},defaultOptions:{}},emits:["success","error","cancel"],setup(r,{emit:n}){const a=r,o=n,t=e.ref(null),i=e.ref(null),s=e.ref(""),p=e.ref(""),{compress:m,cancel:y,downloadResult:h,isCompressing:T,progress:C,error:O,result:D,canCancel:E}=Q(),{selectedEncoder:l,encoderOptions:c,availableEncoders:f,selectEncoder:w,updateOption:b}=K();a.defaultEncoder&&w(a.defaultEncoder),a.defaultOptions&&Object.entries(a.defaultOptions).forEach(([g,d])=>b(g,d));const k=e.computed(()=>i.value?M(i.value.size):""),P=e.computed(()=>D.value?M(D.value.compressed.size):""),z=e.computed(()=>["mozJPEG","webP","jxl","browserJPEG","wp2"].includes(l.value));function F(g){const d=g.target;d.files&&d.files[0]&&j(d.files[0])}function v(g){var d;(d=g.dataTransfer)!=null&&d.files[0]&&j(g.dataTransfer.files[0])}function j(g){g.type.startsWith("image/")&&(s.value&&URL.revokeObjectURL(s.value),p.value&&(URL.revokeObjectURL(p.value),p.value=""),i.value=g,s.value=URL.createObjectURL(g))}function R(){w(l.value)}async function U(){if(i.value)try{const g={encoder:l.value,encoderOptions:{...c.value}},d=await m(i.value,g);p.value=d.compressed.blobUrl,o("success",d)}catch(g){if(g instanceof DOMException&&g.name==="AbortError"){o("cancel");return}o("error",g instanceof Error?g:new Error(String(g)))}}return(g,d)=>(e.openBlock(),e.createElementBlock("div",te,[e.createElementVNode("div",{class:"upload-zone",onDrop:e.withModifiers(v,["prevent"]),onDragover:d[1]||(d[1]=e.withModifiers(()=>{},["prevent"]))},[e.createElementVNode("input",{type:"file",accept:"image/*",onChange:F,ref_key:"fileInput",ref:t,class:"file-input"},null,544),e.createElementVNode("div",{class:"upload-prompt",onClick:d[0]||(d[0]=_=>{var Y;return(Y=t.value)==null?void 0:Y.click()})},[e.renderSlot(g.$slots,"upload-prompt",{},()=>[d[6]||(d[6]=e.createElementVNode("p",null,"拖拽图片到此处,或点击上传",-1))],!0)])],32),s.value?(e.openBlock(),e.createElementBlock("div",oe,[e.createElementVNode("div",ne,[d[7]||(d[7]=e.createElementVNode("h4",null,"原始图片",-1)),e.createElementVNode("img",{src:s.value,alt:"Original"},null,8,re),e.createElementVNode("p",null,e.toDisplayString(k.value),1)]),e.createElementVNode("div",ae,[d[8]||(d[8]=e.createElementVNode("h4",null,"压缩后",-1)),p.value?(e.openBlock(),e.createElementBlock("img",{key:0,src:p.value,alt:"Compressed"},null,8,ie)):e.unref(T)?(e.openBlock(),e.createElementBlock("div",se,[e.createElementVNode("progress",{value:e.unref(C),max:"100"},null,8,le),e.createElementVNode("p",null,"压缩中... "+e.toDisplayString(e.unref(C))+"%",1)])):e.createCommentVNode("",!0),P.value?(e.openBlock(),e.createElementBlock("p",ce,e.toDisplayString(P.value),1)):e.createCommentVNode("",!0)])])):e.createCommentVNode("",!0),s.value?(e.openBlock(),e.createElementBlock("div",de,[d[9]||(d[9]=e.createElementVNode("label",null,"编码器:",-1)),e.withDirectives(e.createElementVNode("select",{"onUpdate:modelValue":d[2]||(d[2]=_=>e.isRef(l)?l.value=_:null),onChange:R},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(f),_=>(e.openBlock(),e.createElementBlock("option",{key:_.type,value:_.type},e.toDisplayString(_.label)+" ("+e.toDisplayString(_.extension)+") ",9,me))),128))],544),[[e.vModelSelect,e.unref(l)]]),z.value?(e.openBlock(),e.createElementBlock("div",ue,[e.createElementVNode("label",null,[e.createTextVNode(" 质量: "+e.toDisplayString(e.unref(c).quality??75)+" ",1),e.createElementVNode("input",{type:"range",min:"0",max:"100",value:e.unref(c).quality??75,onInput:d[3]||(d[3]=_=>e.unref(b)("quality",Number(_.target.value)))},null,40,fe)])])):e.createCommentVNode("",!0),e.renderSlot(g.$slots,"encoder-settings",{encoder:e.unref(l),options:e.unref(c)},void 0,!0)])):e.createCommentVNode("",!0),s.value?(e.openBlock(),e.createElementBlock("div",pe,[e.createElementVNode("button",{onClick:U,disabled:e.unref(T),class:"btn-primary"},e.toDisplayString(e.unref(T)?"压缩中...":"开始压缩"),9,ge),e.unref(E)?(e.openBlock(),e.createElementBlock("button",{key:0,onClick:d[4]||(d[4]=(..._)=>e.unref(y)&&e.unref(y)(..._)),class:"btn-secondary"}," 取消 ")):e.createCommentVNode("",!0),e.unref(D)?(e.openBlock(),e.createElementBlock("button",{key:1,onClick:d[5]||(d[5]=(..._)=>e.unref(h)&&e.unref(h)(..._)),class:"btn-success"}," 下载 (节省 "+e.toDisplayString(e.unref(D).savingsPercent)+"%) ",1)):e.createCommentVNode("",!0)])):e.createCommentVNode("",!0),e.unref(O)?(e.openBlock(),e.createElementBlock("div",Ee,e.toDisplayString(e.unref(O)),1)):e.createCommentVNode("",!0)]))}}),[["__scopeId","data-v-d7e6eec9"]]),be=[{value:"lanczos3",label:"Lanczos3"},{value:"catrom",label:"Catrom"},{value:"mitchell",label:"Mitchell"},{value:"triangle",label:"Triangle"},{value:"vector",label:"Vector"}],he=[{value:"stretch",label:"拉伸"},{value:"contain",label:"适应"}],ye=[{value:0,label:"不旋转"},{value:90,label:"顺时针 90°"},{value:180,label:"旋转 180°"},{value:270,label:"逆时针 90°"}],ke={mozJPEG:"mozjpegEncode",webP:"webpEncode",avif:"avifEncode",jxl:"jxlEncode",oxiPNG:"oxipngEncode",qoi:"qoiEncode",wp2:"wp2Encode"};function _e(){return new Worker(new URL("/assets/imageWorker-Qv3pCULy.js",typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:I&&I.tagName.toUpperCase()==="SCRIPT"&&I.src||new URL("vue-image-compressor.umd.cjs",document.baseURI).href),{type:"module"})}function Te(r,n,a,o){return new Promise((t,i)=>{const s=_e();let p=!1;function m(){p||(p=!0,s.terminate())}s.addEventListener("message",T=>{const{result:C,error:O}=T.data;m(),O?i(new Error(O)):t(C.buffer)}),s.addEventListener("error",T=>{m(),i(T.error||T)});const y=()=>{m(),i(new DOMException("AbortError","AbortError"))};o&&o.addEventListener("abort",y,{once:!0});const h=ke[r];if(!h){m(),i(new Error(`Unknown encoder: ${r}`));return}s.postMessage({id:1,method:h,args:[n,a]})})}async function Oe(r,n={}){const{signal:a}=n;if(a!=null&&a.aborted)throw new DOMException("AbortError","AbortError");const o=n.encoder||"mozJPEG",t={...x[o],...n.encoderOptions},i=B[o],s=await q(r);if(a!=null&&a.aborted)throw new DOMException("AbortError","AbortError");let p;if(o==="browserJPEG")p=await(await N(s,"image/jpeg",t.quality)).arrayBuffer();else if(o==="browserPNG")p=await(await N(s,"image/png")).arrayBuffer();else{if(o==="browserGIF")throw new Error("Browser GIF encoding not supported directly");p=await Te(o,s,t,a)}if(a!=null&&a.aborted)throw new DOMException("AbortError","AbortError");const m=G(r.name,i.extension),y=L(p,m,i.mimeType);return{file:y,originalSize:r.size,compressedSize:y.size,savingsBytes:r.size-y.size,savingsPercent:S(r.size,y.size),width:s.width,height:s.height,encoderType:o,encoderOptions:t}}u.DEFAULT_ENCODER_OPTIONS=x,u.ENCODER_LIST=A,u.ENCODER_REGISTRY=B,u.FIT_METHODS=he,u.ImageCompressor=we,u.RESIZE_METHODS=be,u.ROTATE_OPTIONS=ye,u.arrayBufferToFile=L,u.blobToImageData=q,u.calculateSavings=S,u.canDecodeImageType=J,u.compressFile=Oe,u.createBlobUrl=V,u.formatBytes=M,u.generateCompressedFilename=G,u.getImageDimensions=Z,u.imageDataToBlob=N,u.revokeBlobUrl=$,u.sniffMimeType=W,u.useCompression=Q,u.useEncoderRegistry=K,u.useWorker=H,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
|
|
1
|
+
(function(u,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(u=typeof globalThis<"u"?globalThis:u||self,e(u.VueImageCompressor={},u.Vue))})(this,function(u,e){"use strict";var N=typeof document<"u"?document.currentScript:null;const O={mozJPEG:{label:"MozJPEG",mimeType:"image/jpeg",extension:"jpg"},webP:{label:"WebP",mimeType:"image/webp",extension:"webp"},avif:{label:"AVIF",mimeType:"image/avif",extension:"avif"},jxl:{label:"JPEG XL",mimeType:"image/jxl",extension:"jxl"},oxiPNG:{label:"OxiPNG",mimeType:"image/png",extension:"png"},browserJPEG:{label:"Browser JPEG",mimeType:"image/jpeg",extension:"jpg"},browserPNG:{label:"Browser PNG",mimeType:"image/png",extension:"png"},browserGIF:{label:"Browser GIF",mimeType:"image/gif",extension:"gif"},qoi:{label:"QOI",mimeType:"image/qoi",extension:"qoi"},wp2:{label:"WebP2",mimeType:"image/webp2",extension:"wp2"}},S={mozJPEG:{quality:75,baseline:!1,arithmetic:!1,progressive:!0,optimize_coding:!0,smoothing:0,color_space:3,quant_table:3,trellis_multipass:!1,trellis_opt_zero:!1,trellis_opt_table:!1,trellis_loops:1,auto_subsample:!0,chroma_subsample:2,separate_chroma_quality:!1,chroma_quality:75},webP:{quality:75,target_size:0,target_PSNR:0,method:4,sns_strength:50,filter_strength:60,filter_sharpness:0,filter_type:1,partitions:0,segments:4,pass:1,show_compressed:0,preprocessing:0,autofilter:0,partition_limit:0,alpha_compression:1,alpha_filtering:1,alpha_quality:100,lossless:0,exact:0,use_delta_palette:0,vlnr:0,near_lossless:60},avif:{cqLevel:33,denoiseLevel:0,cqAlphaLevel:-1,tileRows:0,tileCols:0,speed:6,subsample:1,chromaDeltaQ:!1,sharpness:0,tune:0},jxl:{effort:7,quality:75,progressive:!1,targetPsize:0},oxiPNG:{level:2},browserJPEG:{quality:.75},browserPNG:{},browserGIF:{},qoi:{},wp2:{quality:75}},A=Object.keys(O);async function j(r){const n=await createImageBitmap(r),a=document.createElement("canvas");a.width=n.width,a.height=n.height;const o=a.getContext("2d");return o.drawImage(n,0,0),o.getImageData(0,0,a.width,a.height)}async function z(r,n,a){const o=document.createElement("canvas");return o.width=r.width,o.height=r.height,o.getContext("2d").putImageData(r,0,0),new Promise(i=>{o.toBlob(s=>i(s),n,a)})}function Z(r){return new Promise((n,a)=>{const o=new Image;o.onload=()=>{n({width:o.width,height:o.height}),URL.revokeObjectURL(o.src)},o.onerror=a,o.src=URL.createObjectURL(r)})}async function W(r){const n=new Uint8Array(await r.slice(0,4).arrayBuffer());return n[0]===137&&n[1]===80?"image/png":n[0]===255&&n[1]===216?"image/jpeg":n[0]===71&&n[1]===73?"image/gif":n[0]===82&&n[1]===73?"image/webp":n[0]===0&&n[1]===0?"image/avif":r.type||"image/jpeg"}function J(r){return new Promise(n=>{const a=new Image;a.onload=()=>n(!0),a.onerror=()=>n(!1),a.src=`data:${r};base64,`})}function q(r,n,a){return new File([r],n,{type:a})}function L(r,n=2){if(r===0)return"0 Bytes";const a=1024,o=n<0?0:n,t=["Bytes","KB","MB","GB"],i=Math.floor(Math.log(r)/Math.log(a));return parseFloat((r/Math.pow(a,i)).toFixed(o))+" "+t[i]}function M(r,n){if(r===0)return 0;const a=Math.round((r-n)/r*100);return Math.max(0,a)}function G(r,n){return`${r.replace(/\.[^.]+$/,"")}_compressed.${n}`}function F(r){return URL.createObjectURL(r)}function H(r){URL.revokeObjectURL(r)}const X=1e4;function ee(r){let n=0;const a=new Map;r.addEventListener("message",t=>{const{id:i,result:s,error:p}=t.data,m=a.get(i);m&&(a.delete(i),p?m.reject(new Error(p)):m.resolve(s))}),r.addEventListener("error",t=>{console.error("Worker error:",{message:t.message,filename:t.filename,lineno:t.lineno,colno:t.colno,error:t.error}),a.forEach(i=>i.reject(t)),a.clear()});function o(t,...i){return new Promise((s,p)=>{const m=++n;a.set(m,{resolve:s,reject:p}),r.postMessage({id:m,method:t,args:i})})}return{avifDecode:t=>o("avifDecode",t),jxlDecode:t=>o("jxlDecode",t),qoiDecode:t=>o("qoiDecode",t),webpDecode:t=>o("webpDecode",t),wp2Decode:t=>o("wp2Decode",t),avifEncode:(t,i)=>o("avifEncode",t,i),jxlEncode:(t,i)=>o("jxlEncode",t,i),mozjpegEncode:(t,i)=>o("mozjpegEncode",t,i),oxipngEncode:(t,i)=>o("oxipngEncode",t,i),qoiEncode:(t,i)=>o("qoiEncode",t,i),webpEncode:(t,i)=>o("webpEncode",t,i),wp2Encode:(t,i)=>o("wp2Encode",t,i),rotate:(t,i)=>o("rotate",t,i),quantize:(t,i)=>o("quantize",t,i),resize:(t,i)=>o("resize",t,i)}}function $(){const r=e.ref(!1),n=e.ref(!1),a=e.ref(null);let o=null,t=null;function i(){if(!o)try{n.value=!0,o=new Worker(new URL(""+(typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__dirname+"/assets/imageWorker-B_HCdCy9.js").href:new URL("assets/imageWorker-B_HCdCy9.js",typeof document>"u"?location.href:document.currentScript&&document.currentScript.tagName.toUpperCase()==="SCRIPT"&&document.currentScript.src||document.baseURI).href),typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:N&&N.tagName.toUpperCase()==="SCRIPT"&&N.src||new URL("vue-image-compressor.umd.cjs",document.baseURI).href)),r.value=!0,a.value=null}catch(h){a.value=h instanceof Error?h:new Error("Failed to start worker"),console.error("Worker start failed:",h)}finally{n.value=!1}}function s(){t&&(clearTimeout(t),t=null),o&&(o.terminate(),o=null,r.value=!1)}function p(){t&&clearTimeout(t),t=window.setTimeout(()=>{s()},X)}async function m(){if(o||i(),!o)throw new Error("Worker failed to initialize");return ee(o)}async function y(h,T){if(h.aborted)throw new DOMException("AbortError","AbortError");return clearTimeout(t),new Promise((D,C)=>{const B=()=>{s(),C(new DOMException("AbortError","AbortError"))};h.addEventListener("abort",B),T().then(D).catch(C).finally(()=>{h.removeEventListener("abort",B),p()})})}return e.onUnmounted(()=>{s()}),{isReady:r,isLoading:n,error:a,worker:o,getWorkerApi:m,executeTask:y,terminateWorker:s}}function Q(){const r=e.ref(!1),n=e.ref(0),a=e.ref(null),o=e.ref(null),t=e.ref(null),{getWorkerApi:i,executeTask:s}=$(),p=e.computed(()=>r.value&&!!t.value);async function m(E,l){const c=await W(l),f=await J(c),w=await i();if(!f){if(c==="image/avif")return s(E,()=>w.avifDecode(l));if(c==="image/webp")return s(E,()=>w.webpDecode(l));if(c==="image/jxl")return s(E,()=>w.jxlDecode(l));if(c==="image/webp2")return s(E,()=>w.wp2Decode(l));if(c==="image/qoi")return s(E,()=>w.qoiDecode(l))}return j(l)}async function y(E,l,c){if(c===0)return l;const f=await i();return s(E,()=>f.rotate(l,{rotate:c}))}async function h(E,l,c){var b,_;let f=l;const w=await i();return(b=c.resize)!=null&&b.enabled&&(f=await s(E,()=>w.resize(f,{width:c.resize.width||f.width,height:c.resize.height||f.height,method:c.resize.method||"lanczos3",fitMethod:c.resize.fitMethod||"stretch",premultiply:!0,linearRGB:!0}))),(_=c.quantize)!=null&&_.enabled&&(f=await s(E,()=>w.quantize(f,{numColors:c.quantize.numColors||256,dither:c.quantize.dither||1}))),f}async function T(E,l,c){const f=await i(),w=c.encoder;if(w==="browserJPEG")return(await z(l,"image/jpeg",c.encoderOptions.quality)).arrayBuffer();if(w==="browserPNG")return(await z(l,"image/png")).arrayBuffer();if(w==="browserGIF")throw new Error("Browser GIF encoding not supported directly");const _={mozJPEG:f.mozjpegEncode,webP:f.webpEncode,avif:f.avifEncode,jxl:f.jxlEncode,oxiPNG:f.oxipngEncode,qoi:f.qoiEncode,wp2:f.wp2Encode}[w];if(!_)throw new Error(`Unknown encoder: ${w}`);return(await s(E,()=>_.call(f,l,c.encoderOptions))).buffer}async function D(E,l){var w;t.value=new AbortController;const c=t.value.signal;r.value=!0,n.value=0,a.value=null;const f=o.value;o.value=null,(w=f==null?void 0:f.compressed)!=null&&w.blobUrl&&H(f.compressed.blobUrl);try{n.value=10;const b={file:E,size:E.size,width:0,height:0,blobUrl:F(E)},_=await m(c,E);b.width=_.width,b.height=_.height,n.value=25;const P=await y(c,_,l.rotate||0);n.value=35;const I=await h(c,P,l);n.value=50;const V=await T(c,I,l);n.value=80;const R=O[l.encoder],x=G(E.name,(R==null?void 0:R.extension)||"bin"),v=q(V,x,(R==null?void 0:R.mimeType)||"application/octet-stream"),U={file:v,size:v.size,width:I.width,height:I.height,blobUrl:F(v)},g={original:b,compressed:U,savingsBytes:b.size-U.size,savingsPercent:M(b.size,U.size),encoderType:l.encoder,encoderOptions:l.encoderOptions};return o.value=g,n.value=100,g}catch(b){if(b instanceof DOMException&&b.name==="AbortError")throw a.value="已取消",b;const _=b instanceof Error?b.message:"压缩失败";throw a.value=_,console.error("Compression error:",b),b}finally{r.value=!1,t.value=null}}function C(){t.value&&t.value.abort()}function B(){if(!o.value)return;const{compressed:E}=o.value,l=document.createElement("a");l.href=E.blobUrl,l.download=E.file.name,document.body.appendChild(l),l.click(),document.body.removeChild(l)}return{compress:D,cancel:C,downloadResult:B,isCompressing:r,progress:n,error:a,result:o,canCancel:p}}function K(){const r=e.ref("mozJPEG"),n=e.ref({}),a=e.computed(()=>O[r.value]),o=e.computed(()=>S[r.value]),t=e.computed(()=>A.map(m=>({type:m,label:O[m].label,mimeType:O[m].mimeType,extension:O[m].extension})));function i(m){r.value=m,n.value={...S[m]}}function s(m,y){n.value={...n.value,[m]:y}}function p(){n.value={...o.value}}return p(),{selectedEncoder:r,encoderOptions:n,currentMeta:a,currentDefaults:o,availableEncoders:t,selectEncoder:i,updateOption:s,resetOptions:p}}const te={class:"image-compressor"},oe={key:0,class:"preview-area"},ne={class:"preview-item"},re=["src"],ae={class:"preview-item"},ie=["src"],se={key:1,class:"compressing"},le=["value"],ce={key:2},de={key:1,class:"encoder-settings"},me=["value"],ue={key:0,class:"quality-control"},fe=["value"],pe={key:2,class:"actions"},ge=["disabled"],Ee={key:3,class:"error"},we=((r,n)=>{const a=r.__vccOpts||r;for(const[o,t]of n)a[o]=t;return a})(e.defineComponent({__name:"ImageCompressor",props:{defaultEncoder:{},defaultOptions:{}},emits:["success","error","cancel"],setup(r,{emit:n}){const a=r,o=n,t=e.ref(null),i=e.ref(null),s=e.ref(""),p=e.ref(""),{compress:m,cancel:y,downloadResult:h,isCompressing:T,progress:D,error:C,result:B,canCancel:E}=Q(),{selectedEncoder:l,encoderOptions:c,availableEncoders:f,selectEncoder:w,updateOption:b}=K();a.defaultEncoder&&w(a.defaultEncoder),a.defaultOptions&&Object.entries(a.defaultOptions).forEach(([g,d])=>b(g,d));const _=e.computed(()=>i.value?L(i.value.size):""),P=e.computed(()=>B.value?L(B.value.compressed.size):""),I=e.computed(()=>["mozJPEG","webP","jxl","browserJPEG","wp2"].includes(l.value));function V(g){const d=g.target;d.files&&d.files[0]&&x(d.files[0])}function R(g){var d;(d=g.dataTransfer)!=null&&d.files[0]&&x(g.dataTransfer.files[0])}function x(g){g.type.startsWith("image/")&&(s.value&&URL.revokeObjectURL(s.value),p.value&&(URL.revokeObjectURL(p.value),p.value=""),i.value=g,s.value=URL.createObjectURL(g))}function v(){w(l.value)}async function U(){if(i.value)try{const g={encoder:l.value,encoderOptions:{...c.value}},d=await m(i.value,g);p.value=d.compressed.blobUrl,o("success",d)}catch(g){if(g instanceof DOMException&&g.name==="AbortError"){o("cancel");return}o("error",g instanceof Error?g:new Error(String(g)))}}return(g,d)=>(e.openBlock(),e.createElementBlock("div",te,[e.createElementVNode("div",{class:"upload-zone",onDrop:e.withModifiers(R,["prevent"]),onDragover:d[1]||(d[1]=e.withModifiers(()=>{},["prevent"]))},[e.createElementVNode("input",{type:"file",accept:"image/*",onChange:V,ref_key:"fileInput",ref:t,class:"file-input"},null,544),e.createElementVNode("div",{class:"upload-prompt",onClick:d[0]||(d[0]=k=>{var Y;return(Y=t.value)==null?void 0:Y.click()})},[e.renderSlot(g.$slots,"upload-prompt",{},()=>[d[6]||(d[6]=e.createElementVNode("p",null,"拖拽图片到此处,或点击上传",-1))],!0)])],32),s.value?(e.openBlock(),e.createElementBlock("div",oe,[e.createElementVNode("div",ne,[d[7]||(d[7]=e.createElementVNode("h4",null,"原始图片",-1)),e.createElementVNode("img",{src:s.value,alt:"Original"},null,8,re),e.createElementVNode("p",null,e.toDisplayString(_.value),1)]),e.createElementVNode("div",ae,[d[8]||(d[8]=e.createElementVNode("h4",null,"压缩后",-1)),p.value?(e.openBlock(),e.createElementBlock("img",{key:0,src:p.value,alt:"Compressed"},null,8,ie)):e.unref(T)?(e.openBlock(),e.createElementBlock("div",se,[e.createElementVNode("progress",{value:e.unref(D),max:"100"},null,8,le),e.createElementVNode("p",null,"压缩中... "+e.toDisplayString(e.unref(D))+"%",1)])):e.createCommentVNode("",!0),P.value?(e.openBlock(),e.createElementBlock("p",ce,e.toDisplayString(P.value),1)):e.createCommentVNode("",!0)])])):e.createCommentVNode("",!0),s.value?(e.openBlock(),e.createElementBlock("div",de,[d[9]||(d[9]=e.createElementVNode("label",null,"编码器:",-1)),e.withDirectives(e.createElementVNode("select",{"onUpdate:modelValue":d[2]||(d[2]=k=>e.isRef(l)?l.value=k:null),onChange:v},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(f),k=>(e.openBlock(),e.createElementBlock("option",{key:k.type,value:k.type},e.toDisplayString(k.label)+" ("+e.toDisplayString(k.extension)+") ",9,me))),128))],544),[[e.vModelSelect,e.unref(l)]]),I.value?(e.openBlock(),e.createElementBlock("div",ue,[e.createElementVNode("label",null,[e.createTextVNode(" 质量: "+e.toDisplayString(e.unref(c).quality??75)+" ",1),e.createElementVNode("input",{type:"range",min:"0",max:"100",value:e.unref(c).quality??75,onInput:d[3]||(d[3]=k=>e.unref(b)("quality",Number(k.target.value)))},null,40,fe)])])):e.createCommentVNode("",!0),e.renderSlot(g.$slots,"encoder-settings",{encoder:e.unref(l),options:e.unref(c)},void 0,!0)])):e.createCommentVNode("",!0),s.value?(e.openBlock(),e.createElementBlock("div",pe,[e.createElementVNode("button",{onClick:U,disabled:e.unref(T),class:"btn-primary"},e.toDisplayString(e.unref(T)?"压缩中...":"开始压缩"),9,ge),e.unref(E)?(e.openBlock(),e.createElementBlock("button",{key:0,onClick:d[4]||(d[4]=(...k)=>e.unref(y)&&e.unref(y)(...k)),class:"btn-secondary"}," 取消 ")):e.createCommentVNode("",!0),e.unref(B)?(e.openBlock(),e.createElementBlock("button",{key:1,onClick:d[5]||(d[5]=(...k)=>e.unref(h)&&e.unref(h)(...k)),class:"btn-success"}," 下载 (节省 "+e.toDisplayString(e.unref(B).savingsPercent)+"%) ",1)):e.createCommentVNode("",!0)])):e.createCommentVNode("",!0),e.unref(C)?(e.openBlock(),e.createElementBlock("div",Ee,e.toDisplayString(e.unref(C)),1)):e.createCommentVNode("",!0)]))}}),[["__scopeId","data-v-d7e6eec9"]]),be=[{value:"lanczos3",label:"Lanczos3"},{value:"catrom",label:"Catrom"},{value:"mitchell",label:"Mitchell"},{value:"triangle",label:"Triangle"},{value:"vector",label:"Vector"}],he=[{value:"stretch",label:"拉伸"},{value:"contain",label:"适应"}],ye=[{value:0,label:"不旋转"},{value:90,label:"顺时针 90°"},{value:180,label:"旋转 180°"},{value:270,label:"逆时针 90°"}],_e={mozJPEG:"mozjpegEncode",webP:"webpEncode",avif:"avifEncode",jxl:"jxlEncode",oxiPNG:"oxipngEncode",qoi:"qoiEncode",wp2:"wp2Encode"};function ke(){return new Worker(new URL(""+(typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__dirname+"/assets/imageWorker-B_HCdCy9.js").href:new URL("assets/imageWorker-B_HCdCy9.js",typeof document>"u"?location.href:document.currentScript&&document.currentScript.tagName.toUpperCase()==="SCRIPT"&&document.currentScript.src||document.baseURI).href),typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:N&&N.tagName.toUpperCase()==="SCRIPT"&&N.src||new URL("vue-image-compressor.umd.cjs",document.baseURI).href))}function Te(r,n,a,o){return new Promise((t,i)=>{const s=ke();let p=!1;function m(){p||(p=!0,s.terminate())}s.addEventListener("message",T=>{const{result:D,error:C}=T.data;m(),C?i(new Error(C)):t(D.buffer)}),s.addEventListener("error",T=>{m(),i(T.error||T)});const y=()=>{m(),i(new DOMException("AbortError","AbortError"))};o&&o.addEventListener("abort",y,{once:!0});const h=_e[r];if(!h){m(),i(new Error(`Unknown encoder: ${r}`));return}s.postMessage({id:1,method:h,args:[n,a]})})}async function Ce(r,n={}){const{signal:a}=n;if(a!=null&&a.aborted)throw new DOMException("AbortError","AbortError");const o=n.encoder||"mozJPEG",t={...S[o],...n.encoderOptions},i=O[o],s=await j(r);if(a!=null&&a.aborted)throw new DOMException("AbortError","AbortError");let p;if(o==="browserJPEG")p=await(await z(s,"image/jpeg",t.quality)).arrayBuffer();else if(o==="browserPNG")p=await(await z(s,"image/png")).arrayBuffer();else{if(o==="browserGIF")throw new Error("Browser GIF encoding not supported directly");p=await Te(o,s,t,a)}if(a!=null&&a.aborted)throw new DOMException("AbortError","AbortError");const m=G(r.name,i.extension),y=q(p,m,i.mimeType);return{file:y,originalSize:r.size,compressedSize:y.size,savingsBytes:r.size-y.size,savingsPercent:M(r.size,y.size),width:s.width,height:s.height,encoderType:o,encoderOptions:t}}u.DEFAULT_ENCODER_OPTIONS=S,u.ENCODER_LIST=A,u.ENCODER_REGISTRY=O,u.FIT_METHODS=he,u.ImageCompressor=we,u.RESIZE_METHODS=be,u.ROTATE_OPTIONS=ye,u.arrayBufferToFile=q,u.blobToImageData=j,u.calculateSavings=M,u.canDecodeImageType=J,u.compressFile=Ce,u.createBlobUrl=F,u.formatBytes=L,u.generateCompressedFilename=G,u.getImageDimensions=Z,u.imageDataToBlob=z,u.revokeBlobUrl=H,u.sniffMimeType=W,u.useCompression=Q,u.useEncoderRegistry=K,u.useWorker=$,Object.defineProperty(u,Symbol.toStringTag,{value:"Module"})});
|
package/package.json
CHANGED
|
@@ -87,8 +87,7 @@ export function useWorker() {
|
|
|
87
87
|
try {
|
|
88
88
|
isLoading.value = true;
|
|
89
89
|
worker = new Worker(
|
|
90
|
-
new URL('../workers/imageWorker.ts', import.meta.url)
|
|
91
|
-
{ type: 'module' }
|
|
90
|
+
new URL('../workers/imageWorker.ts', import.meta.url)
|
|
92
91
|
);
|
|
93
92
|
isReady.value = true;
|
|
94
93
|
error.value = null;
|
|
@@ -51,8 +51,7 @@ const ENCODER_METHOD_MAP: Record<string, string> = {
|
|
|
51
51
|
|
|
52
52
|
function createWorker(): Worker {
|
|
53
53
|
return new Worker(
|
|
54
|
-
new URL('../workers/imageWorker.ts', import.meta.url)
|
|
55
|
-
{ type: 'module' }
|
|
54
|
+
new URL('../workers/imageWorker.ts', import.meta.url)
|
|
56
55
|
);
|
|
57
56
|
}
|
|
58
57
|
|
|
@@ -82,7 +82,7 @@ const workerApi: WorkerApi = {
|
|
|
82
82
|
return initEmscriptenModule(mozjpeg_enc, {
|
|
83
83
|
locateFile: (path: string) => {
|
|
84
84
|
if (path === 'mozjpeg_enc.wasm') {
|
|
85
|
-
return '
|
|
85
|
+
return '../codecs/mozjpeg/enc/mozjpeg_enc.wasm';
|
|
86
86
|
}
|
|
87
87
|
return path;
|
|
88
88
|
},
|