旗下品牌:
石家庄网站开发 石家庄网站开发公司

资讯动态

察而思、思而行、行而后语、知行合一

【前端技术】JS压缩图片的思路

发布时间:2024-09-20 热度:

在开发中,相信很多人都做过图片上传相关功能。然而,在图片上传过程中,文件体积问题常常被忽视。若直接上传原图片,可能因体积较大导致上传速度慢,且前端渲染时也会比较迟缓,极大地影响用户体验。因此,在不影响清晰度的前提下,前端可以在上传前对图片大小体积进行压缩,调整到合适大小后再进行上传。本文将详细介绍前端 JS 如何实现图片压缩,有需要的小伙伴赶紧收藏起来吧!

原理(必看)

简而言之:主要利用 canvas 的 drawImage 方法先将图片绘制为 canvas 图像,再通过 toDataURL 转化为 DataURL 来存储图片链接。

drawImage 简单介绍

Canvas 2D API 中的 CanvasRenderingContext2D.drawImage () 方法提供了多种在画布(Canvas)上绘制图像的方式。

用法可参考:CanvasRenderingContext2D.drawImage () - Web API 接口参考 | MDN (mozilla.org)。

语法如下:

drawImage (image, dx, dy);

drawImage (image, dx, dy, dWidth, dHeight);

drawImage (image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

我们使用第二种语法进行绘制,参数含义如下:

image:要绘制到上下文的元素。

dx:image 的左上角在目标画布上的 X 轴坐标。

dy:image 的左上角在目标画布上的 Y 轴坐标。

dWidth:image 在目标画布上绘制的宽度,可对绘制的 image 进行缩放。若不指定,绘制时 image 宽度不会缩放。

dHeight:image 在目标画布上绘制的高度,可对绘制的 image 进行缩放。若不指定,绘制时 image 高度不会缩放。

简单示例

注意:随意修改图像尺寸可能导致图像失真。我们可以先获取图像资源的原始尺寸,然后进行等比缩放。即当确定设置宽度后,高度要进行等比调整,可依据交叉相乘积相等的公式进行计算。

例如,如果宽度设置为 500,那么高度也应进行等比缩放。公式为:naturalWidth * X = naturalHeight * 500,由此可计算出高度 X = naturalHeight * 500 /naturalWidth。

以下是代码示例:

javascript

复制

var can = document.querySelector('canvas');

var context = can.getContext('2d');

var imgDom = new Image();

imgDom.src = './img.jpg';

imgDom.onload = function () {

    // 注意:图像绘制时,必须保证资源已经加载完成

    console.log('图片的原始宽度', imgDom.naturalWidth);

    console.log('图片的原始高度', imgDom.naturalHeight);


    context.drawImage(

        imgDom,

        0, 0,

        500, imgDom.naturalHeight * 500 / imgDom.naturalWidth

    );

};

toDataURL 简单介绍

将图片绘制到 canvas 后,还需将 canvas 转化为 Data URL。转化为 DataURL 后,可以在屏幕上显示,也可存储到后端服务器。使用 canvas 提供的 toDataURL 实例方法即可。

官方解释:HTMLCanvasElement.toDataURL () 方法返回一个包含图片展示的 data URI。

参考:HTMLCanvasElement.toDataURL () - Web API 接口参考 | MDN (mozilla.org)。

语法:canvas.toDataURL (type, encoderOptions);

其中,type(可选)为图片格式,默认为 image/png;encoderOptions(可选)在指定图片格式为 image/jpeg 或 image/webp 的情况下,可以从 0 到 1 的区间内选择图片的质量。若超出取值范围,将使用默认值 0.92,其他参数会被忽略。

简单示例

javascript

复制

// 获取压缩后的图片数据

can.width = imgDom.naturalWidth;

can.height = imgDom.naturalHeight;


const compressedData = can.toDataURL('image/jpeg', 0.6); // 可调整质量参数

console.log('compressedData: ', compressedData);

转化后的 DataURL 结果如下。

实现

先给出全部代码,再进行解释。

html

复制

<!DOCTYPE html>

<html>

<head>

    <title>图片压缩上传</title>

    <meta charset="UTF-8">

</head>

<body>

    <input type="file" id="fileInput" accept="image/*">

    <button onclick="compressAndUpload()">压缩并上传图片</button>

    <canvas id="canvas" style="display: none;"></canvas>

    <script>

        function compressAndUpload() {

            const fileInput = document.getElementById('fileInput');

            const file = fileInput.files[0];

            if (!file) {

                alert('请先选择要上传的图片');

                return;

            }

            const reader = new FileReader();

            reader.onload = function () {

                const img = new Image();

                img.src = reader.result;

                img.onload = function () {

                    const canvas = document.getElementById('canvas');

                    const ctx = canvas.getContext('2d');

                    const maxWidth = 800; // 设置最大宽度为 800 像素

                    let width = img.width;

                    let height = img.height;


                    // 判断是否需要缩放

                    if (width > maxWidth) {

                        height *= maxWidth / width;

                        width = maxWidth;

                    }

                    // 设置 canvas 的宽高

                    canvas.width = width;

                    canvas.height = height;


                    // 将图片绘制到 canvas 上

                    ctx.drawImage(img, 0, 0, width, height);

                    // 获取压缩后的图片数据

                    const compressedData = canvas.toDataURL('image/jpeg', 0.7); // 可调整质量参数


                    // 创建一个新的压缩后的 File 对象

                    const compressedFile = dataURItoBlob(compressedData, file.type);

                    compressedFile.lastModifiedDate = file.lastModifiedDate;

                    compressedFile.name = file.name;


                    // 上传压缩后的图片文件

                    uploadImage(compressedFile);

                };

            };

            reader.readAsDataURL(file);

        }


        function dataURItoBlob(dataURI, mimeType) {

            const binary = atob(dataURI.split(',')[1]);

            const array = [];

            for (let i = 0; i < binary.length; i++) {

                array.push(binary.charCodeAt(i));

            }

            return new Blob([new Uint8Array(array)], { type: mimeType });

        }


        function uploadImage(compressedFile) {

            const formData = new FormData();

            formData.append('image', compressedFile);


            fetch('/upload', {

                method: 'POST',

                body: formData

            })

           .then(response => {

                if (response.ok) {

                    console.log('图片上传成功');

                } else {

                    console.error('图片上传失败');

                }

            })

           .catch(error => {

                console.error('发生错误:', error);

            });

        }

    </script>

</body>

</html>

下面分析关键代码部分。

首先,初始化一个 reader,它是 FileReader 对象的实例。reader.readAsDataURL(file)这行代码将选择的文件读取为 Data URI 格式的字符串。执行这行代码时,FileReader 对象会异步读取文件数据,读取完成后触发 onload 事件,读取结果存储在 FileReader 对象的 result 属性中,格式为 Data URI 字符串。

接着,将读取出来的 Data URI 字符串赋值给 Image 的 src,等待 img 加载完毕后开始对 img 进行压缩,压缩方法如上文所示。

然后,设置最大宽度为 800,判断当前图片宽度是否大于该值,若大于则进行缩放计算,小于则不进行等比缩放计算。最后将计算出的值使用 drawImage 绘制到 canvas 上面。

现在,将 canvas 转化成 Data URI 字符串,canvas.toDataURL('image/jpeg', 0.7)这行代码将 canvas 上绘制的图像数据导出为 JPEG 格式的 Data URI 字符串,并设置图像质量为 0.7。

之后,创建一个新的压缩后的 File 对象,通过将 Data URI 字符串转化为 Blob 对象来实现。

最后,使用 FormData 进行上传即可。

压缩前后体积对比

我们看一下压缩前后体积对比,压缩前为 550290,压缩后为 31523,缩小了十几倍,压缩效果非常明显。

总结

前端实现图片压缩主要借助 canvas 来完成。实现思路是先使用 canvas 的 drawImage 方法将图片绘制为 canvas 图像,再结合 toDataURL 转化为 DataURL 进行存储图片链接以及压缩图像质量。在 toDataURL 中可以调整图像质量,同时,在压缩图像时要注意等宽高缩放,否则会导致图像失真。


联系尚武科技
客户服务
石家庄APP开发
400-666-4864
为您提供售前购买咨询、解决方案推荐等1V1服务!
技术支持及售后
石家庄APP开发公司
0311-83796180
为您提供从产品到服务的全面技术支持 !
客户服务
石家庄小程序开发
石家庄小程序开发公司
加我企业微信
为您提供售前购买咨询、
解决方案推荐等1V1服务!
石家庄网站建设公司
咨询相关问题或预约面谈,可以通过以下方式与我们联系。
石家庄网站制作
在线联系:
石家庄Web开发
石家庄软件开发
石家庄软件开发公司
ADD/地址:
河北·石家庄
新华区西三庄大街86号河北互联网大厦B座二层
Copyright © 2008-2024尚武科技 保留所有权利。 冀ICP备12011207号-2 石家庄网站开发冀公网安备 13010502001294号
Copyright © 2024 www.sw-tech.cn, Inc. All rights reserved