ngx-image-cropper 7.1.2 → 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 +2 -2
- package/esm2020/lib/services/load-image.service.mjs +63 -34
- package/fesm2015/ngx-image-cropper.mjs +69 -31
- package/fesm2015/ngx-image-cropper.mjs.map +1 -1
- package/fesm2020/ngx-image-cropper.mjs +62 -33
- package/fesm2020/ngx-image-cropper.mjs.map +1 -1
- package/lib/services/load-image.service.d.ts +2 -1
- package/package.json +1 -1
|
@@ -612,30 +612,30 @@ class LoadImageService {
|
|
|
612
612
|
constructor() {
|
|
613
613
|
this.autoRotateSupported = supportsAutomaticRotation();
|
|
614
614
|
}
|
|
615
|
-
loadImageFile(file, cropperSettings) {
|
|
616
|
-
|
|
617
|
-
|
|
615
|
+
async loadImageFile(file, cropperSettings) {
|
|
616
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
617
|
+
return await this.checkImageTypeAndLoadImageFromArrayBuffer(arrayBuffer, file.type, cropperSettings);
|
|
618
618
|
}
|
|
619
619
|
checkImageTypeAndLoadImageFromArrayBuffer(arrayBuffer, imageType, cropperSettings) {
|
|
620
620
|
if (!this.isValidImageType(imageType)) {
|
|
621
621
|
return Promise.reject(new Error('Invalid image type'));
|
|
622
622
|
}
|
|
623
|
-
return this.loadImageFromArrayBuffer(arrayBuffer, cropperSettings);
|
|
623
|
+
return this.loadImageFromArrayBuffer(arrayBuffer, cropperSettings, imageType);
|
|
624
624
|
}
|
|
625
625
|
isValidImageType(type) {
|
|
626
|
-
return /image\/(png|jpg|jpeg|bmp|gif|tiff|webp|x-icon|vnd.microsoft.icon)/.test(type);
|
|
626
|
+
return /image\/(png|jpg|jpeg|bmp|gif|tiff|svg|webp|x-icon|vnd.microsoft.icon)/.test(type);
|
|
627
627
|
}
|
|
628
|
-
loadImageFromURL(url, cropperSettings) {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
628
|
+
async loadImageFromURL(url, cropperSettings) {
|
|
629
|
+
const res = await fetch(url);
|
|
630
|
+
const buffer = await res.arrayBuffer();
|
|
631
|
+
return await this.loadImageFromArrayBuffer(buffer, cropperSettings);
|
|
632
632
|
}
|
|
633
633
|
loadBase64Image(imageBase64, cropperSettings) {
|
|
634
634
|
const arrayBuffer = this.base64ToArrayBuffer(imageBase64);
|
|
635
635
|
return this.loadImageFromArrayBuffer(arrayBuffer, cropperSettings);
|
|
636
636
|
}
|
|
637
637
|
base64ToArrayBuffer(imageBase64) {
|
|
638
|
-
imageBase64 = imageBase64.replace(/^data
|
|
638
|
+
imageBase64 = imageBase64.replace(/^data:([^;]+);base64,/gmi, '');
|
|
639
639
|
const binaryString = atob(imageBase64);
|
|
640
640
|
const len = binaryString.length;
|
|
641
641
|
const bytes = new Uint8Array(len);
|
|
@@ -644,23 +644,55 @@ class LoadImageService {
|
|
|
644
644
|
}
|
|
645
645
|
return bytes.buffer;
|
|
646
646
|
}
|
|
647
|
-
loadImageFromArrayBuffer(arrayBuffer, cropperSettings) {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
647
|
+
async loadImageFromArrayBuffer(arrayBuffer, cropperSettings, imageType) {
|
|
648
|
+
const res = await new Promise(async (resolve, reject) => {
|
|
649
|
+
try {
|
|
650
|
+
const blob = new Blob([arrayBuffer], imageType ? { type: imageType } : undefined);
|
|
651
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
652
|
+
const originalImage = new Image();
|
|
653
|
+
const isSvg = imageType === 'image/svg+xml';
|
|
654
|
+
const originalImageSize = isSvg ? await this.getSvgImageSize(blob) : undefined;
|
|
655
|
+
originalImage.onload = () => resolve({
|
|
656
|
+
originalImage,
|
|
657
|
+
originalImageSize,
|
|
658
|
+
originalObjectUrl: objectUrl,
|
|
659
|
+
originalArrayBuffer: arrayBuffer
|
|
660
|
+
});
|
|
661
|
+
originalImage.onerror = reject;
|
|
662
|
+
originalImage.src = objectUrl;
|
|
663
|
+
}
|
|
664
|
+
catch (e) {
|
|
665
|
+
reject(e);
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
return await this.transformImageFromArrayBuffer(res, cropperSettings, res.originalImageSize != null);
|
|
669
|
+
}
|
|
670
|
+
async getSvgImageSize(blob) {
|
|
671
|
+
const parser = new DOMParser();
|
|
672
|
+
const doc = parser.parseFromString(await blob.text(), 'image/svg+xml');
|
|
673
|
+
const svgElement = doc.querySelector('svg');
|
|
674
|
+
if (!svgElement) {
|
|
675
|
+
throw Error('Failed to parse SVG image');
|
|
676
|
+
}
|
|
677
|
+
const widthAttr = svgElement.getAttribute('width');
|
|
678
|
+
const heightAttr = svgElement.getAttribute('height');
|
|
679
|
+
if (widthAttr && heightAttr) {
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
const viewBoxAttr = svgElement.getAttribute('viewBox')
|
|
683
|
+
|| svgElement.getAttribute('viewbox');
|
|
684
|
+
if (viewBoxAttr) {
|
|
685
|
+
const viewBox = viewBoxAttr.split(' ');
|
|
686
|
+
return {
|
|
687
|
+
width: +viewBox[2],
|
|
688
|
+
height: +viewBox[3]
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
throw Error('Failed to load SVG image. SVG must have width + height or viewBox definition.');
|
|
660
692
|
}
|
|
661
|
-
async transformImageFromArrayBuffer(res, cropperSettings) {
|
|
693
|
+
async transformImageFromArrayBuffer(res, cropperSettings, forceTransform = false) {
|
|
662
694
|
const autoRotate = await this.autoRotateSupported;
|
|
663
|
-
const exifTransform =
|
|
695
|
+
const exifTransform = getTransformationsFromExifData(autoRotate ? -1 : res.originalArrayBuffer);
|
|
664
696
|
if (!res.originalImage || !res.originalImage.complete) {
|
|
665
697
|
return Promise.reject(new Error('No image loaded'));
|
|
666
698
|
}
|
|
@@ -668,22 +700,19 @@ class LoadImageService {
|
|
|
668
700
|
original: {
|
|
669
701
|
objectUrl: res.originalObjectUrl,
|
|
670
702
|
image: res.originalImage,
|
|
671
|
-
size: {
|
|
703
|
+
size: res.originalImageSize ?? {
|
|
672
704
|
width: res.originalImage.naturalWidth,
|
|
673
705
|
height: res.originalImage.naturalHeight
|
|
674
706
|
}
|
|
675
707
|
},
|
|
676
708
|
exifTransform
|
|
677
709
|
};
|
|
678
|
-
return this.transformLoadedImage(loadedImage, cropperSettings);
|
|
710
|
+
return this.transformLoadedImage(loadedImage, cropperSettings, forceTransform);
|
|
679
711
|
}
|
|
680
|
-
async transformLoadedImage(loadedImage, cropperSettings) {
|
|
712
|
+
async transformLoadedImage(loadedImage, cropperSettings, forceTransform = false) {
|
|
681
713
|
const canvasRotation = cropperSettings.canvasRotation + loadedImage.exifTransform.rotate;
|
|
682
|
-
const originalSize =
|
|
683
|
-
|
|
684
|
-
height: loadedImage.original.image.naturalHeight
|
|
685
|
-
};
|
|
686
|
-
if (canvasRotation === 0 && !loadedImage.exifTransform.flip && !cropperSettings.containWithinAspectRatio) {
|
|
714
|
+
const originalSize = loadedImage.original.size;
|
|
715
|
+
if (!forceTransform && canvasRotation === 0 && !loadedImage.exifTransform.flip && !cropperSettings.containWithinAspectRatio) {
|
|
687
716
|
return {
|
|
688
717
|
original: {
|
|
689
718
|
objectUrl: loadedImage.original.objectUrl,
|