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.
@@ -612,30 +612,30 @@ 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 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\:([^\;]+)\;base64,/gmi, '');
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
- 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));
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 = await getTransformationsFromExifData(autoRotate ? -1 : res.originalArrayBuffer);
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
- width: loadedImage.original.image.naturalWidth,
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,