UNPKG

ng7-pica

Version:

Angular module to resize images files in browser

665 lines (656 loc) 21 kB
import { Subject } from 'rxjs'; import { getData, getAllTags } from 'exif-js'; import Pica from 'pica'; import { Injectable, NgModule } from '@angular/core'; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** @enum {string} */ var NgxPicaErrorType = { NO_FILES_RECEIVED: 'NO_FILES_RECEIVED', CANVAS_CONTEXT_IDENTIFIER_NOT_SUPPORTED: 'CANVAS_CONTEXT_IDENTIFIER_NOT_SUPPORTED', NOT_BE_ABLE_TO_COMPRESS_ENOUGH: 'NOT_BE_ABLE_TO_COMPRESS_ENOUGH', }; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ var NgxPicaExifService = /** @class */ (function () { function NgxPicaExifService() { } /** * @param {?} image * @return {?} */ NgxPicaExifService.prototype.getExifOrientedImage = /** * @param {?} image * @return {?} */ function (image) { return new Promise(function (resolve, reject) { getData((/** @type {?} */ (image)), function () { /** @type {?} */ var allExifMetaData = getAllTags(image); /** @type {?} */ var exifOrientation = allExifMetaData.Orientation; if (exifOrientation) { if (!/^[1-8]$/.test(exifOrientation)) { throw new Error('orientation should be [1-8]'); } /** @type {?} */ var canvas = document.createElement('canvas'); /** @type {?} */ var ctx = canvas.getContext('2d'); /** @type {?} */ var deg = 0; /** @type {?} */ var cx = 0; /** @type {?} */ var cy = 0; /** @type {?} */ var width = image.width; /** @type {?} */ var height = image.height; if ([5, 6, 7, 8].indexOf(exifOrientation) > -1) { width = image.height; height = image.width; } canvas.width = width; canvas.height = height; switch (exifOrientation) { case 3: case 4: cx = -image.width; cy = -image.height; deg = 180; break; case 5: case 6: cy = -image.height; deg = 90; break; case 7: case 8: cx = -image.width; deg = 270; break; default: break; } if ([2, 4, 5, 7].indexOf(exifOrientation) > -1) { ctx.translate(width, 0); ctx.scale(-1, 1); } ctx.rotate(deg / 180 * Math.PI); ctx.drawImage(image, cx, cy); /** @type {?} */ var img_1 = new Image(); img_1.width = width; img_1.height = height; img_1.onload = function () { resolve(img_1); }; img_1.src = canvas.toDataURL(); } else { resolve(image); } }); }); }; NgxPicaExifService.decorators = [ { type: Injectable } ]; return NgxPicaExifService; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ var NgxPicaService = /** @class */ (function () { function NgxPicaService(_ngxPicaExifService) { this._ngxPicaExifService = _ngxPicaExifService; this.picaResizer = new Pica(); this.MAX_STEPS = 20; if (!this.picaResizer || !this.picaResizer.resize) { this.picaResizer = new window.Pica(); } } /** * @param {?} files * @param {?} width * @param {?} height * @param {?=} options * @return {?} */ NgxPicaService.prototype.resizeImages = /** * @param {?} files * @param {?} width * @param {?} height * @param {?=} options * @return {?} */ function (files, width, height, options) { var _this = this; /** @type {?} */ var resizedImage = new Subject(); /** @type {?} */ var totalFiles = files.length; if (totalFiles > 0) { /** @type {?} */ var nextFile_1 = new Subject(); /** @type {?} */ var index_1 = 0; /** @type {?} */ var subscription_1 = nextFile_1.subscribe(function (file) { _this.resizeImage(file, width, height, options).subscribe(function (imageResized) { index_1++; resizedImage.next(imageResized); if (index_1 < totalFiles) { nextFile_1.next(files[index_1]); } else { resizedImage.complete(); subscription_1.unsubscribe(); } }, function (err) { /** @type {?} */ var ngxPicaError = { file: file, err: err }; resizedImage.error(ngxPicaError); }); }); nextFile_1.next(files[index_1]); } else { /** @type {?} */ var ngxPicaError = { err: NgxPicaErrorType.NO_FILES_RECEIVED }; resizedImage.error(ngxPicaError); resizedImage.complete(); } return resizedImage.asObservable(); }; /** * @param {?} file * @param {?} width * @param {?} height * @param {?=} options * @return {?} */ NgxPicaService.prototype.resizeImage = /** * @param {?} file * @param {?} width * @param {?} height * @param {?=} options * @return {?} */ function (file, width, height, options) { var _this = this; /** @type {?} */ var resizedImage = new Subject(); /** @type {?} */ var originCanvas = document.createElement('canvas'); /** @type {?} */ var ctx = originCanvas.getContext('2d'); /** @type {?} */ var img = new Image(); if (ctx) { img.onload = function () { _this._ngxPicaExifService.getExifOrientedImage(img).then(function (orientedImage) { window.URL.revokeObjectURL(img.src); originCanvas.width = orientedImage.width; originCanvas.height = orientedImage.height; ctx.drawImage(orientedImage, 0, 0); /** @type {?} */ var imageData = ctx.getImageData(0, 0, orientedImage.width, orientedImage.height); if (options && options.aspectRatio && options.aspectRatio.keepAspectRatio) { /** @type {?} */ var ratio = 0; if (options.aspectRatio.forceMinDimensions) { ratio = Math.max(width / imageData.width, height / imageData.height); } else { ratio = Math.min(width / imageData.width, height / imageData.height); } width = Math.round(imageData.width * ratio); height = Math.round(imageData.height * ratio); } /** @type {?} */ var destinationCanvas = document.createElement('canvas'); destinationCanvas.width = width; destinationCanvas.height = height; _this.picaResize(file, originCanvas, destinationCanvas, options) .catch(function (err) { return resizedImage.error(err); }) .then(function (imgResized) { resizedImage.next(imgResized); }); }); }; img.src = window.URL.createObjectURL(file); } else { resizedImage.error(NgxPicaErrorType.CANVAS_CONTEXT_IDENTIFIER_NOT_SUPPORTED); } return resizedImage.asObservable(); }; /** * @param {?} files * @param {?} sizeInMB * @return {?} */ NgxPicaService.prototype.compressImages = /** * @param {?} files * @param {?} sizeInMB * @return {?} */ function (files, sizeInMB) { var _this = this; /** @type {?} */ var compressedImage = new Subject(); /** @type {?} */ var totalFiles = files.length; if (totalFiles > 0) { /** @type {?} */ var nextFile_2 = new Subject(); /** @type {?} */ var index_2 = 0; /** @type {?} */ var subscription_2 = nextFile_2.subscribe(function (file) { _this.compressImage(file, sizeInMB).subscribe(function (imageCompressed) { index_2++; compressedImage.next(imageCompressed); if (index_2 < totalFiles) { nextFile_2.next(files[index_2]); } else { compressedImage.complete(); subscription_2.unsubscribe(); } }, function (err) { /** @type {?} */ var ngxPicaError = { file: file, err: err }; compressedImage.error(ngxPicaError); }); }); nextFile_2.next(files[index_2]); } else { /** @type {?} */ var ngxPicaError = { err: NgxPicaErrorType.NO_FILES_RECEIVED }; compressedImage.error(ngxPicaError); compressedImage.complete(); } return compressedImage.asObservable(); }; /** * @param {?} file * @param {?} sizeInMB * @return {?} */ NgxPicaService.prototype.compressImage = /** * @param {?} file * @param {?} sizeInMB * @return {?} */ function (file, sizeInMB) { var _this = this; /** @type {?} */ var compressedImage = new Subject(); /** @type {?} */ var originCanvas = document.createElement('canvas'); /** @type {?} */ var ctx = originCanvas.getContext('2d'); /** @type {?} */ var img = new Image(); if (ctx) { img.onload = function () { _this._ngxPicaExifService.getExifOrientedImage(img).then(function (orientedImage) { window.URL.revokeObjectURL(img.src); originCanvas.width = orientedImage.width; originCanvas.height = orientedImage.height; ctx.drawImage(orientedImage, 0, 0); if (_this.bytesToMB(file.size) <= sizeInMB) { _this.picaResizer.toBlob(originCanvas, file.type, 1) .catch(function (err) { return compressedImage.error(err); }) .then(function (blob) { /** @type {?} */ var imgCompressed = _this.blobToFile(blob, file.name, file.type, new Date().getTime()); compressedImage.next(imgCompressed); }); } else { _this.getCompressedImage(originCanvas, file.type, 1, sizeInMB, 0) .catch(function (err) { return compressedImage.error(err); }) .then(function (blob) { /** @type {?} */ var imgCompressed = _this.blobToFile(blob, file.name, file.type, new Date().getTime()); compressedImage.next(imgCompressed); }); } }); }; img.src = window.URL.createObjectURL(file); } else { compressedImage.error(NgxPicaErrorType.CANVAS_CONTEXT_IDENTIFIER_NOT_SUPPORTED); } return compressedImage.asObservable(); }; /** * @param {?} canvas * @param {?} type * @param {?} quality * @param {?} sizeInMB * @param {?} step * @return {?} */ NgxPicaService.prototype.getCompressedImage = /** * @param {?} canvas * @param {?} type * @param {?} quality * @param {?} sizeInMB * @param {?} step * @return {?} */ function (canvas, type, quality, sizeInMB, step) { var _this = this; return new Promise(function (resolve, reject) { _this.picaResizer.toBlob(canvas, type, quality) .catch(function (err) { return reject(err); }) .then(function (blob) { _this.checkCompressedImageSize(canvas, blob, quality, sizeInMB, step) .catch(function (err) { return reject(err); }) .then(function (compressedBlob) { resolve(compressedBlob); }); }); }); }; /** * @param {?} canvas * @param {?} blob * @param {?} quality * @param {?} sizeInMB * @param {?} step * @return {?} */ NgxPicaService.prototype.checkCompressedImageSize = /** * @param {?} canvas * @param {?} blob * @param {?} quality * @param {?} sizeInMB * @param {?} step * @return {?} */ function (canvas, blob, quality, sizeInMB, step) { var _this = this; return new Promise(function (resolve, reject) { if (step > _this.MAX_STEPS) { reject(NgxPicaErrorType.NOT_BE_ABLE_TO_COMPRESS_ENOUGH); } else if (_this.bytesToMB(blob.size) < sizeInMB) { resolve(blob); } else { /** @type {?} */ var newQuality = quality - (quality * 0.1); /** @type {?} */ var newStep = step + 1; // recursively compression resolve(_this.getCompressedImage(canvas, blob.type, newQuality, sizeInMB, newStep)); } }); }; /** * @param {?} file * @param {?} from * @param {?} to * @param {?} options * @return {?} */ NgxPicaService.prototype.picaResize = /** * @param {?} file * @param {?} from * @param {?} to * @param {?} options * @return {?} */ function (file, from, to, options) { var _this = this; return new Promise(function (resolve, reject) { _this.picaResizer.resize(from, to, options) .catch(function (err) { return reject(err); }) .then(function (resizedCanvas) { return _this.picaResizer.toBlob(resizedCanvas, file.type); }) .then(function (blob) { /** @type {?} */ var fileResized = _this.blobToFile(blob, file.name, file.type, new Date().getTime()); resolve(fileResized); }); }); }; /** * @param {?} blob * @param {?} name * @param {?} type * @param {?} lastModified * @return {?} */ NgxPicaService.prototype.blobToFile = /** * @param {?} blob * @param {?} name * @param {?} type * @param {?} lastModified * @return {?} */ function (blob, name, type, lastModified) { /** @type {?} */ var file = /** @type {?} */ (new Blob([blob], { type: type })); file.name = name; file.lastModifiedDate = lastModified; return /** @type {?} */ (file); }; /** * @param {?} bytes * @return {?} */ NgxPicaService.prototype.bytesToMB = /** * @param {?} bytes * @return {?} */ function (bytes) { return bytes / 1048576; }; NgxPicaService.decorators = [ { type: Injectable } ]; /** @nocollapse */ NgxPicaService.ctorParameters = function () { return [ { type: NgxPicaExifService } ]; }; return NgxPicaService; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ var NgxPicaImageService = /** @class */ (function () { function NgxPicaImageService() { this.imageExtensions = [ 'ase', 'art', 'bmp', 'blp', 'cd5', 'cit', 'cpt', 'cr2', 'cut', 'dds', 'dib', 'djvu', 'egt', 'exif', 'gif', 'gpl', 'grf', 'icns', 'ico', 'iff', 'jng', 'jpeg', 'jpg', 'jfif', 'jp2', 'jps', 'lbm', 'max', 'miff', 'mng', 'msp', 'nitf', 'ota', 'pbm', 'pc1', 'pc2', 'pc3', 'pcf', 'pcx', 'pdn', 'pgm', 'PI1', 'PI2', 'PI3', 'pict', 'pct', 'pnm', 'pns', 'ppm', 'psb', 'psd', 'pdd', 'psp', 'px', 'pxm', 'pxr', 'qfx', 'raw', 'rle', 'sct', 'sgi', 'rgb', 'int', 'bw', 'tga', 'tiff', 'tif', 'vtf', 'xbm', 'xcf', 'xpm', '3dv', 'amf', 'ai', 'awg', 'cgm', 'cdr', 'cmx', 'dxf', 'e2d', 'egt', 'eps', 'fs', 'gbr', 'odg', 'svg', 'stl', 'vrml', 'x3d', 'sxd', 'v2d', 'vnd', 'wmf', 'emf', 'art', 'xar', 'png', 'webp', 'jxr', 'hdp', 'wdp', 'cur', 'ecw', 'iff', 'lbm', 'liff', 'nrrd', 'pam', 'pcx', 'pgf', 'sgi', 'rgb', 'rgba', 'bw', 'int', 'inta', 'sid', 'ras', 'sun', 'tga' ]; } /** * @param {?} file * @return {?} */ NgxPicaImageService.prototype.isImage = /** * @param {?} file * @return {?} */ function (file) { /** @type {?} */ var fileExtension = file.name.toLowerCase().substr(file.name.lastIndexOf('.') + 1); return (this.imageExtensions.indexOf(fileExtension) !== -1); }; NgxPicaImageService.decorators = [ { type: Injectable } ]; return NgxPicaImageService; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ var NgxPicaModule = /** @class */ (function () { function NgxPicaModule() { } NgxPicaModule.decorators = [ { type: NgModule, args: [{ providers: [ { provide: NgxPicaService, useClass: NgxPicaService }, { provide: NgxPicaExifService, useClass: NgxPicaExifService }, { provide: NgxPicaImageService, useClass: NgxPicaImageService }, ] },] } ]; return NgxPicaModule; }()); /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc */ export { NgxPicaModule, NgxPicaService, NgxPicaImageService, NgxPicaExifService }; //# sourceMappingURL=ng7-pica.js.map