ng7-pica
Version:
Angular module to resize images files in browser
665 lines (656 loc) • 21 kB
JavaScript
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