Open arachimi opened 5 months ago
@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.
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?
I tried setting the cropper size smaller, but I still encounter the same issue.
@arachimi, could you provide the source code and error text?
@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?
@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>
@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.
Note: I am using Mobile Safari for testing. Thank you in advance ❤️.
@Norserium I have change code to basic version.
@arachimi, you should pass canvas
prop with options like I've written above. Try it.
@Norserium Okay. Do you mean this prop?
:canvas="{
maxWidth: 4096,
maxHeight: 4096,
maxArea: 4096 * 4096,
}"
Here is the result:
Thank you.
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