compressorjs-next 2.0.0 → 2.0.1

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 CHANGED
@@ -297,7 +297,7 @@ new Compressor(file, {
297
297
  * Type: `Function`
298
298
  * Default: `null`
299
299
  * Parameters:
300
- - `result`: The compressed image (a `File` (**read only**) or `Blob` object).
300
+ - `result`: The compressed image (a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) object, which is also a `Blob`).
301
301
 
302
302
  The hook function to execute when successful to compress the image.
303
303
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Compressor.js Next v2.0.0
2
+ * Compressor.js Next v2.0.1
3
3
  * https://github.com/j9t/compressorjs-next
4
4
  *
5
5
  * Copyright 2018–2024 Chen Fengyuan
@@ -537,17 +537,18 @@ class Compressor {
537
537
  target
538
538
  }) => {
539
539
  if (this.aborted) return;
540
- let result;
540
+ let blob;
541
541
  try {
542
- const stripped = stripExif(target.result);
543
- result = uint8ArrayToBlob(stripped, mimeType);
542
+ blob = uint8ArrayToBlob(stripExif(target.result), mimeType);
544
543
  } catch {
545
544
  this.fail(new Error('Failed to process the image data.'));
546
545
  return;
547
546
  }
548
547
  const date = new Date();
549
- result.name = file.name;
550
- result.lastModified = date.getTime();
548
+ const result = new File([blob], file.name || '', {
549
+ type: mimeType,
550
+ lastModified: date.getTime()
551
+ });
551
552
  this.result = result;
552
553
  if (options.success) {
553
554
  options.success.call(this, result);
@@ -846,13 +847,16 @@ class Compressor {
846
847
  strictFallback = true;
847
848
  } else {
848
849
  const date = new Date();
849
- result.lastModified = date.getTime();
850
- result.name = file.name;
850
+ let name = file.name || '';
851
851
 
852
852
  // Convert the extension to match its type
853
- if (result.name && result.type !== file.type) {
854
- result.name = result.name.replace(REGEXP_EXTENSION, imageTypeToExtension(result.type));
853
+ if (name && result.type !== file.type) {
854
+ name = name.replace(REGEXP_EXTENSION, imageTypeToExtension(result.type));
855
855
  }
856
+ result = new File([result], name, {
857
+ type: result.type,
858
+ lastModified: date.getTime()
859
+ });
856
860
  }
857
861
  } else {
858
862
  // Returns original file if the result is null in some cases
@@ -866,9 +870,11 @@ class Compressor {
866
870
  if (file.arrayBuffer) {
867
871
  file.arrayBuffer().then(arrayBuffer => {
868
872
  if (this.aborted) return;
869
- const stripped = uint8ArrayToBlob(stripExif(arrayBuffer), file.type);
870
- stripped.name = file.name;
871
- stripped.lastModified = file.lastModified;
873
+ const strippedBlob = uint8ArrayToBlob(stripExif(arrayBuffer), file.type);
874
+ const stripped = new File([strippedBlob], file.name || '', {
875
+ type: file.type,
876
+ lastModified: file.lastModified || Date.now()
877
+ });
872
878
  this.result = stripped;
873
879
  if (options.success) {
874
880
  options.success.call(this, stripped);
@@ -888,9 +894,11 @@ class Compressor {
888
894
  target
889
895
  }) => {
890
896
  if (this.aborted) return;
891
- const stripped = uint8ArrayToBlob(stripExif(target.result), file.type);
892
- stripped.name = file.name;
893
- stripped.lastModified = file.lastModified;
897
+ const strippedBlob = uint8ArrayToBlob(stripExif(target.result), file.type);
898
+ const stripped = new File([strippedBlob], file.name || '', {
899
+ type: file.type,
900
+ lastModified: file.lastModified || Date.now()
901
+ });
894
902
  this.result = stripped;
895
903
  if (options.success) {
896
904
  options.success.call(this, stripped);
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Compressor.js Next v2.0.0
2
+ * Compressor.js Next v2.0.1
3
3
  * https://github.com/j9t/compressorjs-next
4
4
  *
5
5
  * Copyright 2018–2024 Chen Fengyuan
@@ -535,17 +535,18 @@ class Compressor {
535
535
  target
536
536
  }) => {
537
537
  if (this.aborted) return;
538
- let result;
538
+ let blob;
539
539
  try {
540
- const stripped = stripExif(target.result);
541
- result = uint8ArrayToBlob(stripped, mimeType);
540
+ blob = uint8ArrayToBlob(stripExif(target.result), mimeType);
542
541
  } catch {
543
542
  this.fail(new Error('Failed to process the image data.'));
544
543
  return;
545
544
  }
546
545
  const date = new Date();
547
- result.name = file.name;
548
- result.lastModified = date.getTime();
546
+ const result = new File([blob], file.name || '', {
547
+ type: mimeType,
548
+ lastModified: date.getTime()
549
+ });
549
550
  this.result = result;
550
551
  if (options.success) {
551
552
  options.success.call(this, result);
@@ -844,13 +845,16 @@ class Compressor {
844
845
  strictFallback = true;
845
846
  } else {
846
847
  const date = new Date();
847
- result.lastModified = date.getTime();
848
- result.name = file.name;
848
+ let name = file.name || '';
849
849
 
850
850
  // Convert the extension to match its type
851
- if (result.name && result.type !== file.type) {
852
- result.name = result.name.replace(REGEXP_EXTENSION, imageTypeToExtension(result.type));
851
+ if (name && result.type !== file.type) {
852
+ name = name.replace(REGEXP_EXTENSION, imageTypeToExtension(result.type));
853
853
  }
854
+ result = new File([result], name, {
855
+ type: result.type,
856
+ lastModified: date.getTime()
857
+ });
854
858
  }
855
859
  } else {
856
860
  // Returns original file if the result is null in some cases
@@ -864,9 +868,11 @@ class Compressor {
864
868
  if (file.arrayBuffer) {
865
869
  file.arrayBuffer().then(arrayBuffer => {
866
870
  if (this.aborted) return;
867
- const stripped = uint8ArrayToBlob(stripExif(arrayBuffer), file.type);
868
- stripped.name = file.name;
869
- stripped.lastModified = file.lastModified;
871
+ const strippedBlob = uint8ArrayToBlob(stripExif(arrayBuffer), file.type);
872
+ const stripped = new File([strippedBlob], file.name || '', {
873
+ type: file.type,
874
+ lastModified: file.lastModified || Date.now()
875
+ });
870
876
  this.result = stripped;
871
877
  if (options.success) {
872
878
  options.success.call(this, stripped);
@@ -886,9 +892,11 @@ class Compressor {
886
892
  target
887
893
  }) => {
888
894
  if (this.aborted) return;
889
- const stripped = uint8ArrayToBlob(stripExif(target.result), file.type);
890
- stripped.name = file.name;
891
- stripped.lastModified = file.lastModified;
895
+ const strippedBlob = uint8ArrayToBlob(stripExif(target.result), file.type);
896
+ const stripped = new File([strippedBlob], file.name || '', {
897
+ type: file.type,
898
+ lastModified: file.lastModified || Date.now()
899
+ });
892
900
  this.result = stripped;
893
901
  if (options.success) {
894
902
  options.success.call(this, stripped);
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Compressor.js Next v2.0.0
2
+ * Compressor.js Next v2.0.1
3
3
  * https://github.com/j9t/compressorjs-next
4
4
  *
5
5
  * Copyright 2018–2024 Chen Fengyuan
@@ -541,17 +541,18 @@
541
541
  target
542
542
  }) => {
543
543
  if (this.aborted) return;
544
- let result;
544
+ let blob;
545
545
  try {
546
- const stripped = stripExif(target.result);
547
- result = uint8ArrayToBlob(stripped, mimeType);
546
+ blob = uint8ArrayToBlob(stripExif(target.result), mimeType);
548
547
  } catch {
549
548
  this.fail(new Error('Failed to process the image data.'));
550
549
  return;
551
550
  }
552
551
  const date = new Date();
553
- result.name = file.name;
554
- result.lastModified = date.getTime();
552
+ const result = new File([blob], file.name || '', {
553
+ type: mimeType,
554
+ lastModified: date.getTime()
555
+ });
555
556
  this.result = result;
556
557
  if (options.success) {
557
558
  options.success.call(this, result);
@@ -850,13 +851,16 @@
850
851
  strictFallback = true;
851
852
  } else {
852
853
  const date = new Date();
853
- result.lastModified = date.getTime();
854
- result.name = file.name;
854
+ let name = file.name || '';
855
855
 
856
856
  // Convert the extension to match its type
857
- if (result.name && result.type !== file.type) {
858
- result.name = result.name.replace(REGEXP_EXTENSION, imageTypeToExtension(result.type));
857
+ if (name && result.type !== file.type) {
858
+ name = name.replace(REGEXP_EXTENSION, imageTypeToExtension(result.type));
859
859
  }
860
+ result = new File([result], name, {
861
+ type: result.type,
862
+ lastModified: date.getTime()
863
+ });
860
864
  }
861
865
  } else {
862
866
  // Returns original file if the result is null in some cases
@@ -870,9 +874,11 @@
870
874
  if (file.arrayBuffer) {
871
875
  file.arrayBuffer().then(arrayBuffer => {
872
876
  if (this.aborted) return;
873
- const stripped = uint8ArrayToBlob(stripExif(arrayBuffer), file.type);
874
- stripped.name = file.name;
875
- stripped.lastModified = file.lastModified;
877
+ const strippedBlob = uint8ArrayToBlob(stripExif(arrayBuffer), file.type);
878
+ const stripped = new File([strippedBlob], file.name || '', {
879
+ type: file.type,
880
+ lastModified: file.lastModified || Date.now()
881
+ });
876
882
  this.result = stripped;
877
883
  if (options.success) {
878
884
  options.success.call(this, stripped);
@@ -892,9 +898,11 @@
892
898
  target
893
899
  }) => {
894
900
  if (this.aborted) return;
895
- const stripped = uint8ArrayToBlob(stripExif(target.result), file.type);
896
- stripped.name = file.name;
897
- stripped.lastModified = file.lastModified;
901
+ const strippedBlob = uint8ArrayToBlob(stripExif(target.result), file.type);
902
+ const stripped = new File([strippedBlob], file.name || '', {
903
+ type: file.type,
904
+ lastModified: file.lastModified || Date.now()
905
+ });
898
906
  this.result = stripped;
899
907
  if (options.success) {
900
908
  options.success.call(this, stripped);
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Compressor.js Next v2.0.0
2
+ * Compressor.js Next v2.0.1
3
3
  * https://github.com/j9t/compressorjs-next
4
4
  *
5
5
  * Copyright 2018–2024 Chen Fengyuan
@@ -7,4 +7,4 @@
7
7
  *
8
8
  * Released under the MIT license.
9
9
  */
10
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Compressor=t()}(this,function(){"use strict";var e={strict:!0,retainExif:!1,maxWidth:1/0,maxHeight:1/0,minWidth:0,minHeight:0,width:void 0,height:void 0,resize:"none",quality:.8,mimeType:"auto",convertTypes:[],convertSize:5e6,beforeDraw:null,drew:null,success:null,error:null};const t="undefined"!=typeof window&&void 0!==window.document?window:{},i=e=>e>0&&e<1/0,r=/^image\/.+$/;function a(e){return r.test(e)}const{fromCharCode:n}=String;function s(e){const t=new DataView(e);let i;try{let e,r,a;if(255===t.getUint8(0)&&216===t.getUint8(1)){const e=t.byteLength;let i=2;for(;i+1<e;){if(255===t.getUint8(i)&&225===t.getUint8(i+1)){r=i;break}i+=1}}if(r){const i=r+10;if("Exif"===function(e,t,i){let r,a="";for(i+=t,r=t;r<i;r+=1)a+=n(e.getUint8(r));return a}(t,r+4,4)){const r=t.getUint16(i);if(e=18761===r,(e||19789===r)&&42===t.getUint16(i+2,e)){const r=t.getUint32(i+4,e);r>=8&&(a=i+r)}}}if(a){const r=t.getUint16(a,e);let n,s;for(s=0;s<r;s+=1)if(n=a+12*s+2,274===t.getUint16(n,e)){n+=8,i=t.getUint16(n,e),t.setUint16(n,1,e);break}}}catch{i=1}return i}let o;function h(e){const t=new DataView(e),{byteLength:i}=t,r=[];if(i<4||255!==t.getUint8(0)||216!==t.getUint8(1))return new Uint8Array(e);r.push(new Uint8Array(e,0,2));let a=2;for(;a+3<i;){const n=t.getUint8(a),s=t.getUint8(a+1);if(255!==n)break;if(218===s){r.push(new Uint8Array(e,a));break}if(a+3>=i)break;const o=t.getUint16(a+2);if(o<2)break;const h=a+2+o;if(h>i)break;225!==s&&r.push(new Uint8Array(e,a,h-a)),a=h}const n=r.reduce((e,t)=>e+t.length,0),s=new Uint8Array(n);let o=0;for(const e of r)s.set(e,o),o+=e.length;return s}const l=/\.\d*(?:0|9){12}\d*$/;function d(e,t=1e11){return l.test(e)?Math.round(e*t)/t:e}function c({aspectRatio:e,height:t,width:r},a="none"){const n=i(r),s=i(t);if(n&&s){const i=t*e;("contain"===a||"none"===a)&&i>r||"cover"===a&&i<r?t=r/e:r=t*e}else n?t=r/e:s&&(r=t*e);return{width:r,height:t}}function f(e,t){return new Blob([e],{type:t})}const{ArrayBuffer:u,FileReader:g}=t,m=t.URL||t.webkitURL,w=/\.\w+$/;return class{constructor(t,i){this.file=t,this.exif=[],this.image=new Image,this.options={...e,...i},this.mimeTypeSet=i&&i.mimeType&&a(i.mimeType),this.aborted=!1,this.canvasFallback=!1,this.result=null,this.url=null,this.init()}init(){const{file:e,options:t}=this;if(!(e instanceof Blob))return void this.fail(new Error("The first argument must be a File or Blob object."));const i=e.type;if(!a(i))return void this.fail(new Error("The first argument must be an image File or Blob object."));if(!m||!g)return void this.fail(new Error("The current browser does not support image compression."));if(u||(t.retainExif=!1),!function(){if(void 0!==o)return o;try{const e=document.createElement("canvas");e.width=4,e.height=4;const t=e.getContext("2d"),i=t.createImageData(e.width,e.height);for(let e=0;e<i.data.length;e+=4)i.data[e]=e,i.data[e+1]=1,i.data[e+2]=2,i.data[e+3]=255;t.putImageData(i,0,0);const r=t.getImageData(0,0,e.width,e.height);o=r.data.every((e,t)=>{const i=t%4;return 0===i?e===(255&t):1===i?1===e:2===i?2===e:255===e})}catch{o=!1}return o}()){if(console.warn("Compressor.js Next: Canvas data is unreliable (e.g., due to browser fingerprinting resistance)—compression, resizing, and format conversion are unavailable"),this.canvasFallback=!0,"image/jpeg"!==i||t.retainExif)Promise.resolve().then(()=>{this.aborted||(this.result=e,t.success&&t.success.call(this,e))});else{const r=new g;this.reader=r,r.onload=({target:r})=>{if(this.aborted)return;let a;try{a=f(h(r.result),i)}catch{return void this.fail(new Error("Failed to process the image data."))}const n=new Date;a.name=e.name,a.lastModified=n.getTime(),this.result=a,t.success&&t.success.call(this,a)},r.onabort=()=>{this.fail(new Error("Aborted to read the image with FileReader."))},r.onerror=()=>{this.fail(new Error("Failed to read the image with FileReader."))},r.onloadend=()=>{this.reader=null},r.readAsArrayBuffer(e)}return}if("image/jpeg"===i&&t.retainExif){const t=new g;this.reader=t,t.onload=({target:t})=>{this.aborted||(s(t.result),this.exif=function(e){const t=new DataView(e),{byteLength:i}=t,r=[];let a=0;for(;a+3<i;){const e=t.getUint8(a),n=t.getUint8(a+1);if(255===e&&218===n)break;if(255===e&&216===n)a+=2;else{const s=a+t.getUint16(a+2)+2;if(255===e&&225===n)for(let e=a;e<s&&e<i;e+=1)r.push(t.getUint8(e));a=s}}return r}(t.result),this.url=m.createObjectURL(e),this.load({url:this.url}))},t.onabort=()=>{this.fail(new Error("Aborted to read the image with FileReader."))},t.onerror=()=>{this.fail(new Error("Failed to read the image with FileReader."))},t.onloadend=()=>{this.reader=null},t.readAsArrayBuffer(e)}else this.url=m.createObjectURL(e),this.load({url:this.url})}load(e){const{file:i,image:r}=this;r.onload=()=>{this.draw({...e,naturalWidth:r.naturalWidth,naturalHeight:r.naturalHeight})},r.onabort=()=>{this.fail(new Error("Aborted to load the image."))},r.onerror=()=>{this.fail(new Error("Failed to load the image."))},t.navigator&&/(?:iPad|iPhone|iPod).*?AppleWebKit/i.test(t.navigator.userAgent)&&(r.crossOrigin="anonymous"),r.alt=i.name,r.src=e.url}draw({naturalWidth:e,naturalHeight:t}){const{file:r,image:n,options:s}=this,o=document.createElement("canvas"),l=o.getContext("2d"),u=("contain"===s.resize||"cover"===s.resize)&&i(s.width)&&i(s.height);let m=Math.max(s.maxWidth,0)||1/0,w=Math.max(s.maxHeight,0)||1/0,p=Math.max(s.minWidth,0)||0,b=Math.max(s.minHeight,0)||0,y=e/t,{width:U,height:v}=s;u&&(y=U/v),({width:m,height:w}=c({aspectRatio:y,width:m,height:w},"contain")),({width:p,height:b}=c({aspectRatio:y,width:p,height:b},"cover")),u?({width:U,height:v}=c({aspectRatio:y,width:U,height:v},s.resize)):({width:U=e,height:v=t}=c({aspectRatio:y,width:U,height:v})),U=Math.floor(d(Math.min(Math.max(U,p),m))),v=Math.floor(d(Math.min(Math.max(v,b),w)));const x=[];if(u){const{width:i,height:r}=c({aspectRatio:y,width:e,height:t},{contain:"cover",cover:"contain"}[s.resize]),a=(e-i)/2,n=(t-r)/2;x.push(a,n,i,r)}x.push(0,0,U,v),o.width=U,o.height=v,a(s.mimeType)||(s.mimeType=r.type);let E="transparent";!this.mimeTypeSet&&r.size>s.convertSize&&s.convertTypes.indexOf(s.mimeType)>=0&&(s.mimeType="image/jpeg");const F="image/jpeg"===s.mimeType;if(F&&(E="#fff"),l.fillStyle=E,l.fillRect(0,0,U,v),s.beforeDraw&&s.beforeDraw.call(this,l,o),this.aborted)return;if(l.drawImage(n,...x),s.drew&&s.drew.call(this,l,o),this.aborted)return;o.toBlob(i=>{if(!this.aborted){const r=i=>this.done({naturalWidth:e,naturalHeight:t,result:i});if(i&&F&&s.retainExif&&this.exif&&this.exif.length>0){const e=e=>{if(this.aborted)return;const t=function(e,t){const i=new DataView(e),r=new Uint8Array(e);if(255!==i.getUint8(2)||224!==i.getUint8(3))return r;const a=4+i.getUint16(4),n=r.byteLength-a,s=new Uint8Array(2+t.length+n);s[0]=255,s[1]=216;for(let e=0;e<t.length;e+=1)s[2+e]=t[e];return s.set(r.subarray(a),2+t.length),s}(e,this.exif);r(f(t,s.mimeType))};if(i.arrayBuffer)i.arrayBuffer().then(e).catch(()=>{this.aborted||this.fail(new Error("Failed to read the compressed image with `Blob.arrayBuffer()`."))});else{const t=new g;this.reader=t,t.onload=({target:t})=>{e(t.result)},t.onabort=()=>{this.fail(new Error("Aborted to read the compressed image with FileReader."))},t.onerror=()=>{this.fail(new Error("Failed to read the compressed image with FileReader."))},t.onloadend=()=>{this.reader=null},t.readAsArrayBuffer(i)}}else if(i&&F&&!s.retainExif){const e=e=>{this.aborted||r(f(h(e),s.mimeType))};if(i.arrayBuffer)i.arrayBuffer().then(e).catch(()=>{this.aborted||this.fail(new Error("Failed to read the compressed image with `Blob.arrayBuffer()`."))});else{const t=new g;this.reader=t,t.onload=({target:t})=>{e(t.result)},t.onabort=()=>{this.fail(new Error("Aborted to read the compressed image with FileReader."))},t.onerror=()=>{this.fail(new Error("Failed to read the compressed image with FileReader."))},t.onloadend=()=>{this.reader=null},t.readAsArrayBuffer(i)}}else r(i)}},s.mimeType,s.quality)}done({naturalWidth:e,naturalHeight:t,result:i}){const{file:r,options:n}=this;this.revokeUrl();let s=!1;if(i)if(n.strict&&!n.retainExif&&i.size>r.size&&n.mimeType===r.type&&!(n.width>e||n.height>t||n.minWidth>e||n.minHeight>t||n.maxWidth<e||n.maxHeight<t))i=r,s=!0;else{const e=new Date;i.lastModified=e.getTime(),i.name=r.name,i.name&&i.type!==r.type&&(i.name=i.name.replace(w,function(e){let t=a(e)?e.slice(6):"";return"jpeg"===t&&(t="jpg"),`.${t}`}(i.type)))}else console.warn("Compressor.js Next: Canvas produced no output—returning the original image"),i=r;if(s&&"image/jpeg"===r.type)if(r.arrayBuffer)r.arrayBuffer().then(e=>{if(this.aborted)return;const t=f(h(e),r.type);t.name=r.name,t.lastModified=r.lastModified,this.result=t,n.success&&n.success.call(this,t)}).catch(e=>{this.aborted||(console.warn(`Compressor.js Next: Failed to strip EXIF from original file—returning original with EXIF intact${r.name?` [${r.name}]`:""}${e?.message?`: ${e.message}`:""}`),this.result=r,n.success&&n.success.call(this,r))});else{const e=new g;this.reader=e,e.onload=({target:e})=>{if(this.aborted)return;const t=f(h(e.result),r.type);t.name=r.name,t.lastModified=r.lastModified,this.result=t,n.success&&n.success.call(this,t)},e.onabort=()=>{this.fail(new Error("Aborted to read the original file with FileReader."))},e.onerror=()=>{this.aborted||(console.warn("Compressor.js Next: Failed to strip EXIF from original file—returning original with EXIF intact"+(r.name?` [${r.name}]`:"")),this.result=r,n.success&&n.success.call(this,r))},e.onloadend=()=>{this.reader=null},e.readAsArrayBuffer(r)}else this.result=i,n.success&&n.success.call(this,i)}fail(e){const{options:t}=this;if(this.revokeUrl(),!t.error)throw e;t.error.call(this,e)}revokeUrl(){m&&this.url&&(m.revokeObjectURL(this.url),this.url=null)}abort(){this.aborted||(this.aborted=!0,this.reader?this.reader.abort():this.image.complete?this.fail(new Error("The compression process has been aborted.")):(this.image.onload=null,this.image.onerror=null,this.image.onabort=null,this.fail(new Error("Aborted to load the image."))))}static setDefaults(t){Object.assign(e,t)}}});
10
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Compressor=t()}(this,function(){"use strict";var e={strict:!0,retainExif:!1,maxWidth:1/0,maxHeight:1/0,minWidth:0,minHeight:0,width:void 0,height:void 0,resize:"none",quality:.8,mimeType:"auto",convertTypes:[],convertSize:5e6,beforeDraw:null,drew:null,success:null,error:null};const t="undefined"!=typeof window&&void 0!==window.document?window:{},i=e=>e>0&&e<1/0,r=/^image\/.+$/;function a(e){return r.test(e)}const{fromCharCode:n}=String;function s(e){const t=new DataView(e);let i;try{let e,r,a;if(255===t.getUint8(0)&&216===t.getUint8(1)){const e=t.byteLength;let i=2;for(;i+1<e;){if(255===t.getUint8(i)&&225===t.getUint8(i+1)){r=i;break}i+=1}}if(r){const i=r+10;if("Exif"===function(e,t,i){let r,a="";for(i+=t,r=t;r<i;r+=1)a+=n(e.getUint8(r));return a}(t,r+4,4)){const r=t.getUint16(i);if(e=18761===r,(e||19789===r)&&42===t.getUint16(i+2,e)){const r=t.getUint32(i+4,e);r>=8&&(a=i+r)}}}if(a){const r=t.getUint16(a,e);let n,s;for(s=0;s<r;s+=1)if(n=a+12*s+2,274===t.getUint16(n,e)){n+=8,i=t.getUint16(n,e),t.setUint16(n,1,e);break}}}catch{i=1}return i}let o;function h(e){const t=new DataView(e),{byteLength:i}=t,r=[];if(i<4||255!==t.getUint8(0)||216!==t.getUint8(1))return new Uint8Array(e);r.push(new Uint8Array(e,0,2));let a=2;for(;a+3<i;){const n=t.getUint8(a),s=t.getUint8(a+1);if(255!==n)break;if(218===s){r.push(new Uint8Array(e,a));break}if(a+3>=i)break;const o=t.getUint16(a+2);if(o<2)break;const h=a+2+o;if(h>i)break;225!==s&&r.push(new Uint8Array(e,a,h-a)),a=h}const n=r.reduce((e,t)=>e+t.length,0),s=new Uint8Array(n);let o=0;for(const e of r)s.set(e,o),o+=e.length;return s}const l=/\.\d*(?:0|9){12}\d*$/;function d(e,t=1e11){return l.test(e)?Math.round(e*t)/t:e}function c({aspectRatio:e,height:t,width:r},a="none"){const n=i(r),s=i(t);if(n&&s){const i=t*e;("contain"===a||"none"===a)&&i>r||"cover"===a&&i<r?t=r/e:r=t*e}else n?t=r/e:s&&(r=t*e);return{width:r,height:t}}function f(e,t){return new Blob([e],{type:t})}const{ArrayBuffer:u,FileReader:g}=t,m=t.URL||t.webkitURL,w=/\.\w+$/;return class{constructor(t,i){this.file=t,this.exif=[],this.image=new Image,this.options={...e,...i},this.mimeTypeSet=i&&i.mimeType&&a(i.mimeType),this.aborted=!1,this.canvasFallback=!1,this.result=null,this.url=null,this.init()}init(){const{file:e,options:t}=this;if(!(e instanceof Blob))return void this.fail(new Error("The first argument must be a File or Blob object."));const i=e.type;if(!a(i))return void this.fail(new Error("The first argument must be an image File or Blob object."));if(!m||!g)return void this.fail(new Error("The current browser does not support image compression."));if(u||(t.retainExif=!1),!function(){if(void 0!==o)return o;try{const e=document.createElement("canvas");e.width=4,e.height=4;const t=e.getContext("2d"),i=t.createImageData(e.width,e.height);for(let e=0;e<i.data.length;e+=4)i.data[e]=e,i.data[e+1]=1,i.data[e+2]=2,i.data[e+3]=255;t.putImageData(i,0,0);const r=t.getImageData(0,0,e.width,e.height);o=r.data.every((e,t)=>{const i=t%4;return 0===i?e===(255&t):1===i?1===e:2===i?2===e:255===e})}catch{o=!1}return o}()){if(console.warn("Compressor.js Next: Canvas data is unreliable (e.g., due to browser fingerprinting resistance)—compression, resizing, and format conversion are unavailable"),this.canvasFallback=!0,"image/jpeg"!==i||t.retainExif)Promise.resolve().then(()=>{this.aborted||(this.result=e,t.success&&t.success.call(this,e))});else{const r=new g;this.reader=r,r.onload=({target:r})=>{if(this.aborted)return;let a;try{a=f(h(r.result),i)}catch{return void this.fail(new Error("Failed to process the image data."))}const n=new Date,s=new File([a],e.name||"",{type:i,lastModified:n.getTime()});this.result=s,t.success&&t.success.call(this,s)},r.onabort=()=>{this.fail(new Error("Aborted to read the image with FileReader."))},r.onerror=()=>{this.fail(new Error("Failed to read the image with FileReader."))},r.onloadend=()=>{this.reader=null},r.readAsArrayBuffer(e)}return}if("image/jpeg"===i&&t.retainExif){const t=new g;this.reader=t,t.onload=({target:t})=>{this.aborted||(s(t.result),this.exif=function(e){const t=new DataView(e),{byteLength:i}=t,r=[];let a=0;for(;a+3<i;){const e=t.getUint8(a),n=t.getUint8(a+1);if(255===e&&218===n)break;if(255===e&&216===n)a+=2;else{const s=a+t.getUint16(a+2)+2;if(255===e&&225===n)for(let e=a;e<s&&e<i;e+=1)r.push(t.getUint8(e));a=s}}return r}(t.result),this.url=m.createObjectURL(e),this.load({url:this.url}))},t.onabort=()=>{this.fail(new Error("Aborted to read the image with FileReader."))},t.onerror=()=>{this.fail(new Error("Failed to read the image with FileReader."))},t.onloadend=()=>{this.reader=null},t.readAsArrayBuffer(e)}else this.url=m.createObjectURL(e),this.load({url:this.url})}load(e){const{file:i,image:r}=this;r.onload=()=>{this.draw({...e,naturalWidth:r.naturalWidth,naturalHeight:r.naturalHeight})},r.onabort=()=>{this.fail(new Error("Aborted to load the image."))},r.onerror=()=>{this.fail(new Error("Failed to load the image."))},t.navigator&&/(?:iPad|iPhone|iPod).*?AppleWebKit/i.test(t.navigator.userAgent)&&(r.crossOrigin="anonymous"),r.alt=i.name,r.src=e.url}draw({naturalWidth:e,naturalHeight:t}){const{file:r,image:n,options:s}=this,o=document.createElement("canvas"),l=o.getContext("2d"),u=("contain"===s.resize||"cover"===s.resize)&&i(s.width)&&i(s.height);let m=Math.max(s.maxWidth,0)||1/0,w=Math.max(s.maxHeight,0)||1/0,p=Math.max(s.minWidth,0)||0,b=Math.max(s.minHeight,0)||0,y=e/t,{width:U,height:v}=s;u&&(y=U/v),({width:m,height:w}=c({aspectRatio:y,width:m,height:w},"contain")),({width:p,height:b}=c({aspectRatio:y,width:p,height:b},"cover")),u?({width:U,height:v}=c({aspectRatio:y,width:U,height:v},s.resize)):({width:U=e,height:v=t}=c({aspectRatio:y,width:U,height:v})),U=Math.floor(d(Math.min(Math.max(U,p),m))),v=Math.floor(d(Math.min(Math.max(v,b),w)));const x=[];if(u){const{width:i,height:r}=c({aspectRatio:y,width:e,height:t},{contain:"cover",cover:"contain"}[s.resize]),a=(e-i)/2,n=(t-r)/2;x.push(a,n,i,r)}x.push(0,0,U,v),o.width=U,o.height=v,a(s.mimeType)||(s.mimeType=r.type);let E="transparent";!this.mimeTypeSet&&r.size>s.convertSize&&s.convertTypes.indexOf(s.mimeType)>=0&&(s.mimeType="image/jpeg");const F="image/jpeg"===s.mimeType;if(F&&(E="#fff"),l.fillStyle=E,l.fillRect(0,0,U,v),s.beforeDraw&&s.beforeDraw.call(this,l,o),this.aborted)return;if(l.drawImage(n,...x),s.drew&&s.drew.call(this,l,o),this.aborted)return;o.toBlob(i=>{if(!this.aborted){const r=i=>this.done({naturalWidth:e,naturalHeight:t,result:i});if(i&&F&&s.retainExif&&this.exif&&this.exif.length>0){const e=e=>{if(this.aborted)return;const t=function(e,t){const i=new DataView(e),r=new Uint8Array(e);if(255!==i.getUint8(2)||224!==i.getUint8(3))return r;const a=4+i.getUint16(4),n=r.byteLength-a,s=new Uint8Array(2+t.length+n);s[0]=255,s[1]=216;for(let e=0;e<t.length;e+=1)s[2+e]=t[e];return s.set(r.subarray(a),2+t.length),s}(e,this.exif);r(f(t,s.mimeType))};if(i.arrayBuffer)i.arrayBuffer().then(e).catch(()=>{this.aborted||this.fail(new Error("Failed to read the compressed image with `Blob.arrayBuffer()`."))});else{const t=new g;this.reader=t,t.onload=({target:t})=>{e(t.result)},t.onabort=()=>{this.fail(new Error("Aborted to read the compressed image with FileReader."))},t.onerror=()=>{this.fail(new Error("Failed to read the compressed image with FileReader."))},t.onloadend=()=>{this.reader=null},t.readAsArrayBuffer(i)}}else if(i&&F&&!s.retainExif){const e=e=>{this.aborted||r(f(h(e),s.mimeType))};if(i.arrayBuffer)i.arrayBuffer().then(e).catch(()=>{this.aborted||this.fail(new Error("Failed to read the compressed image with `Blob.arrayBuffer()`."))});else{const t=new g;this.reader=t,t.onload=({target:t})=>{e(t.result)},t.onabort=()=>{this.fail(new Error("Aborted to read the compressed image with FileReader."))},t.onerror=()=>{this.fail(new Error("Failed to read the compressed image with FileReader."))},t.onloadend=()=>{this.reader=null},t.readAsArrayBuffer(i)}}else r(i)}},s.mimeType,s.quality)}done({naturalWidth:e,naturalHeight:t,result:i}){const{file:r,options:n}=this;this.revokeUrl();let s=!1;if(i)if(n.strict&&!n.retainExif&&i.size>r.size&&n.mimeType===r.type&&!(n.width>e||n.height>t||n.minWidth>e||n.minHeight>t||n.maxWidth<e||n.maxHeight<t))i=r,s=!0;else{const e=new Date;let t=r.name||"";t&&i.type!==r.type&&(t=t.replace(w,function(e){let t=a(e)?e.slice(6):"";return"jpeg"===t&&(t="jpg"),`.${t}`}(i.type))),i=new File([i],t,{type:i.type,lastModified:e.getTime()})}else console.warn("Compressor.js Next: Canvas produced no output—returning the original image"),i=r;if(s&&"image/jpeg"===r.type)if(r.arrayBuffer)r.arrayBuffer().then(e=>{if(this.aborted)return;const t=f(h(e),r.type),i=new File([t],r.name||"",{type:r.type,lastModified:r.lastModified||Date.now()});this.result=i,n.success&&n.success.call(this,i)}).catch(e=>{this.aborted||(console.warn(`Compressor.js Next: Failed to strip EXIF from original file—returning original with EXIF intact${r.name?` [${r.name}]`:""}${e?.message?`: ${e.message}`:""}`),this.result=r,n.success&&n.success.call(this,r))});else{const e=new g;this.reader=e,e.onload=({target:e})=>{if(this.aborted)return;const t=f(h(e.result),r.type),i=new File([t],r.name||"",{type:r.type,lastModified:r.lastModified||Date.now()});this.result=i,n.success&&n.success.call(this,i)},e.onabort=()=>{this.fail(new Error("Aborted to read the original file with FileReader."))},e.onerror=()=>{this.aborted||(console.warn("Compressor.js Next: Failed to strip EXIF from original file—returning original with EXIF intact"+(r.name?` [${r.name}]`:"")),this.result=r,n.success&&n.success.call(this,r))},e.onloadend=()=>{this.reader=null},e.readAsArrayBuffer(r)}else this.result=i,n.success&&n.success.call(this,i)}fail(e){const{options:t}=this;if(this.revokeUrl(),!t.error)throw e;t.error.call(this,e)}revokeUrl(){m&&this.url&&(m.revokeObjectURL(this.url),this.url=null)}abort(){this.aborted||(this.aborted=!0,this.reader?this.reader.abort():this.image.complete?this.fail(new Error("The compression process has been aborted.")):(this.image.onload=null,this.image.onerror=null,this.image.onabort=null,this.fail(new Error("Aborted to load the image."))))}static setDefaults(t){Object.assign(e,t)}}});
package/package.json CHANGED
@@ -27,7 +27,7 @@
27
27
  "eslint": "^10.0.0",
28
28
  "husky": "^9.1.7",
29
29
  "playwright": "^1.58.2",
30
- "rollup": "^4.57.1",
30
+ "rollup": "^4.59.0",
31
31
  "stylelint": "^17.1.1",
32
32
  "stylelint-config-standard": "^40.0.0",
33
33
  "stylelint-order": "^7.0.1",
@@ -95,5 +95,5 @@
95
95
  "sideEffects": false,
96
96
  "type": "module",
97
97
  "types": "types/index.d.ts",
98
- "version": "2.0.0"
98
+ "version": "2.0.1"
99
99
  }
package/src/index.js CHANGED
@@ -83,21 +83,20 @@ export default class Compressor {
83
83
  reader.onload = ({ target }) => {
84
84
  if (this.aborted) return;
85
85
 
86
- let result;
86
+ let blob;
87
87
 
88
88
  try {
89
- const stripped = stripExif(target.result);
90
-
91
- result = uint8ArrayToBlob(stripped, mimeType);
89
+ blob = uint8ArrayToBlob(stripExif(target.result), mimeType);
92
90
  } catch {
93
91
  this.fail(new Error('Failed to process the image data.'));
94
92
  return;
95
93
  }
96
94
 
97
95
  const date = new Date();
98
-
99
- result.name = file.name;
100
- result.lastModified = date.getTime();
96
+ const result = new File([blob], file.name || '', {
97
+ type: mimeType,
98
+ lastModified: date.getTime(),
99
+ });
101
100
 
102
101
  this.result = result;
103
102
 
@@ -414,17 +413,20 @@ export default class Compressor {
414
413
  strictFallback = true;
415
414
  } else {
416
415
  const date = new Date();
417
-
418
- result.lastModified = date.getTime();
419
- result.name = file.name;
416
+ let name = file.name || '';
420
417
 
421
418
  // Convert the extension to match its type
422
- if (result.name && result.type !== file.type) {
423
- result.name = result.name.replace(
419
+ if (name && result.type !== file.type) {
420
+ name = name.replace(
424
421
  REGEXP_EXTENSION,
425
422
  imageTypeToExtension(result.type),
426
423
  );
427
424
  }
425
+
426
+ result = new File([result], name, {
427
+ type: result.type,
428
+ lastModified: date.getTime(),
429
+ });
428
430
  }
429
431
  } else {
430
432
  // Returns original file if the result is null in some cases
@@ -439,10 +441,12 @@ export default class Compressor {
439
441
  file.arrayBuffer().then((arrayBuffer) => {
440
442
  if (this.aborted) return;
441
443
 
442
- const stripped = uint8ArrayToBlob(stripExif(arrayBuffer), file.type);
444
+ const strippedBlob = uint8ArrayToBlob(stripExif(arrayBuffer), file.type);
445
+ const stripped = new File([strippedBlob], file.name || '', {
446
+ type: file.type,
447
+ lastModified: file.lastModified || Date.now(),
448
+ });
443
449
 
444
- stripped.name = file.name;
445
- stripped.lastModified = file.lastModified;
446
450
  this.result = stripped;
447
451
 
448
452
  if (options.success) {
@@ -468,10 +472,12 @@ export default class Compressor {
468
472
  reader.onload = ({ target }) => {
469
473
  if (this.aborted) return;
470
474
 
471
- const stripped = uint8ArrayToBlob(stripExif(target.result), file.type);
475
+ const strippedBlob = uint8ArrayToBlob(stripExif(target.result), file.type);
476
+ const stripped = new File([strippedBlob], file.name || '', {
477
+ type: file.type,
478
+ lastModified: file.lastModified || Date.now(),
479
+ });
472
480
 
473
- stripped.name = file.name;
474
- stripped.lastModified = file.lastModified;
475
481
  this.result = stripped;
476
482
 
477
483
  if (options.success) {
File without changes