image - vue-advanced-cropper 图像裁剪尺寸比原始尺寸大

标签 image vuejs2 crop

我正在实现一个系统,用户选择图像,他必须在保存之前裁剪它;我正在使用 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/

相关文章:

image - 如何在 Matlab 中找到二值图像中的所有连通分量?

vue.js - 将 "data"部分中的变量声明为 $root 的别名不是 react 性的

css - 缩放图像直到 X 或 Y 与容器相同,然后裁剪其余部分

java - 如何将图像转换为BufferedImage

image - AddThis Pinterest 小部件提供我不想提供的图像,例如导航按钮、广告。

html - 图片库出现问题

javascript - 我可以在 Vuex 的 settimeout 函数中更改并提交状态吗?

javascript - 如何将 axios.all 的响应推送到 vue 数据元素?

python - 使用OpenCV和python在较大图像中裁剪灰度图像

swift - SpriteKit 聚光灯效果