ngx-image-cropper 7.1.1 → 7.2.0
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/esm2020/lib/component/image-cropper.component.mjs +3 -2
- package/esm2020/lib/services/load-image.service.mjs +63 -34
- package/fesm2015/ngx-image-cropper.mjs +71 -32
- package/fesm2015/ngx-image-cropper.mjs.map +1 -1
- package/fesm2020/ngx-image-cropper.mjs +64 -34
- package/fesm2020/ngx-image-cropper.mjs.map +1 -1
- package/lib/services/load-image.service.d.ts +2 -1
- package/package.json +1 -1
|
@@ -3,7 +3,8 @@ import * as i0 from '@angular/core';
|
|
|
3
3
|
import { Injectable, EventEmitter, isDevMode, Component, ChangeDetectionStrategy, Optional, Inject, ViewChild, Input, HostBinding, Output, HostListener, NgModule } from '@angular/core';
|
|
4
4
|
import * as i4 from '@angular/platform-browser';
|
|
5
5
|
import { HAMMER_LOADER } from '@angular/platform-browser';
|
|
6
|
-
import {
|
|
6
|
+
import { takeUntil, first } from 'rxjs/operators';
|
|
7
|
+
import { merge, fromEvent } from 'rxjs';
|
|
7
8
|
import * as i5 from '@angular/common';
|
|
8
9
|
import { CommonModule } from '@angular/common';
|
|
9
10
|
|
|
@@ -617,29 +618,33 @@ class LoadImageService {
|
|
|
617
618
|
this.autoRotateSupported = supportsAutomaticRotation();
|
|
618
619
|
}
|
|
619
620
|
loadImageFile(file, cropperSettings) {
|
|
620
|
-
return
|
|
621
|
-
|
|
621
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
622
|
+
const arrayBuffer = yield file.arrayBuffer();
|
|
623
|
+
return yield this.checkImageTypeAndLoadImageFromArrayBuffer(arrayBuffer, file.type, cropperSettings);
|
|
624
|
+
});
|
|
622
625
|
}
|
|
623
626
|
checkImageTypeAndLoadImageFromArrayBuffer(arrayBuffer, imageType, cropperSettings) {
|
|
624
627
|
if (!this.isValidImageType(imageType)) {
|
|
625
628
|
return Promise.reject(new Error('Invalid image type'));
|
|
626
629
|
}
|
|
627
|
-
return this.loadImageFromArrayBuffer(arrayBuffer, cropperSettings);
|
|
630
|
+
return this.loadImageFromArrayBuffer(arrayBuffer, cropperSettings, imageType);
|
|
628
631
|
}
|
|
629
632
|
isValidImageType(type) {
|
|
630
|
-
return /image\/(png|jpg|jpeg|bmp|gif|tiff|webp|x-icon|vnd.microsoft.icon)/.test(type);
|
|
633
|
+
return /image\/(png|jpg|jpeg|bmp|gif|tiff|svg|webp|x-icon|vnd.microsoft.icon)/.test(type);
|
|
631
634
|
}
|
|
632
635
|
loadImageFromURL(url, cropperSettings) {
|
|
633
|
-
return
|
|
634
|
-
|
|
635
|
-
|
|
636
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
637
|
+
const res = yield fetch(url);
|
|
638
|
+
const buffer = yield res.arrayBuffer();
|
|
639
|
+
return yield this.loadImageFromArrayBuffer(buffer, cropperSettings);
|
|
640
|
+
});
|
|
636
641
|
}
|
|
637
642
|
loadBase64Image(imageBase64, cropperSettings) {
|
|
638
643
|
const arrayBuffer = this.base64ToArrayBuffer(imageBase64);
|
|
639
644
|
return this.loadImageFromArrayBuffer(arrayBuffer, cropperSettings);
|
|
640
645
|
}
|
|
641
646
|
base64ToArrayBuffer(imageBase64) {
|
|
642
|
-
imageBase64 = imageBase64.replace(/^data
|
|
647
|
+
imageBase64 = imageBase64.replace(/^data:([^;]+);base64,/gmi, '');
|
|
643
648
|
const binaryString = atob(imageBase64);
|
|
644
649
|
const len = binaryString.length;
|
|
645
650
|
const bytes = new Uint8Array(len);
|
|
@@ -648,24 +653,61 @@ class LoadImageService {
|
|
|
648
653
|
}
|
|
649
654
|
return bytes.buffer;
|
|
650
655
|
}
|
|
651
|
-
loadImageFromArrayBuffer(arrayBuffer, cropperSettings) {
|
|
652
|
-
return
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
656
|
+
loadImageFromArrayBuffer(arrayBuffer, cropperSettings, imageType) {
|
|
657
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
658
|
+
const res = yield new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
659
|
+
try {
|
|
660
|
+
const blob = new Blob([arrayBuffer], imageType ? { type: imageType } : undefined);
|
|
661
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
662
|
+
const originalImage = new Image();
|
|
663
|
+
const isSvg = imageType === 'image/svg+xml';
|
|
664
|
+
const originalImageSize = isSvg ? yield this.getSvgImageSize(blob) : undefined;
|
|
665
|
+
originalImage.onload = () => resolve({
|
|
666
|
+
originalImage,
|
|
667
|
+
originalImageSize,
|
|
668
|
+
originalObjectUrl: objectUrl,
|
|
669
|
+
originalArrayBuffer: arrayBuffer
|
|
670
|
+
});
|
|
671
|
+
originalImage.onerror = reject;
|
|
672
|
+
originalImage.src = objectUrl;
|
|
673
|
+
}
|
|
674
|
+
catch (e) {
|
|
675
|
+
reject(e);
|
|
676
|
+
}
|
|
677
|
+
}));
|
|
678
|
+
return yield this.transformImageFromArrayBuffer(res, cropperSettings, res.originalImageSize != null);
|
|
679
|
+
});
|
|
664
680
|
}
|
|
665
|
-
|
|
681
|
+
getSvgImageSize(blob) {
|
|
682
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
683
|
+
const parser = new DOMParser();
|
|
684
|
+
const doc = parser.parseFromString(yield blob.text(), 'image/svg+xml');
|
|
685
|
+
const svgElement = doc.querySelector('svg');
|
|
686
|
+
if (!svgElement) {
|
|
687
|
+
throw Error('Failed to parse SVG image');
|
|
688
|
+
}
|
|
689
|
+
const widthAttr = svgElement.getAttribute('width');
|
|
690
|
+
const heightAttr = svgElement.getAttribute('height');
|
|
691
|
+
if (widthAttr && heightAttr) {
|
|
692
|
+
return null;
|
|
693
|
+
}
|
|
694
|
+
const viewBoxAttr = svgElement.getAttribute('viewBox')
|
|
695
|
+
|| svgElement.getAttribute('viewbox');
|
|
696
|
+
if (viewBoxAttr) {
|
|
697
|
+
const viewBox = viewBoxAttr.split(' ');
|
|
698
|
+
return {
|
|
699
|
+
width: +viewBox[2],
|
|
700
|
+
height: +viewBox[3]
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
throw Error('Failed to load SVG image. SVG must have width + height or viewBox definition.');
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
transformImageFromArrayBuffer(res, cropperSettings, forceTransform = false) {
|
|
707
|
+
var _a;
|
|
666
708
|
return __awaiter(this, void 0, void 0, function* () {
|
|
667
709
|
const autoRotate = yield this.autoRotateSupported;
|
|
668
|
-
const exifTransform =
|
|
710
|
+
const exifTransform = getTransformationsFromExifData(autoRotate ? -1 : res.originalArrayBuffer);
|
|
669
711
|
if (!res.originalImage || !res.originalImage.complete) {
|
|
670
712
|
return Promise.reject(new Error('No image loaded'));
|
|
671
713
|
}
|
|
@@ -673,24 +715,21 @@ class LoadImageService {
|
|
|
673
715
|
original: {
|
|
674
716
|
objectUrl: res.originalObjectUrl,
|
|
675
717
|
image: res.originalImage,
|
|
676
|
-
size: {
|
|
718
|
+
size: (_a = res.originalImageSize) !== null && _a !== void 0 ? _a : {
|
|
677
719
|
width: res.originalImage.naturalWidth,
|
|
678
720
|
height: res.originalImage.naturalHeight
|
|
679
721
|
}
|
|
680
722
|
},
|
|
681
723
|
exifTransform
|
|
682
724
|
};
|
|
683
|
-
return this.transformLoadedImage(loadedImage, cropperSettings);
|
|
725
|
+
return this.transformLoadedImage(loadedImage, cropperSettings, forceTransform);
|
|
684
726
|
});
|
|
685
727
|
}
|
|
686
|
-
transformLoadedImage(loadedImage, cropperSettings) {
|
|
728
|
+
transformLoadedImage(loadedImage, cropperSettings, forceTransform = false) {
|
|
687
729
|
return __awaiter(this, void 0, void 0, function* () {
|
|
688
730
|
const canvasRotation = cropperSettings.canvasRotation + loadedImage.exifTransform.rotate;
|
|
689
|
-
const originalSize =
|
|
690
|
-
|
|
691
|
-
height: loadedImage.original.image.naturalHeight
|
|
692
|
-
};
|
|
693
|
-
if (canvasRotation === 0 && !loadedImage.exifTransform.flip && !cropperSettings.containWithinAspectRatio) {
|
|
731
|
+
const originalSize = loadedImage.original.size;
|
|
732
|
+
if (!forceTransform && canvasRotation === 0 && !loadedImage.exifTransform.flip && !cropperSettings.containWithinAspectRatio) {
|
|
694
733
|
return {
|
|
695
734
|
original: {
|
|
696
735
|
objectUrl: loadedImage.original.objectUrl,
|