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.
@@ -612,30 +612,31 @@ class LoadImageService {
612
612
  constructor() {
613
613
  this.autoRotateSupported = supportsAutomaticRotation();
614
614
  }
615
- loadImageFile(file, cropperSettings) {
616
- return file.arrayBuffer()
617
- .then(arrayBuffer => this.checkImageTypeAndLoadImageFromArrayBuffer(arrayBuffer, file.type, cropperSettings));
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
- return fetch(url)
630
- .then(res => res.arrayBuffer())
631
- .then(buffer => this.loadImageFromArrayBuffer(buffer, cropperSettings));
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\:([^\;]+)\;base64,/gmi, '');
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
- return new Promise((resolve, reject) => {
649
- const blob = new Blob([arrayBuffer]);
650
- const objectUrl = URL.createObjectURL(blob);
651
- const originalImage = new Image();
652
- originalImage.onload = () => resolve({
653
- originalImage,
654
- originalObjectUrl: objectUrl,
655
- originalArrayBuffer: arrayBuffer
656
- });
657
- originalImage.onerror = reject;
658
- originalImage.src = objectUrl;
659
- }).then((res) => this.transformImageFromArrayBuffer(res, cropperSettings));
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 = await getTransformationsFromExifData(autoRotate ? -1 : res.originalArrayBuffer);
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
- width: loadedImage.original.image.naturalWidth,
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,