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