Vue-Advanced-cropper裁剪大小的图像大于原始图像

发布于 2025-01-30 18:34:38 字数 210 浏览 6 评论 0原文

我正在实施一个系统,用户选择图像,他必须在保存之前裁剪它;我使用Vue-Advance-Cropper插件;所有系统均已设置,但结果图像尺寸大于原始系统。

示例:i在307KO插入图像,我得到448KO;我在40ko上插入图像,我获得了206KO;

是否有任何选择使结果尺寸要小于原件的尺寸要小,或者没有什么可以做什么?

I'm implementing a system where user choose image, he must crop it before save; i'm using vue-advance-cropper plugin; all system is setted up but the result image sized is bigger than the original;

example: i insert image at 307ko i got 448ko; i insert image at 40ko i got 206ko;

is there any option that i missed to make the result lesser size than the original or is there not anything can be done?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

帅气称霸 2025-02-06 18:34:38

摘要

我想所描述的问题与使用的库没有任何常见。

在裁剪图像格式和原始图像格式之间的差异中,裁剪图像大小大于原始图像大小的最常见原因。

澄清它。如果您上传JPEG图像,请裁剪并从 toblob 方法,您将默认情况下获得png图像,因此显然它将比原始图像更大在大多数情况下。

那是因为toblob从画布创建了一个全新的图像,并且对原始图像属性一无所知。因此,您无法通过这种方法的性质创建原始图像的确切副本,包括其大小。

好消息是您可以更接近原始图像。

toblob方法具有以下签名:

toBlob(callback)
toBlob(callback, type)
toBlob(callback, type, quality)

因此,您可以设置相同的类型和图像质量的合理值。

解决方案

vue-advanced-cropper文档。我将显示它的完整版本:

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)
        }
    }
};

此示例将帮助您使Cropper结果大小非常接近原始图像大小。您可以在带有上面代码的较轻版本。

Abstract

I suppose that the described problem has nothing common with the used library.

The most common reason that a cropped image size is larger than an original image size in the difference between a cropped image format and an original image format.

To clarify it. If you upload a jpeg image, crop it and get it from the cropper canvas by toBlob method, you will get a png image by default, so it's obviously will be larger than an original image in the most of cases.

That's because toBlob creates a completely new image from the canvas and it know nothing about original image properties. So you can't create the exact copy of the original image, including its size, by the nature of this approach.

The good news is that you can get closer to an original image.

The toBlob method has the following signature:

toBlob(callback)
toBlob(callback, type)
toBlob(callback, type, quality)

So, you can set the same type and the reasonable value of an image quality.

Solution

There is the image uploading example in the vue-advanced-cropper documentation. I will show the full version of it bellow:

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)
        }
    }
};

This example will help you make the cropper result size pretty close to the original image size. You can test it online in the sandbox with the lighter version of the code above.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文