JS图⽚压缩原理与实现⽅法详解
⽬录
前⾔
压缩思路
优缺点介绍
代码实现
Input 上传 File 处理
Canvas 处理 File 对象
Api 解析:drawImage
Canvas 输出图⽚
Api 解析:toDataURL
a 标签的下载
Api 解析:download
⾮主流浏览器下载处理
Api 解析:atob
Api 解析:Uint8Array
Api 解析: Blob
Api 解析:createObjectURL
Api 解析: window.navigator
总结
本⽂实例讲述了JS 图⽚压缩原理与实现⽅法。分享给⼤家供⼤家参考,具体如下:
前⾔
说起图⽚压缩,⼤家想到的或者平时⽤到的很多⼯具都可以实现,例如,客户端类的有图⽚压缩⼯具 PPDuck3, JS 实现类的有插件 compression.js ,亦或是在线处理类的 OSS 上传,⽂件上传后,在访问⽂件时中也有图⽚的压缩配置选项,不过,能不能⾃⼰撸⼀套 JS 实现的图⽚压缩代码呢?当然可以,那我们先来理⼀下思路。
压缩思路
涉及到 JS 的图⽚压缩,我的想法是需要⽤到 Canvas 的绘图能⼒,通过调整图⽚的分辨率或者绘图质量来达到图⽚压缩的效果,实现思路如下:
获取上传 Input 中的图⽚对象 File
将图⽚转换成 base64 格式
base64 编码的图⽚通过 Canvas 转换压缩,这⾥会⽤到的 Canvas 的 drawImage 以及 toDataURL 这两个 Api,⼀个调节图⽚的分辨率的,⼀个是调节图⽚压缩质量并且输出的,后续会有详细介绍
转换后的图⽚⽣成对应的新图⽚,然后输出
优缺点介绍
不过 Canvas 压缩的⽅式也有着⾃⼰的优缺点:
优点:实现简单,参数可以配置化,⾃定义图⽚的尺⼨,指定区域裁剪等等。
缺点:只有 jpeg 、webp ⽀持原图尺⼨下图⽚质量的调整来达到压缩图⽚的效果,其他图⽚格式,仅能通过调节尺⼨来实现
代码实现
<template>
<div class="container">
<input type="file" id="input-img" @change="compress" />
<a :download="fileName" :href="compressImg" rel="external nofollow" >普通下载</a>
<button @click="downloadImg">兼容 IE 下载</button>
<div>
<img :src="compressImg" />
</div>
</div>
<script>
export default {
name: 'compress',
data: function() {
return {
compressImg: null,
fileName: null,
};
},
components: {},
methods: {
compress() {
// 获取⽂件对象
const fileObj = document.querySelector('#input-img').files[0];
// 获取⽂件名称,后续下载重命名
this.fileName = `${new Date().getTime()}-${fileObj.name}`;
// 获取⽂件后缀名
const fileNames = fileObj.name.split('.');
const type = fileNames[fileNames.length-1];
// 压缩图⽚
this.handleCompressImage(fileObj, type);
},
handleCompressImage(img, type) {
const vm = this;
let reader = new FileReader();
// 读取⽂件
let image = new Image(); //新建⼀个img标签
image.src = sult;
let canvas = ateElement('canvas');
let context = Context('2d');
// 定义 canvas ⼤⼩,也就是压缩后下载的图⽚⼤⼩
let imageWidth = image.width; //压缩后图⽚的⼤⼩
let imageHeight = image.height;
canvas.width = imageWidth;
canvas.height = imageHeight;
// 图⽚不压缩,全部加载展⽰
context.drawImage(image, 0, 0);
// 图⽚按压缩尺⼨载⼊
// let imageWidth = 500; //压缩后图⽚的⼤⼩
/
/ let imageHeight = 200;
// context.drawImage(image, 0, 0, 500, 200);
// 图⽚去截取指定位置载⼊
// context.drawImage(image,100, 100, 100, 100, 0, 0, imageWidth, imageHeight); vmpressImg = DataURL(`image/${type}`);
};
};
},
// base64 图⽚转 blob 后下载
downloadImg() {
let parts = thispressImg.split(';base64,');
let contentType = parts[0].split(':')[1];
let raw = window.atob(parts[1]);
let rawLength = raw.length;
let uInt8Array = new Uint8Array(rawLength);
for(let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
navigator标签const blob = new Blob([uInt8Array], {type: contentType});
thispressImg = ateObjectURL(blob);
if (window.navigator.msSaveOrOpenBlob) {
// 兼容 ie 的下载⽅式
window.navigator.msSaveOrOpenBlob(blob, this.fileName);
}else{
const a = ateElement('a');
a.href = thispressImg;
a.setAttribute('download', this.fileName);
a.click();
}
},
}
};
上⾯的代码是可以直接拿来看效果的,不喜欢⽤ Vue 的也可以把代码稍微调整⼀下,下⾯开始具体分解⼀下代码的实现思路Input 上传 File 处理
将 File 对象通过FileReader的readAsDataURL⽅法转换为URL格式的字符串(base64编码)
const fileObj = document.querySelector('#input-img').files[0];
let reader = new FileReader();
// 读取⽂件
Canvas 处理 File 对象
建⽴⼀个 Image 对象,⼀个 canvas 画布,设定⾃⼰想要下载的图⽚尺⼨,调⽤ drawImage ⽅法在 canvas 中绘制上传的图⽚
let image = new Image(); //新建⼀个img标签
image.src = sult;
let canvas = ateElement('canvas');
let context = Context('2d');
context.drawImage(image, 0, 0);
Api 解析:drawImage
context.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
img
就是图⽚对象,可以是页⾯上获取的 DOM 对象,也可以是虚拟 DOM 中的图⽚对象。
dx , dy , dWidth , dHeight
表⽰在 canvas 画布上规划出⼀⽚区域⽤来放置图⽚,dx, dy 为绘图位置在 Canvas 元素的 X 轴、Y 轴坐标,dWidth, dHeight 指在 Canvas 元素上绘制图像的宽度和⾼度(如果不说明,在绘制时图⽚的宽度和⾼度不会缩放)。
sx , sy , swidth , sheight
这 4 个参数是⽤来裁剪源图⽚的,表⽰图⽚在 canvas 画布上显⽰的⼤⼩和位置。sx,sy 表⽰在源图⽚上裁剪位置的 X 轴、Y 轴坐标,然后以 swidth,sheight 尺⼨来选择⼀个区域范围,裁剪出来的图⽚作为最终在 Canvas 上显⽰的图⽚内容(swidth,sheight 不说明的情况下,整个矩形(裁剪)从坐标的 sx 和 sy 开始,到图⽚的右下⾓结束)。
以下为图⽚绘制的实例:
context.drawImage(image, 0, 0, 100, 100);
context.drawImage(image, 300, 300, 200, 200);
context.drawImage(image, 0, 100, 150, 150, 300, 0, 150, 150);
Api 中奇怪之处在于,sx,sy,swidth,sheight 为选填参数,但位置在 dx, dy, dWidth, dHeight 之前。
Canvas 输出图⽚
调⽤ canvas 的 toDataURL ⽅法可以输出 base64 格式的图⽚。
Api 解析:toDataURL
图⽚格式,默认为 image/png。
encoderOptions 可选
在指定图⽚格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图⽚的质量。如果超出取值范围,将会使⽤默认值 0.92。其他参数会被忽略。
a 标签的下载
调⽤ <a> 标签的 download 属性,即可完成图⽚的下载。
Api 解析:download
// href 下载必填
<a download="filename" href="href" rel="external nofollow" > 下载 </a>
filename
选填,规定作为⽂件名来使⽤的⽂本。
href
⽂件的下载地址。
⾮主流浏览器下载处理
到此可以解决 Chroma 、 Firefox 和 Safari(⾃测⽀持)浏览器的下载功能,因为 IE 等浏览器不⽀持 download 属性,所以需要进⾏其他⽅式的下载,也就有了代码中的后续内容
// base64 图⽚转 blob 后下载
downloadImg() {
let parts = thispressImg.split(';base64,');
let contentType = parts[0].split(':')[1];
let raw = window.atob(parts[1]);
let rawLength = raw.length;
let uInt8Array = new Uint8Array(rawLength);
for(let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
const blob = new Blob([uInt8Array], {type: contentType});
thispressImg = ateObjectURL(blob);
if (window.navigator.msSaveOrOpenBlob) {
// 兼容 ie 的下载⽅式
window.navigator.msSaveOrOpenBlob(blob, this.fileName);
}else{
const a = ateElement('a');
a.href = thispressImg;
a.setAttribute('download', this.fileName);
a.click();
}
}
将之前 canvas ⽣成的 base64 数据拆分后,通过 atob ⽅法解码
将解码后的数据转换成 Uint8Array 格式的⽆符号整形数组
转换后的数组来⽣成⼀个 Blob 数据对象,通过ateObjectURL(blob)来⽣成⼀个临时的 DOM 对象
之后 IE 类浏览器可以调⽤window.navigator.msSaveOrOpenBlob⽅法来执⾏下载,其他浏览器也可以继续通过 <a> 标签的download 属性来进⾏下载
Api 解析:atob
base-64 解码使⽤⽅法是 atob()。
必需,是⼀个通过 btoa() ⽅法编码的字符串,btoa()是 base64 编码的使⽤⽅法。
Api 解析:Uint8Array
new Uint8Array(length)
length
创建初始化为 0 的,包含 length 个元素的⽆符号整型数组。
Api 解析: Blob
Blob 对象表⽰⼀个不可变、原始数据的类⽂件对象。
// 构造函数允许通过其它对象创建 Blob 对象
new Blob([obj],{type:createType})
obj
字符串内容
createType
要构造的类型
兼容性 IE 10 以上
Api 解析:createObjectURL
静态⽅法会创建⼀个 DOMString。
objectURL = ateObjectURL(object);
object
⽤于创建 URL 的 File 对象、Blob 对象或者 MediaSource 对象。
Api 解析: window.navigator
// 官⽅已不建议使⽤的⽂件下载⽅式,仅针对 ie 且兼容性 10 以上
// msSaveBlob 仅提供下载
// msSaveOrOpenBlob ⽀持下载和打开
window.navigator.msSaveOrOpenBlob(blob, fileName);
blob
要下载的 blob 对象
fileName
下载后命名的⽂件名称。
总结
本⽂仅针对图⽚压缩介绍了⼀些思路,简单的使⽤场景可能如下介绍,当然也会引申出来更多的使⽤场景,这些还有待⼤家⼀起挖掘。
上传存储图⽚如果需要对⽂件⼤⼩格式有要求的,可以统⼀压缩处理图⽚
前台页⾯想要编辑图⽚,可以在 Canvas 处理图⽚的时候,加⼀些其他逻辑,例如添加⽂字,剪裁,拼图等等操作
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论