browser-image-compression
Advanced tools
Comparing version 1.0.6 to 1.0.7
@@ -0,1 +1,11 @@ | ||
## v1.0.7 (15 Mar 2020) | ||
* add onProgress function in options for compression progress updates | ||
* allow fileType override | ||
* fix garbage clean canvas for safari | ||
* fix issue in Cordova support | ||
* fix issue in IE browser | ||
* fix other issues | ||
* useWebWorker default set to false | ||
* add ts type file | ||
## v1.0.6 (5 July 2019) | ||
@@ -21,2 +31,2 @@ * fixed: exif orientation do not work in some situations | ||
* added: support web worker | ||
* added: follows image exif orientation | ||
* added: follows image exif orientation |
/** | ||
* Browser Image Compression | ||
* v1.0.6 | ||
* v1.0.7 | ||
* by Donald <donaldcwl@gmail.com> | ||
@@ -8,3 +8,3 @@ * https://github.com/Donaldcwl/browser-image-compression | ||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).imageCompression=n()}(this,function(){"use strict";function _slicedToArray(e,n){return function _arrayWithHoles(e){if(Array.isArray(e))return e}(e)||function _iterableToArrayLimit(e,n){var r=[],t=!0,i=!1,a=void 0;try{for(var o,s=e[Symbol.iterator]();!(t=(o=s.next()).done)&&(r.push(o.value),!n||r.length!==n);t=!0);}catch(e){i=!0,a=e}finally{try{t||null==s.return||s.return()}finally{if(i)throw a}}return r}(e,n)||function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}var e="undefined"!=typeof window&&window.cordova&&window.cordova.require("cordova/modulemapper"),CustomFile=e&&e.getOriginalSymbol(window,"File")||File,CustomFileReader=e&&e.getOriginalSymbol(window,"FileReader")||FileReader;function getDataUrlFromFile(e){return new Promise(function(n,r){var t=new CustomFileReader;t.onload=function(){return n(t.result)},t.onerror=function(e){return r(e)},t.readAsDataURL(e)})}function getFilefromDataUrl(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Date.now();return new Promise(function(t){for(var i=e.split(","),a=i[0].match(/:(.*?);/)[1],o=atob(i[1]),s=o.length,c=new Uint8Array(s);s--;)c[s]=o.charCodeAt(s);var u=new Blob([c],{type:a});u.name=n,u.lastModified=r,t(u)})}function loadImage(e){return new Promise(function(n,r){var t=new Image;t.onload=function(){return n(t)},t.onerror=function(e){return r(e)},t.src=e})}function drawImageInCanvas(e){var n=_slicedToArray(getNewCanvasAndCtx(e.width,e.height),2),r=n[0];return n[1].drawImage(e,0,0,r.width,r.height),r}function drawFileInCanvas(e){return new Promise(function(n,r){var t,i,a=function $Try_1_Post(){try{return i=drawImageInCanvas(t),n([t,i])}catch(e){return r(e)}},o=function $Try_1_Catch(n){try{return getDataUrlFromFile(e).then(function(e){try{return loadImage(e).then(function(e){try{return t=e,a()}catch(e){return r(e)}},r)}catch(e){return r(e)}},r)}catch(e){return r(e)}};try{return createImageBitmap(e).then(function(e){try{return t=e,a()}catch(e){return o()}},o)}catch(e){o()}})}function canvasToFile(e,n,r,t){var i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1;return new Promise(function(a,o){var s;return"function"==typeof OffscreenCanvas&&e instanceof OffscreenCanvas?e.convertToBlob({type:n,quality:i}).then(function(e){try{return(s=e).name=r,s.lastModified=t,$If_4.call(this)}catch(e){return o(e)}}.bind(this),o):getFilefromDataUrl(e.toDataURL(n,i),r,t).then(function(e){try{return s=e,$If_4.call(this)}catch(e){return o(e)}}.bind(this),o);function $If_4(){return a(s)}})}function getExifOrientation(e){return new Promise(function(n,r){var t=new CustomFileReader;t.onload=function(e){var r=new DataView(e.target.result);if(65496!=r.getUint16(0,!1))return n(-2);for(var t=r.byteLength,i=2;i<t;){if(r.getUint16(i+2,!1)<=8)return n(-1);var a=r.getUint16(i,!1);if(i+=2,65505==a){if(1165519206!=r.getUint32(i+=2,!1))return n(-1);var o=18761==r.getUint16(i+=6,!1);i+=r.getUint32(i+4,o);var s=r.getUint16(i,o);i+=2;for(var c=0;c<s;c++)if(274==r.getUint16(i+12*c,o))return n(r.getUint16(i+12*c+8,o))}else{if(65280!=(65280&a))break;i+=r.getUint16(i,!1)}}return n(-1)},t.onerror=function(e){return r(e)},t.readAsArrayBuffer(e)})}function handleMaxWidthOrHeight(e,n){var r,t=e.width,i=e.height,a=n.maxWidthOrHeight,o=e;if(Number.isInteger(a)&&(t>a||i>a)){var s=_slicedToArray(getNewCanvasAndCtx(t,i),2);o=s[0],r=s[1],t>i?(o.width=a,o.height=i/t*a):(o.width=t/i*a,o.height=a),r.drawImage(e,0,0,o.width,o.height)}return o}function followExifOrientation(e,n){var r=e.width,t=e.height,i=_slicedToArray(getNewCanvasAndCtx(r,t),2),a=i[0],o=i[1];switch(4<n&&n<9?(a.width=t,a.height=r):(a.width=r,a.height=t),n){case 2:o.transform(-1,0,0,1,r,0);break;case 3:o.transform(-1,0,0,-1,r,t);break;case 4:o.transform(1,0,0,-1,0,t);break;case 5:o.transform(0,1,1,0,0,0);break;case 6:o.transform(0,1,-1,0,t,0);break;case 7:o.transform(0,-1,-1,0,t,r);break;case 8:o.transform(0,-1,1,0,0,r)}return o.drawImage(e,0,0,r,t),a}function getNewCanvasAndCtx(e,n){var r,t;try{t=(r=new OffscreenCanvas(e,n)).getContext("2d")}catch(e){t=(r=document.createElement("canvas")).getContext("2d")}return r.width=e,r.height=n,[r,t]}function compress(e,n){return new Promise(function(r,t){var i,a,o,s,c,u;return i=n.maxIteration||10,a=1024*n.maxSizeMB*1024,drawFileInCanvas(e).then(function(f){try{var m=_slicedToArray(f,2);return m[0],o=handleMaxWidthOrHeight(o=m[1],n),new Promise(function(r,t){var i;if(!(i=n.exifOrientation))return getExifOrientation(e).then(function(e){try{return i=e,$If_2.call(this)}catch(e){return t(e)}}.bind(this),t);function $If_2(){return r(i)}return $If_2.call(this)}).then(function(f){try{return n.exifOrientation=f,o=followExifOrientation(o,n.exifOrientation),s=1,canvasToFile(o,e.type,e.name,e.lastModified,s).then(function(n){try{var f,m=function $Loop_3(){if(i--&&u.size>a){var n,r,c,f=_slicedToArray(getNewCanvasAndCtx(n=.9*o.width,r=.9*o.height),2);return c=f[0],f[1].drawImage(o,0,0,n,r),"image/jpeg"===e.type&&(s*=.9),canvasToFile(c,e.type,e.name,e.lastModified,s).then(function(e){try{return u=e,o=c,$Loop_3}catch(e){return t(e)}},t)}return[1]},l=function $Loop_3_exit(){return r(u)};return(c=n).size<=a?r(c):(u=c,(f=function(e){for(;e;){if(e.then)return void e.then(f,t);try{if(e.pop){if(e.length)return e.pop()?l.call(this):e;e=m}else e=e.call(this)}catch(e){return t(e)}}}.bind(this))(m))}catch(e){return t(e)}}.bind(this),t)}catch(e){return t(e)}}.bind(this),t)}catch(e){return t(e)}}.bind(this),t)})}var n,r=0;var t=function createWorker(e){return new Worker(URL.createObjectURL(new Blob(["(".concat(e,")()")])))}(function(){var e=!1;self.addEventListener("message",function(n){return new Promise(function(r,t){var i,a,o,s,c=n.data;i=c.file,a=c.id,o=c.imageCompressionLibUrl,s=c.options;var u=function $Try_1_Post(){try{return r()}catch(e){return t(e)}},f=function $Try_1_Catch(e){try{return self.postMessage({error:e.message+"\n"+e.stack,id:a}),u()}catch(e){return t(e)}};try{var m;return e||(importScripts(o),e=!0),imageCompression(i,s).then(function(e){try{return m=e,self.postMessage({file:m,id:a}),u()}catch(e){return f(e)}},f)}catch(e){f(e)}})})});function compressOnWebWorker(e,i){return new Promise(function(a,o){return new Promise(function(s,c){n||(n=function createSourceObject(e){return URL.createObjectURL(new Blob([e],{type:"application/javascript"}))}("\n function imageCompression (){return (".concat(imageCompression,").apply(null, arguments)}\n\n imageCompression.getDataUrlFromFile = ").concat(imageCompression.getDataUrlFromFile,"\n imageCompression.getFilefromDataUrl = ").concat(imageCompression.getFilefromDataUrl,"\n imageCompression.loadImage = ").concat(imageCompression.loadImage,"\n imageCompression.drawImageInCanvas = ").concat(imageCompression.drawImageInCanvas,"\n imageCompression.drawFileInCanvas = ").concat(imageCompression.drawFileInCanvas,"\n imageCompression.canvasToFile = ").concat(imageCompression.canvasToFile,"\n imageCompression.getExifOrientation = ").concat(imageCompression.getExifOrientation,"\n imageCompression.handleMaxWidthOrHeight = ").concat(imageCompression.handleMaxWidthOrHeight,"\n imageCompression.followExifOrientation = ").concat(imageCompression.followExifOrientation,"\n\n getDataUrlFromFile = imageCompression.getDataUrlFromFile\n getFilefromDataUrl = imageCompression.getFilefromDataUrl\n loadImage = imageCompression.loadImage\n drawImageInCanvas = imageCompression.drawImageInCanvas\n drawFileInCanvas = imageCompression.drawFileInCanvas\n canvasToFile = imageCompression.canvasToFile\n getExifOrientation = imageCompression.getExifOrientation\n handleMaxWidthOrHeight = imageCompression.handleMaxWidthOrHeight\n followExifOrientation = imageCompression.followExifOrientation\n\n getNewCanvasAndCtx = ").concat(getNewCanvasAndCtx,"\n \n CustomFileReader = FileReader\n \n CustomFile = File\n \n function _slicedToArray(arr, n) { return arr }\n\n function compress (){return (").concat(compress,").apply(null, arguments)}\n ")));var u=r++;return t.addEventListener("message",function handler(e){e.data.id===u&&(t.removeEventListener("message",handler),e.data.error&&o(new Error(e.data.error)),a(e.data.file))}),t.postMessage({file:e,id:u,imageCompressionLibUrl:n,options:i}),s()})})}function imageCompression(e,n){return new Promise(function(r,t){var i,a;if(n.maxSizeMB=n.maxSizeMB||Number.POSITIVE_INFINITY,n.useWebWorker="boolean"!=typeof n.useWebWorker||n.useWebWorker,!(e instanceof Blob||e instanceof CustomFile))return t(new Error("The file given is not an instance of Blob or File"));if(!/^image/.test(e.type))return t(new Error("The file given is not an image"));if(a="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope,!n.useWebWorker||"function"!=typeof Worker||a)return compress(e,n).then(function(e){try{return i=e,$If_3.call(this)}catch(e){return t(e)}}.bind(this),t);var o=function(){try{return $If_3.call(this)}catch(e){return t(e)}}.bind(this),s=function $Try_1_Catch(r){try{return console.warn("Run compression in web worker failed:",r,", fall back to main thread"),compress(e,n).then(function(e){try{return i=e,o()}catch(e){return t(e)}},t)}catch(e){return t(e)}};try{return compressOnWebWorker(e,n).then(function(e){try{return i=e,o()}catch(e){return s(e)}},s)}catch(e){s(e)}function $If_3(){try{i.name=e.name,i.lastModified=e.lastModified}catch(e){}return r(i)}})}return imageCompression.getDataUrlFromFile=getDataUrlFromFile,imageCompression.getFilefromDataUrl=getFilefromDataUrl,imageCompression.loadImage=loadImage,imageCompression.drawImageInCanvas=drawImageInCanvas,imageCompression.drawFileInCanvas=drawFileInCanvas,imageCompression.canvasToFile=canvasToFile,imageCompression.getExifOrientation=getExifOrientation,imageCompression.handleMaxWidthOrHeight=handleMaxWidthOrHeight,imageCompression.followExifOrientation=followExifOrientation,imageCompression}); | ||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).imageCompression=n()}(this,(function(){"use strict";function _defineProperty(e,n,r){return n in e?Object.defineProperty(e,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[n]=r,e}function ownKeys(e,n){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);n&&(t=t.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),r.push.apply(r,t)}return r}function _objectSpread2(e){for(var n=1;n<arguments.length;n++){var r=null!=arguments[n]?arguments[n]:{};n%2?ownKeys(Object(r),!0).forEach((function(n){_defineProperty(e,n,r[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):ownKeys(Object(r)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(r,n))}))}return e}function _slicedToArray(e,n){return function _arrayWithHoles(e){if(Array.isArray(e))return e}(e)||function _iterableToArrayLimit(e,n){if(!(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e)))return;var r=[],t=!0,o=!1,i=void 0;try{for(var a,s=e[Symbol.iterator]();!(t=(a=s.next()).done)&&(r.push(a.value),!n||r.length!==n);t=!0);}catch(e){o=!0,i=e}finally{try{t||null==s.return||s.return()}finally{if(o)throw i}}return r}(e,n)||function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}var e="undefined"!=typeof window&&window.cordova&&window.cordova.require&&window.cordova.require("cordova/modulemapper"),CustomFile=e&&e.getOriginalSymbol(window,"File")||File,CustomFileReader=e&&e.getOriginalSymbol(window,"FileReader")||FileReader;function getDataUrlFromFile(e){return new Promise((function(n,r){var t=new CustomFileReader;t.onload=function(){return n(t.result)},t.onerror=function(e){return r(e)},t.readAsDataURL(e)}))}function getFilefromDataUrl(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Date.now();return new Promise((function(t){for(var o=e.split(","),i=o[0].match(/:(.*?);/)[1],a=atob(o[1]),s=a.length,c=new Uint8Array(s);s--;)c[s]=a.charCodeAt(s);var l=new Blob([c],{type:i});l.name=n,l.lastModified=r,t(l)}))}function loadImage(e){return new Promise((function(n,r){var t=new Image;t.onload=function(){return n(t)},t.onerror=function(e){return r(e)},t.src=e}))}function drawImageInCanvas(e){var n=_slicedToArray(getNewCanvasAndCtx(e.width,e.height),2),r=n[0];return n[1].drawImage(e,0,0,r.width,r.height),r}function drawFileInCanvas(e){return new Promise((function(n,r){var t,o,i=function $Try_1_Post(){try{return o=drawImageInCanvas(t),n([t,o])}catch(e){return r(e)}},a=function $Try_1_Catch(n){try{return getDataUrlFromFile(e).then((function(e){try{return loadImage(e).then((function(e){try{return t=e,i()}catch(e){return r(e)}}),r)}catch(e){return r(e)}}),r)}catch(e){return r(e)}};try{return createImageBitmap(e).then((function(e){try{return t=e,i()}catch(e){return a()}}),a)}catch(e){a()}}))}function canvasToFile(e,n,r,t){var o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1;return new Promise((function(i,a){var s;return"function"==typeof OffscreenCanvas&&e instanceof OffscreenCanvas?e.convertToBlob({type:n,quality:o}).then(function(e){try{return(s=e).name=r,s.lastModified=t,$If_4.call(this)}catch(e){return a(e)}}.bind(this),a):getFilefromDataUrl(e.toDataURL(n,o),r,t).then(function(e){try{return s=e,$If_4.call(this)}catch(e){return a(e)}}.bind(this),a);function $If_4(){return i(s)}}))}function getExifOrientation(e){return new Promise((function(n,r){var t=new CustomFileReader;t.onload=function(e){var r=new DataView(e.target.result);if(65496!=r.getUint16(0,!1))return n(-2);for(var t=r.byteLength,o=2;o<t;){if(r.getUint16(o+2,!1)<=8)return n(-1);var i=r.getUint16(o,!1);if(o+=2,65505==i){if(1165519206!=r.getUint32(o+=2,!1))return n(-1);var a=18761==r.getUint16(o+=6,!1);o+=r.getUint32(o+4,a);var s=r.getUint16(o,a);o+=2;for(var c=0;c<s;c++)if(274==r.getUint16(o+12*c,a))return n(r.getUint16(o+12*c+8,a))}else{if(65280!=(65280&i))break;o+=r.getUint16(o,!1)}}return n(-1)},t.onerror=function(e){return r(e)},t.readAsArrayBuffer(e)}))}function handleMaxWidthOrHeight(e,n){var r,t=e.width,o=e.height,i=n.maxWidthOrHeight,a=e;if(Number.isInteger(i)&&(t>i||o>i)){var s=_slicedToArray(getNewCanvasAndCtx(t,o),2);a=s[0],r=s[1],t>o?(a.width=i,a.height=o/t*i):(a.width=t/o*i,a.height=i),r.drawImage(e,0,0,a.width,a.height),cleanupCanvasMemory(e)}return a}function followExifOrientation(e,n){var r=e.width,t=e.height,o=_slicedToArray(getNewCanvasAndCtx(r,t),2),i=o[0],a=o[1];switch(4<n&&n<9?(i.width=t,i.height=r):(i.width=r,i.height=t),n){case 2:a.transform(-1,0,0,1,r,0);break;case 3:a.transform(-1,0,0,-1,r,t);break;case 4:a.transform(1,0,0,-1,0,t);break;case 5:a.transform(0,1,1,0,0,0);break;case 6:a.transform(0,1,-1,0,t,0);break;case 7:a.transform(0,-1,-1,0,t,r);break;case 8:a.transform(0,-1,1,0,0,r)}return a.drawImage(e,0,0,r,t),cleanupCanvasMemory(e),i}function getNewCanvasAndCtx(e,n){var r,t;try{if(null===(t=(r=new OffscreenCanvas(e,n)).getContext("2d")))throw new Error("getContext of OffscreenCanvas returns null")}catch(e){t=(r=document.createElement("canvas")).getContext("2d")}return r.width=e,r.height=n,[r,t]}function cleanupCanvasMemory(e){e.width=0,e.height=0}function compress(e,n){return new Promise((function(r,t){var o,i,a,s,c,l,u,f,m,g,p,d,h;function incProgress(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:5;o+=e,"function"==typeof n.onProgress&&n.onProgress(Math.min(o,100))}function setProgress(e){o=Math.min(Math.max(e,o),100),"function"==typeof n.onProgress&&n.onProgress(o)}return o=0,i=n.maxIteration||10,a=1024*n.maxSizeMB*1024,incProgress(),drawFileInCanvas(e).then(function(o){try{var y=_slicedToArray(o,2);return y[0],s=y[1],incProgress(),c=handleMaxWidthOrHeight(s,n),incProgress(),new Promise((function(r,t){var o;if(!(o=n.exifOrientation))return getExifOrientation(e).then(function(e){try{return o=e,$If_2.call(this)}catch(e){return t(e)}}.bind(this),t);function $If_2(){return r(o)}return $If_2.call(this)})).then(function(o){try{return n.exifOrientation=o,incProgress(),l=followExifOrientation(c,n.exifOrientation),incProgress(),u=1,canvasToFile(l,n.fileType||e.type,e.name,e.lastModified,u).then(function(o){try{{if(f=o,incProgress(),f.size<=a)return setProgress(100),r(f);var y;function $Loop_3(){if(i--&&g>a){var r,o,s=_slicedToArray(getNewCanvasAndCtx(r=.9*h.width,o=.9*h.height),2);return d=s[0],s[1].drawImage(h,0,0,r,o),"image/jpeg"===e.type&&(u*=.9),canvasToFile(d,n.fileType||e.type,e.name,e.lastModified,u).then((function(e){try{return p=e,cleanupCanvasMemory(h),h=d,g=p.size,setProgress(Math.min(99,Math.floor((m-g)/(m-a)*100))),$Loop_3}catch(e){return t(e)}}),t)}return[1]}return m=f.size,g=m,h=l,(y=function(e){for(;e;){if(e.then)return void e.then(y,t);try{if(e.pop){if(e.length)return e.pop()?$Loop_3_exit.call(this):e;e=$Loop_3}else e=e.call(this)}catch(e){return t(e)}}}.bind(this))($Loop_3);function $Loop_3_exit(){return cleanupCanvasMemory(h),cleanupCanvasMemory(d),cleanupCanvasMemory(c),cleanupCanvasMemory(l),cleanupCanvasMemory(s),setProgress(100),r(p)}}}catch(e){return t(e)}}.bind(this),t)}catch(e){return t(e)}}.bind(this),t)}catch(e){return t(e)}}.bind(this),t)}))}Number.isInteger=Number.isInteger||function(e){return"number"==typeof e&&isFinite(e)&&Math.floor(e)===e};var n,r,t=0;function generateLib(){return function createSourceObject(e){return URL.createObjectURL(new Blob([e],{type:"application/javascript"}))}("\n function imageCompression (){return (".concat(imageCompression,").apply(null, arguments)}\n\n imageCompression.getDataUrlFromFile = ").concat(imageCompression.getDataUrlFromFile,"\n imageCompression.getFilefromDataUrl = ").concat(imageCompression.getFilefromDataUrl,"\n imageCompression.loadImage = ").concat(imageCompression.loadImage,"\n imageCompression.drawImageInCanvas = ").concat(imageCompression.drawImageInCanvas,"\n imageCompression.drawFileInCanvas = ").concat(imageCompression.drawFileInCanvas,"\n imageCompression.canvasToFile = ").concat(imageCompression.canvasToFile,"\n imageCompression.getExifOrientation = ").concat(imageCompression.getExifOrientation,"\n imageCompression.handleMaxWidthOrHeight = ").concat(imageCompression.handleMaxWidthOrHeight,"\n imageCompression.followExifOrientation = ").concat(imageCompression.followExifOrientation,"\n imageCompression.cleanupMemory = ").concat(imageCompression.cleanupMemory,"\n\n getDataUrlFromFile = imageCompression.getDataUrlFromFile\n getFilefromDataUrl = imageCompression.getFilefromDataUrl\n loadImage = imageCompression.loadImage\n drawImageInCanvas = imageCompression.drawImageInCanvas\n drawFileInCanvas = imageCompression.drawFileInCanvas\n canvasToFile = imageCompression.canvasToFile\n getExifOrientation = imageCompression.getExifOrientation\n handleMaxWidthOrHeight = imageCompression.handleMaxWidthOrHeight\n followExifOrientation = imageCompression.followExifOrientation\n cleanupMemory = imageCompression.cleanupMemory\n\n getNewCanvasAndCtx = ").concat(getNewCanvasAndCtx,"\n \n CustomFileReader = FileReader\n \n CustomFile = File\n \n function _slicedToArray(arr, n) { return arr }\n \n function _typeof(a) { return typeof a }\n\n function compress (){return (").concat(compress,").apply(null, arguments)}\n "))}function generateWorkerScript(){return function createWorker(e){return"function"==typeof e&&(e="(".concat(f,")()")),new Worker(URL.createObjectURL(new Blob([e])))}("\n let scriptImported = false\n self.addEventListener('message', async (e) => {\n const { file, id, imageCompressionLibUrl, options } = e.data\n options.onProgress = (progress) => self.postMessage({ progress, id })\n try {\n if (!scriptImported) {\n // console.log('[worker] importScripts', imageCompressionLibUrl)\n self.importScripts(imageCompressionLibUrl)\n scriptImported = true\n }\n // console.log('[worker] self', self)\n const compressedFile = await imageCompression(file, options)\n self.postMessage({ file: compressedFile, id })\n } catch (e) {\n // console.error('[worker] error', e)\n self.postMessage({ error: e.message + '\\n' + e.stack, id })\n }\n })\n ")}function imageCompression(e,o){return new Promise((function(i,a){var s,c,l;if(o.maxSizeMB=o.maxSizeMB||Number.POSITIVE_INFINITY,c="boolean"==typeof o.useWebWorker&&o.useWebWorker,delete o.useWebWorker,!(e instanceof Blob||e instanceof CustomFile))return a(new Error("The file given is not an instance of Blob or File"));if(!/^image/.test(e.type))return a(new Error("The file given is not an image"));if(l="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope,!c||"function"!=typeof Worker||l)return compress(e,o).then(function(e){try{return s=e,$If_3.call(this)}catch(e){return a(e)}}.bind(this),a);var u=function(){try{return $If_3.call(this)}catch(e){return a(e)}}.bind(this),f=function $Try_1_Catch(n){try{return compress(e,o).then((function(e){try{return s=e,u()}catch(e){return a(e)}}),a)}catch(e){return a(e)}};try{return function compressOnWebWorker(e,o){return new Promise((function(i,a){return new Promise((function(s,c){var l=t++;return n||(n=generateLib()),r||(r=generateWorkerScript()),r.addEventListener("message",(function handler(e){if(e.data.id===l){if(void 0!==e.data.progress&&e.data.progress<100)return void o.onProgress(e.data.progress);r.removeEventListener("message",handler),e.data.error&&a(new Error(e.data.error)),i(e.data.file)}})),r.postMessage({file:e,id:l,imageCompressionLibUrl:n,options:_objectSpread2({},o,{onProgress:void 0})}),s()}))}))}(e,o).then((function(e){try{return s=e,u()}catch(e){return f()}}),f)}catch(e){f()}function $If_3(){try{s.name=e.name,s.lastModified=e.lastModified}catch(e){}return i(s)}}))}return imageCompression.getDataUrlFromFile=getDataUrlFromFile,imageCompression.getFilefromDataUrl=getFilefromDataUrl,imageCompression.loadImage=loadImage,imageCompression.drawImageInCanvas=drawImageInCanvas,imageCompression.drawFileInCanvas=drawFileInCanvas,imageCompression.canvasToFile=canvasToFile,imageCompression.getExifOrientation=getExifOrientation,imageCompression.handleMaxWidthOrHeight=handleMaxWidthOrHeight,imageCompression.followExifOrientation=followExifOrientation,imageCompression.cleanupMemory=cleanupCanvasMemory,imageCompression.version="1.0.7",imageCompression})); | ||
//# sourceMappingURL=browser-image-compression.js.map |
@@ -1,2 +0,10 @@ | ||
import { canvasToFile, drawFileInCanvas, followExifOrientation, getExifOrientation, handleMaxWidthOrHeight, getNewCanvasAndCtx } from './utils' | ||
import { | ||
canvasToFile, | ||
cleanupCanvasMemory, | ||
drawFileInCanvas, | ||
followExifOrientation, | ||
getExifOrientation, | ||
getNewCanvasAndCtx, | ||
handleMaxWidthOrHeight | ||
} from './utils' | ||
@@ -7,10 +15,28 @@ /** | ||
* @param {File} file | ||
* @param {Object} options - { maxSizeMB=Number.POSITIVE_INFINITY, maxWidthOrHeight, useWebWorker=true, maxIteration = 10, exifOrientation } | ||
* @param {Object} options - { maxSizeMB=Number.POSITIVE_INFINITY, maxWidthOrHeight, useWebWorker=false, maxIteration = 10, exifOrientation, fileType } | ||
* @param {number} [options.maxSizeMB=Number.POSITIVE_INFINITY] | ||
* @param {number} [options.maxWidthOrHeight=undefined] * @param {number} [options.maxWidthOrHeight=undefined] | ||
* @param {number} [options.maxWidthOrHeight=undefined] | ||
* @param {number} [options.maxIteration=10] | ||
* @param {number} [options.exifOrientation=] - default to be the exif orientation from the image file | ||
* @param {number} [options.exifOrientation] - default to be the exif orientation from the image file | ||
* @param {Function} [options.onProgress] - a function takes one progress argument (progress from 0 to 100) | ||
* @param {string} [options.fileType] - default to be the original mime type from the image file | ||
* @returns {Promise<File | Blob>} | ||
*/ | ||
export default async function compress (file, options) { | ||
let progress = 0 | ||
function incProgress (inc = 5) { | ||
progress += inc | ||
if (typeof options.onProgress === 'function') { | ||
options.onProgress(Math.min(progress, 100)) | ||
} | ||
} | ||
function setProgress (p) { | ||
progress = Math.min(Math.max(p, progress), 100) | ||
if (typeof options.onProgress === 'function') { | ||
options.onProgress(progress) | ||
} | ||
} | ||
let remainingTrials = options.maxIteration || 10 | ||
@@ -20,26 +46,40 @@ | ||
incProgress() | ||
// drawFileInCanvas | ||
let [img, canvas] = await drawFileInCanvas(file) | ||
let [img, origCanvas] = await drawFileInCanvas(file) | ||
incProgress() | ||
// handleMaxWidthOrHeight | ||
canvas = handleMaxWidthOrHeight(canvas, options) | ||
const maxWidthOrHeightFixedCanvas = handleMaxWidthOrHeight(origCanvas, options) | ||
incProgress() | ||
// exifOrientation | ||
options.exifOrientation = options.exifOrientation || await getExifOrientation(file) | ||
canvas = followExifOrientation(canvas, options.exifOrientation) | ||
incProgress() | ||
const orientationFixedCanvas = followExifOrientation(maxWidthOrHeightFixedCanvas, options.exifOrientation) | ||
incProgress() | ||
let quality = 1 | ||
let tempFile = await canvasToFile(canvas, file.type, file.name, file.lastModified, quality) | ||
let tempFile = await canvasToFile(orientationFixedCanvas, options.fileType || file.type, file.name, file.lastModified, quality) | ||
incProgress() | ||
// check if we need to compress or resize | ||
if (tempFile.size <= maxSizeByte) { | ||
// no need to compress | ||
setProgress(100) | ||
return tempFile | ||
} | ||
let compressedFile = tempFile | ||
while (remainingTrials-- && compressedFile.size > maxSizeByte) { | ||
const originalSize = tempFile.size | ||
let currentSize = originalSize | ||
let compressedFile | ||
let newCanvas, ctx | ||
let canvas = orientationFixedCanvas | ||
while (remainingTrials-- && currentSize > maxSizeByte) { | ||
const newWidth = canvas.width * 0.9 | ||
const newHeight = canvas.height * 0.9 | ||
const [newCanvas, ctx] = getNewCanvasAndCtx(newWidth, newHeight) | ||
const newHeight = canvas.height * 0.9; | ||
[newCanvas, ctx] = getNewCanvasAndCtx(newWidth, newHeight) | ||
@@ -51,8 +91,22 @@ ctx.drawImage(canvas, 0, 0, newWidth, newHeight) | ||
} | ||
compressedFile = await canvasToFile(newCanvas, file.type, file.name, file.lastModified, quality) | ||
compressedFile = await canvasToFile(newCanvas, options.fileType || file.type, file.name, file.lastModified, quality) | ||
cleanupCanvasMemory(canvas) | ||
canvas = newCanvas | ||
currentSize = compressedFile.size | ||
setProgress(Math.min(99, Math.floor((originalSize - currentSize) / (originalSize - maxSizeByte) * 100))) | ||
} | ||
// garbage clean canvas for safari | ||
// ref: https://bugs.webkit.org/show_bug.cgi?id=195325 | ||
cleanupCanvasMemory(canvas) | ||
cleanupCanvasMemory(newCanvas) | ||
cleanupCanvasMemory(maxWidthOrHeightFixedCanvas) | ||
cleanupCanvasMemory(orientationFixedCanvas) | ||
cleanupCanvasMemory(origCanvas) | ||
setProgress(100) | ||
return compressedFile | ||
} | ||
} |
@@ -12,3 +12,4 @@ import compress from './image-compression' | ||
followExifOrientation, | ||
CustomFile | ||
CustomFile, | ||
cleanupCanvasMemory | ||
} from './utils' | ||
@@ -21,8 +22,10 @@ import { compressOnWebWorker } from './web-worker' | ||
* @param {File} file | ||
* @param {Object} options - { maxSizeMB=Number.POSITIVE_INFINITY, maxWidthOrHeight, useWebWorker=true, maxIteration = 10, exifOrientation } | ||
* @param {Object} options - { maxSizeMB=Number.POSITIVE_INFINITY, maxWidthOrHeight, useWebWorker=false, maxIteration = 10, exifOrientation, fileType } | ||
* @param {number} [options.maxSizeMB=Number.POSITIVE_INFINITY] | ||
* @param {number} [options.maxWidthOrHeight=undefined] * @param {number} [options.maxWidthOrHeight=undefined] | ||
* @param {boolean} [options.useWebWorker=true] | ||
* @param {number} [options.maxWidthOrHeight=undefined] | ||
* @param {boolean} [options.useWebWorker=false] | ||
* @param {number} [options.maxIteration=10] | ||
* @param {number} [options.exifOrientation=] - default to be the exif orientation from the image file | ||
* @param {number} [options.exifOrientation] - default to be the exif orientation from the image file | ||
* @param {Function} [options.onProgress] - a function takes one progress argument (progress from 0 to 100) | ||
* @param {string} [options.fileType] - default to be the original mime type from the image file | ||
* @returns {Promise<File | Blob>} | ||
@@ -35,3 +38,4 @@ */ | ||
options.maxSizeMB = options.maxSizeMB || Number.POSITIVE_INFINITY | ||
options.useWebWorker = typeof options.useWebWorker === 'boolean' ? options.useWebWorker : true | ||
const useWebWorker = typeof options.useWebWorker === 'boolean' ? options.useWebWorker : false | ||
delete options.useWebWorker | ||
@@ -47,3 +51,3 @@ if (!(file instanceof Blob || file instanceof CustomFile)) { | ||
// if (inWebWorker) { | ||
// if ((useWebWorker && typeof Worker === 'function') || inWebWorker) { | ||
// console.log('run compression in web worker') | ||
@@ -54,11 +58,14 @@ // } else { | ||
if (options.useWebWorker && typeof Worker === 'function' && !inWebWorker) { | ||
if (useWebWorker && typeof Worker === 'function' && !inWebWorker) { | ||
try { | ||
// console.log(1) | ||
// "compressOnWebWorker" is kind of like a recursion to call "imageCompression" again inside web worker | ||
compressedFile = await compressOnWebWorker(file, options) | ||
} catch (e) { | ||
console.warn('Run compression in web worker failed:', e, ', fall back to main thread') | ||
// console.warn('Run compression in web worker failed:', e, ', fall back to main thread') | ||
// console.log(1.5) | ||
compressedFile = await compress(file, options) | ||
} | ||
} else { | ||
// console.log(2) | ||
compressedFile = await compress(file, options) | ||
@@ -84,3 +91,5 @@ } | ||
imageCompression.followExifOrientation = followExifOrientation | ||
imageCompression.cleanupMemory = cleanupCanvasMemory | ||
imageCompression.version = '1.0.7' | ||
export default imageCompression |
// add support for cordova-plugin-file | ||
const moduleMapper = typeof window !== 'undefined' && window.cordova && window.cordova.require('cordova/modulemapper'); | ||
export const CustomFile = (moduleMapper && moduleMapper.getOriginalSymbol(window, 'File')) || File; | ||
export const CustomFileReader = (moduleMapper && moduleMapper.getOriginalSymbol(window, 'FileReader')) || FileReader; | ||
const moduleMapper = typeof window !== 'undefined' && window.cordova && window.cordova.require && window.cordova.require('cordova/modulemapper') | ||
export const CustomFile = (moduleMapper && moduleMapper.getOriginalSymbol(window, 'File')) || File | ||
export const CustomFileReader = (moduleMapper && moduleMapper.getOriginalSymbol(window, 'FileReader')) || FileReader | ||
/** | ||
@@ -201,2 +202,4 @@ * getDataUrlFromFile | ||
ctx.drawImage(canvas, 0, 0, newCanvas.width, newCanvas.height) | ||
cleanupCanvasMemory(canvas) | ||
} | ||
@@ -244,2 +247,4 @@ | ||
cleanupCanvasMemory(canvas) | ||
return newCanvas | ||
@@ -260,2 +265,5 @@ } | ||
ctx = canvas.getContext('2d') | ||
if (ctx === null) { | ||
throw new Error("getContext of OffscreenCanvas returns null") | ||
} | ||
} catch (e) { | ||
@@ -268,2 +276,19 @@ canvas = document.createElement('canvas') | ||
return [canvas, ctx] | ||
} | ||
} | ||
/** | ||
* clear Canvas memory | ||
* @param canvas | ||
* @returns null | ||
*/ | ||
export function cleanupCanvasMemory (canvas) { | ||
canvas.width = 0 | ||
canvas.height = 0 | ||
} | ||
// Polyfill for Number.isInteger | ||
Number.isInteger = Number.isInteger || function (value) { | ||
return typeof value === 'number' && | ||
isFinite(value) && | ||
Math.floor(value) === value | ||
} |
@@ -1,2 +0,2 @@ | ||
import imageCompression from './index' | ||
import lib from './index' | ||
import compress from './image-compression' | ||
@@ -7,27 +7,11 @@ import { getNewCanvasAndCtx } from './utils' | ||
let imageCompressionLibUrl | ||
let worker | ||
function createWorker (f) { | ||
return new Worker(URL.createObjectURL(new Blob([`(${f})()`]))) | ||
function createWorker (script) { | ||
if (typeof script === 'function') { | ||
script = `(${f})()` | ||
} | ||
return new Worker(URL.createObjectURL(new Blob([script]))) | ||
} | ||
const worker = createWorker(() => { | ||
let scriptImported = false | ||
self.addEventListener('message', async (e) => { | ||
const { file, id, imageCompressionLibUrl, options } = e.data | ||
try { | ||
if (!scriptImported) { | ||
// console.log('[worker] importScripts', imageCompressionLibUrl) | ||
importScripts(imageCompressionLibUrl) | ||
scriptImported = true | ||
} | ||
// console.log('[worker] self', self) | ||
const compressedFile = await imageCompression(file, options) | ||
self.postMessage({ file: compressedFile, id }) | ||
} catch (e) { | ||
// console.error('[worker] error', e) | ||
self.postMessage({ error: e.message + '\n' + e.stack, id }) | ||
} | ||
}) | ||
}) | ||
function createSourceObject (str) { | ||
@@ -37,17 +21,17 @@ return URL.createObjectURL(new Blob([str], { type: 'application/javascript' })) | ||
export function compressOnWebWorker (file, options) { | ||
return new Promise(async (resolve, reject) => { | ||
if (!imageCompressionLibUrl) { | ||
imageCompressionLibUrl = createSourceObject(` | ||
function imageCompression (){return (${imageCompression}).apply(null, arguments)} | ||
function generateLib () { | ||
// prepare the lib to be used inside WebWorker | ||
return createSourceObject(` | ||
function imageCompression (){return (${lib}).apply(null, arguments)} | ||
imageCompression.getDataUrlFromFile = ${imageCompression.getDataUrlFromFile} | ||
imageCompression.getFilefromDataUrl = ${imageCompression.getFilefromDataUrl} | ||
imageCompression.loadImage = ${imageCompression.loadImage} | ||
imageCompression.drawImageInCanvas = ${imageCompression.drawImageInCanvas} | ||
imageCompression.drawFileInCanvas = ${imageCompression.drawFileInCanvas} | ||
imageCompression.canvasToFile = ${imageCompression.canvasToFile} | ||
imageCompression.getExifOrientation = ${imageCompression.getExifOrientation} | ||
imageCompression.handleMaxWidthOrHeight = ${imageCompression.handleMaxWidthOrHeight} | ||
imageCompression.followExifOrientation = ${imageCompression.followExifOrientation} | ||
imageCompression.getDataUrlFromFile = ${lib.getDataUrlFromFile} | ||
imageCompression.getFilefromDataUrl = ${lib.getFilefromDataUrl} | ||
imageCompression.loadImage = ${lib.loadImage} | ||
imageCompression.drawImageInCanvas = ${lib.drawImageInCanvas} | ||
imageCompression.drawFileInCanvas = ${lib.drawFileInCanvas} | ||
imageCompression.canvasToFile = ${lib.canvasToFile} | ||
imageCompression.getExifOrientation = ${lib.getExifOrientation} | ||
imageCompression.handleMaxWidthOrHeight = ${lib.handleMaxWidthOrHeight} | ||
imageCompression.followExifOrientation = ${lib.followExifOrientation} | ||
imageCompression.cleanupMemory = ${lib.cleanupMemory} | ||
@@ -63,2 +47,3 @@ getDataUrlFromFile = imageCompression.getDataUrlFromFile | ||
followExifOrientation = imageCompression.followExifOrientation | ||
cleanupMemory = imageCompression.cleanupMemory | ||
@@ -72,10 +57,51 @@ getNewCanvasAndCtx = ${getNewCanvasAndCtx} | ||
function _slicedToArray(arr, n) { return arr } | ||
function _typeof(a) { return typeof a } | ||
function compress (){return (${compress}).apply(null, arguments)} | ||
`) | ||
} | ||
} | ||
function generateWorkerScript () { | ||
// code to be run in the WebWorker | ||
return createWorker(` | ||
let scriptImported = false | ||
self.addEventListener('message', async (e) => { | ||
const { file, id, imageCompressionLibUrl, options } = e.data | ||
options.onProgress = (progress) => self.postMessage({ progress, id }) | ||
try { | ||
if (!scriptImported) { | ||
// console.log('[worker] importScripts', imageCompressionLibUrl) | ||
self.importScripts(imageCompressionLibUrl) | ||
scriptImported = true | ||
} | ||
// console.log('[worker] self', self) | ||
const compressedFile = await imageCompression(file, options) | ||
self.postMessage({ file: compressedFile, id }) | ||
} catch (e) { | ||
// console.error('[worker] error', e) | ||
self.postMessage({ error: e.message + '\\n' + e.stack, id }) | ||
} | ||
}) | ||
`) | ||
} | ||
export function compressOnWebWorker (file, options) { | ||
return new Promise(async (resolve, reject) => { | ||
let id = cnt++ | ||
if (!imageCompressionLibUrl) { | ||
imageCompressionLibUrl = generateLib() | ||
} | ||
if (!worker) { | ||
worker = generateWorkerScript() | ||
} | ||
function handler (e) { | ||
if (e.data.id === id) { | ||
if (e.data.progress !== undefined && e.data.progress < 100) { | ||
options.onProgress(e.data.progress) | ||
return | ||
} | ||
worker.removeEventListener('message', handler) | ||
@@ -90,4 +116,9 @@ if (e.data.error) { | ||
worker.addEventListener('message', handler) | ||
worker.postMessage({ file, id, imageCompressionLibUrl, options }) | ||
worker.postMessage({ | ||
file, | ||
id, | ||
imageCompressionLibUrl, | ||
options: { ...options, onProgress: undefined } | ||
}) | ||
}) | ||
} | ||
} |
{ | ||
"name": "browser-image-compression", | ||
"version": "1.0.6", | ||
"version": "1.0.7", | ||
"description": "Compress images in the browser", | ||
@@ -8,2 +8,3 @@ "main": "dist/browser-image-compression.js", | ||
"jsnext:main": "dist/browser-image-compression.mjs", | ||
"types": "dist/browser-image-compression.d.ts", | ||
"scripts": { | ||
@@ -47,15 +48,16 @@ "eslint": "eslint lib test", | ||
"babel-eslint": "^10.0.1", | ||
"babel-plugin-istanbul": "^5.1.0", | ||
"babel-plugin-istanbul": "^6.0.0", | ||
"canvas": "^2.3.1", | ||
"chai": "^4.1.0", | ||
"chai-as-promised": "^7.1.1", | ||
"eslint": "^5.12.1", | ||
"eslint": "6.8.0", | ||
"istanbul": "^0.4.5", | ||
"jsdom": "^15.1.1", | ||
"make-coverage-badge": "^1.0.1", | ||
"mocha": "^6.1.4", | ||
"nyc": "^14.1.1", | ||
"rollup": "^1.1.2", | ||
"mocha": "7.1.0", | ||
"nyc": "15.0.0", | ||
"rollup": "2.0.6", | ||
"rollup-plugin-babel": "^4.3.2", | ||
"rollup-plugin-license": "^0.8.1", | ||
"rollup-plugin-copy": "^3.3.0", | ||
"rollup-plugin-license": "0.13.0", | ||
"rollup-plugin-nodent": "^0.2.2", | ||
@@ -62,0 +64,0 @@ "rollup-plugin-terser": "^5.0.0", |
@@ -51,3 +51,6 @@ # Browser Image Compression # | ||
useWebWorker: boolean, // optional, use multi-thread web worker, fallback to run in main-thread (default: true) | ||
maxIteration: number // optional, max number of iteration to compress the image (default: 10) | ||
maxIteration: number, // optional, max number of iteration to compress the image (default: 10) | ||
exifOrientation: number, // optional, see https://stackoverflow.com/a/32490603/10395024 | ||
onProgress: Function, // optional, a function takes one progress argument (percentage from 0 to 100) | ||
fileType: string // optional, fileType override | ||
} | ||
@@ -124,2 +127,7 @@ | ||
## Demo / Example ## | ||
open https://donaldcwl.github.io/browser-image-compression/example/basic.html | ||
or check the "[example]" folder in this repo | ||
## Browsers support ## | ||
@@ -131,12 +139,2 @@ | ||
## Example ## | ||
Please check the "[example]" folder in this repo | ||
- How to run the example: | ||
```bash | ||
git clone https://github.com/Donaldcwl/browser-image-compression.git | ||
cd browser-image-compression/example | ||
# open "basic.html" on your browser | ||
``` | ||
## Contribution ## | ||
@@ -143,0 +141,0 @@ 1. fork the repo and git clone it |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
103770
15
665
22
150