我正在实现一个系统,用户选择图像,他必须在保存之前裁剪它;我正在使用 vue-advance-cropper 插件;所有系统均已设置,但结果图像尺寸比原始尺寸大;
示例:我在 307ko 处插入图像,得到 448ko;我在 40ko 处插入图像,得到 206ko;
我是否错过了任何选项来使结果的大小小于原始大小,或者没有什么可以做的?
最佳答案
摘要
我认为所描述的问题与所使用的库没有任何共同点。
裁剪图像尺寸大于原始图像尺寸的最常见原因是裁剪图像格式与原始图像格式之间的差异。
澄清一下。如果您上传 jpeg
图像,请裁剪它并通过 toBlob
从裁剪 Canvas 中获取它。方法,默认情况下你会得到一个 png
图像,所以在大多数情况下它显然会比原始图像大。
这是因为 toBlob
从 Canvas 创建一个全新的图像,并且它对原始图像属性一无所知。因此,根据这种方法的性质,您无法创建原始图像的精确副本,包括其大小。
好消息是您可以更接近原始图像。
toBlob
方法具有以下签名:
toBlob(callback)
toBlob(callback, type)
toBlob(callback, type, quality)
因此,您可以设置相同的类型和图像质量的合理值。
解决方案
vue-advanced-cropper
documentation中有图片上传示例。我将在下面展示它的完整版本:
import { Cropper } from 'vue-advanced-cropper'
// This function is used to detect the actual image type,
function getMimeType(file, fallback = null) {
const byteArray = (new Uint8Array(file)).subarray(0, 4);
let header = '';
for (let i = 0; i < byteArray.length; i++) {
header += byteArray[i].toString(16);
}
switch (header) {
case "89504e47":
return "image/png";
case "47494638":
return "image/gif";
case "ffd8ffe0":
case "ffd8ffe1":
case "ffd8ffe2":
case "ffd8ffe3":
case "ffd8ffe8":
return "image/jpeg";
default:
return fallback;
}
}
export default {
components: {
Cropper,
},
data() {
return {
image: {
src: null,
type: null
}
};
},
methods: {
crop() {
const { canvas } = this.$refs.cropper.getResult();
canvas.toBlob((blob) => {
// Do something with blob: upload to a server, download and etc.
}, this.image.type);
},
reset() {
this.image = {
src: null,
type: null
}
},
loadImage(event) {
// Reference to the DOM input element
const { files } = event.target;
// Ensure that you have a file before attempting to read it
if (files && files[0]) {
// 1. Revoke the object URL, to allow the garbage collector to destroy the uploaded before file
if (this.image.src) {
URL.revokeObjectURL(this.image.src)
}
// 2. Create the blob link to the file to optimize performance:
const blob = URL.createObjectURL(files[0]);
// 3. The steps below are designated to determine a file mime type to use it during the
// getting of a cropped image from the canvas. You can replace it them by the following string,
// but the type will be derived from the extension and it can lead to an incorrect result:
//
// this.image = {
// src: blob;
// type: files[0].type
// }
// Create a new FileReader to read this image binary data
const reader = new FileReader();
// Define a callback function to run, when FileReader finishes its job
reader.onload = (e) => {
// Note: arrow function used here, so that "this.image" refers to the image of Vue component
this.image = {
// Set the image source (it will look like blob:http://example.com/2c5270a5-18b5-406e-a4fb-07427f5e7b94)
src: blob,
// Determine the image type to preserve it during the extracting the image from canvas:
type: getMimeType(e.target.result, files[0].type),
};
};
// Start the reader job - read file as a data url (base64 format)
reader.readAsArrayBuffer(files[0]);
}
},
},
destroyed() {
// Revoke the object URL, to allow the garbage collector to destroy the uploaded before file
if (this.image.src) {
URL.revokeObjectURL(this.image.src)
}
}
};
此示例将帮助您使裁剪器结果大小非常接近原始图像大小。您可以在 the sandbox 在线测试使用上面代码的简化版本。
关于image - vue-advanced-cropper 图像裁剪尺寸比原始尺寸大,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72305032/