Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with Cropping HEIC Files on Apple Devices #279

Open
arachimi opened this issue Jun 14, 2024 · 8 comments
Open

Issue with Cropping HEIC Files on Apple Devices #279

arachimi opened this issue Jun 14, 2024 · 8 comments

Comments

@arachimi
Copy link

Dear Developer,

I encountered a problem with cropping HEIC files from the Apple Gallery. When I select a file from the Gallery and attempt to crop it, I receive the following error from the Safari log:

"Canvas area exceeds the maximum limit (width * height > 16777216)."

This might be causing the crop function to fail.

I have attached a sample file with the issue in this Google Drive link:

https://drive.google.com/file/d/1WOKcNmwsCHKGt95KKLBYe7W-eInZu0Nd/view?usp=drive_link

You can also test it on this website:

https://codesandbox.io/embed/vue-advanced-cropper-composition-api-5z0ww0?codemirror=1

I tried it on Safari iOS and found that after cropping, the resulting image is black.

Thanks as always

@Norserium
Copy link
Collaborator

Norserium commented Jun 15, 2024

@arachimi, you can use canvas-size library to detect the maximum width, height and area and pass this values to canvas prop.

<cropper
	:src="image"
	:canvas="{
		maxHeight: canvasSize.maxHeight,
		maxWidth: canvasSize.maxHeight,
		maxArea: canvasSize.maxArea,
	}"
/>

Perhaps, it should be a part of the cropper library, but I'm not sure because it will increase the library size the cropper's and users usually set the canvas size limitations anyway.

@arachimi
Copy link
Author

Thank you for your suggestion.
I think the problem doesn't come from the cropper itself but rather from the source images I choose from the Gallery.

I tried setting the cropper size smaller, but I still encounter the same issue.

What do you think?

@Norserium
Copy link
Collaborator

Norserium commented Jun 16, 2024

I tried setting the cropper size smaller, but I still encounter the same issue.

@arachimi, could you provide the source code and error text?

@arachimi
Copy link
Author

@Norserium Thank you. I will provide source code below.

Template :

<template>
  <div class="cropper-wrapper">
    <div class="image-wrapper">
      <div :style="{ backgroundImage: 'url(' + img + ')' }" class="cropper" />

      <Cropper
        classname="upload-example-cropper"
        imageClassname="imgName"
        :src="img"
        ref="cropper"
        @change="change"
        :stencil-props="{
          handlers: {
            eastNorth: true,
            north: false,
            westNorth: true,
            west: false,
            westSouth: true,
            south: false,
            eastSouth: true,
            east: false,
          },
          movable: true,
          scalable: true,
          minAspectRatio,
          maxAspectRatio,
          autoZoom: true,
        }"
        :maxWidth = "maxWidth"
        :maxHeight = "maxHeight"
        :minWidth = "minWidth"
        :minHeight = "minHeight"
        :setCoordinates = "setCoordinates"
      />
    </div>
    <div class="button-wrapper">
      <f7-button class="rotate-button" @click="rotateLeft" style="margin-left: auto">
        <img src="static/svg/RotateLeft.svg" alt="Rotate Left Icon" />
      </f7-button>
      <f7-button class="rotate-button" @click="rotateRight" style="margin-right: auto">
        <img src="static/svg/RotateRight.svg" alt="Rotate Right Icon" />
      </f7-button>
    </div>
  </div>
</template>

Vue:

export default {
  props: {
    img: String,
    mode: String,
    f7router: Object,
  },
  components: {
    Cropper,
  },
  data() {
    return {
      maxAspectRatio: 3 / 2,
      minAspectRatio: 2 / 3,
      coordinates: {
        width: 0,
        height: 0,
        left: 0,
        top: 0,
      },
      rotation: 0,
      croppedImage: '',
      maxWidth: 4096,
      maxHeight: 4096,
      minWidth: 128,
      minHeight: 128,
      orginal: {
        w: 0,
        h: 0
      }

    }
  },
  mounted() {
      this.$refs.cropper.setCoordinates(this.setCoordinates)
      console.log("check", this.img.length)
  },
  emits: ["changeEvent"],
  methods: {
    setCoordinates({ coordinates, imageSize }) {
      this.orginal.w = imageSize.width
      this.orginal.h = imageSize.height

      console.log("mounted",imageSize.width,imageSize.height, coordinates)

      var w = Math.min(this.maxWidth,imageSize.width)
      var h = Math.min(this.maxHeight,imageSize.height)

      if (w > h * this.maxAspectRatio) {
        w = h * this.maxAspectRatio
      } else if (w < h * this.minAspectRatio) {
        h = w / this.minAspectRatio
      }
      return {
        width: w,
        height: h,
        left: imageSize.width / 2 - w / 2,
        top: imageSize.height / 2 - h / 2,
      }
    },
    async rotateRight() {
      this.$refs.cropper.rotate(90)
    },
    async rotateLeft() {
      this.$refs.cropper.rotate(-90)
    },
    back() {
      this.f7router.back()
      this.f7router.app.tab.show('#view-fifth', false)
      f7.preloader.hide()
    },
    change({ coordinates, canvas }) {
      console.log("coordinates", coordinates, canvas);
      const max = 2048
      var resizeCanvas = document.createElement("canvas");
      var w = canvas.width;
      var h = canvas.height;
      var wth = w > h;
      if (wth && w > max) {
        h = h/w * max
        w = max;
      }
      else if (h > max) {
        w = w/h * max
        h = max;
      }
      console.log("resize", w, h);
      resizeCanvas.width = w;
      resizeCanvas.height = h;
      var resizedContext = resizeCanvas.getContext("2d");
      resizedContext.drawImage(canvas, 0, 0, w, h);
      const croppedImage = resizeCanvas.toDataURL('image/jpeg', 0.9)
      this.$emit('changeEvent', croppedImage)
      f7.preloader.hide()
    },
  },
  computed: {

  },
}

Log from console.
Uploading Screenshot 2567-06-17 at 12.03.50.png…

After crop process it's show black image. Could you please point out where I went wrong or what mistakes I made?

@Norserium
Copy link
Collaborator

Norserium commented Jun 17, 2024

@arachimi, you are doing it incorrectly. The cropper already has a functional to resize a canvas.

<template>
  <div class="cropper-wrapper">
    <div class="image-wrapper">
      <div :style="{ backgroundImage: 'url(' + img + ')' }" class="cropper" />

      <Cropper
        classname="upload-example-cropper"
        imageClassname="imgName"
        :src="img"
        ref="cropper"
        @change="change"
        :stencil-props="{
          handlers: {
            eastNorth: true,
            north: false,
            westNorth: true,
            west: false,
            westSouth: true,
            south: false,
            eastSouth: true,
            east: false,
          },
          movable: true,
          scalable: true,
          minAspectRatio,
          maxAspectRatio,
          autoZoom: true,
        }"
        :canvas="{
            maxWidth: 4096,
            maxHeight: 4096,
            maxArea: 4096 * 4096,
        }"
      />
    </div>
    <div class="button-wrapper">
      <f7-button class="rotate-button" @click="rotateLeft" style="margin-left: auto">
        <img src="static/svg/RotateLeft.svg" alt="Rotate Left Icon" />
      </f7-button>
      <f7-button class="rotate-button" @click="rotateRight" style="margin-right: auto">
        <img src="static/svg/RotateRight.svg" alt="Rotate Right Icon" />
      </f7-button>
    </div>
  </div>
</template>

@arachimi
Copy link
Author

@Norserium I have change code to basic version.

<template>
  <div>
    <input type="file" @change="onFileChange" accept="image/*" />
    <div v-if="imageSrc">
      <cropper
        :src="imageSrc"
        :stencil-props="{ aspectRatio: 1 }"
        @change="onCrop"
      />
    </div>
    <div v-if="croppedImage">
      <h3>Cropped Image</h3>
      <img :src="croppedImage" alt="Cropped Image" style="width: 100%;" />
    </div>
  </div>
</template>

<script>
import { Cropper } from 'vue-advanced-cropper';
import 'vue-advanced-cropper/dist/style.css';


export default {
  components: {
    Cropper,
  },
  data() {
    return {
      imageSrc: null,
      croppedImage: null,
    };
  },
  methods: {
    onFileChange(event) {
      const file = event.target.files[0];
      console.log(file);
      if (file) {
        const reader = new FileReader();
        reader.onload = (e) => {
          this.imageSrc = e.target.result;
        };
        reader.readAsDataURL(file);
      }
    },
    onCrop({ coordinates, canvas }) {
      if (canvas) {
        console.log(coordinates);
        this.croppedImage = canvas.toDataURL('image/jpeg');
      }
    },
  },
};
</script>

I have made a video example for you to see as well

At first, when I select a normal image, you can see that the app can select and crop the image normally. But my problem is that there are some images that it cannot crop. I have sent a sample image file for you to check in the first comment, which is this file:

https://drive.google.com/file/d/1WOKcNmwsCHKGt95KKLBYe7W-eInZu0Nd/view

The mentioned image is an adapter charging cable image. I'm not sure why when this file is selected, it cannot be cropped. How can I fix it?

I have attached a video example showing my usage steps for you to watch and check.

https://drive.google.com/file/d/1qeOLXSWq2mQo0FEL8Gam1KZdMrzqcD3i/view?usp=drive_link

And finally, I have attached the log from the Safari Console.

Screenshot 2567-06-17 at 21 27 44

Note: I am using Mobile Safari for testing.
Thank you in advance ❤️.

@Norserium
Copy link
Collaborator

Norserium commented Jun 17, 2024

@Norserium I have change code to basic version.

@arachimi, you should pass canvas prop with options like I've written above. Try it.

@arachimi
Copy link
Author

@Norserium Okay. Do you mean this prop?

:canvas="{
            maxWidth: 4096,
            maxHeight: 4096,
            maxArea: 4096 * 4096,
        }"

Here is the result:

Screenshot 2567-06-18 at 12 55 23

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants