这是第 48 篇不掺水的原创,想获取更多原创好文,请扫 上方二维码关注我们吧~
本文首发于前端早早聊大众号:JS 图片简易紧缩
前言
说起图片紧缩,我们想到的或许平常用到的许多工具都能够完成,例如,客户端类的有图片紧缩工具 PPDuck3, JS 完成类的有插K t : 9 b , , c [件 compression.js ,亦或是在线处Z t ! , w r理类的 OSS 上传,文件上传后,在访问文件时中也有图片的紧缩装备选项,H j s 2 Y S K N不过,能不能自己撸一套 JS 完成的图片紧缩代j x @ Q 7 J ! 6码呢?当然能够,那我们先来理一下思路。
紧缩思路
涉及到 JS 的图片紧缩,我的想法是需求用到 Canvas 的绘图才能,经过调整图片的分辨率或许绘图质量来到达2 W K u ` t q g 5图片紧缩的效果,完成思路如下:
- 获取上传 Input 中的图片目标 File
- 将图片转化成 base64 格局
- base64 编码的图片经过 Canvas 转化紧缩,这里会用到的 Canvas 的 drawImage 以及 toDataURL 这两个 Api,一个调理图片的分辨率的,一个是调理图片紧缩质量并且输出的,后续会有详细介绍
- 转* a ? 3 ( 2化后的图片生成对应的新图片,然后输出
优缺陷介绍
不过 Canvas 紧缩的办法也有着自己的优缺V * G } l { T W I陷:
- 长处:完成g U ^ h u ( H简略,参% ~ N s O :数能够装备化,自界说图片的尺度,指定区域裁剪等等。
- 缺陷:只有 jpeg 、webp 支撑原图尺度下图片质量的调整来到达紧缩4 % C P { t n 6 u图片的效果,其他图i U _ 片格局,仅能经过调理尺A s F $度来完成
代码完成
&[ G hlt;template>
<div class="container">
<inpu * E ^ j at type="file" id="input-img" @change="compress" /? . l n>
<a :download=w S q b G ~ D P"fileName" :hre* m c wf="https://juejin.im/post/5ea574cc518825736eD / N57fcca/compressImg" >普通下载</a>
<button @click=": V W 8downloadImg">兼容 IE 下载</butto` K I ] l ( # /n>
<div>
<img :src="https://juejin.i2 D M L 2 1m/post/5ea57! T { A X4cc518825736e57fcca/compressImg" />
</div>
</div>
</template>
<script>
export default {
name: 'compress',
data: fuK ) S i B i 3nction() {
return {
compressImF L . Mg: null,
fileName: null,
};
},
components: {},
methods: {
compress() {
// 获取文件目标
const fil~ 0 6 TeObj = document.querySelector('#input-img').files[0];
// 获取文件名称,后续下载重命名
this.fileName = `${new Date().getTime()}-${fileObj.name}`;
//6 4 f ) ! W 获取U L I Z 4 3 d v 3文件后缀名
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();
// 读取文件
reader.readAsDataURL(img);
reader.onlm t { / a ` A _ Zoad = fun{ 6 w G Q T %ction(e) {
let image = new Image(); //新建一个img标签
image.src = e.target.result;
image.onload = function() {
let canvas = don f 7 0 mcument.createElemG X s Oent('canvas');
let context = canvas.getContext('2d'A c M 0 = 1);
// 界说 canvas 巨细,也就是紧缩后下载的图片巨细
let imageWidth = image.width; //紧缩后图片的巨细
let imageHeight = image.he= | F G a % ~ight;
canvas.width =K n I h t imageWidth;
canvas.height = image5 ) v 4 |Height;
// 图片不紧缩,全部加载展现
context.drawImage(image, 0, 0)m r } *;
// 图片按紧缩尺度载入
// let imageWidth = 500; //紧缩A 8 c后图片的巨细
// let imageHeight = 200;
// context.drawImage(image, 0, 0, 500, 200);
// 图片去截取指定方位载入
// context.drawImage(image,100, 100, 100, 100, 0, 0, imageWidth, imageHeight);
vm.compressImg = canvas.toDataURL(`image/${type}`);
};
};
},
// base6E e X ? ! b M l 24 图片转 blob 后下载
downloadImg() {
let parts = this.compressImg.split(';base64,');
let contentType = parts[0].split(':')[1];
let ra0 B X T I = 4 ;w = window.atob(parts[1]^ f F ? z ( N q);
let rawLength = raw.length;
let uInt8Array = new Uint8Array(rawLength);
for(let i = 0; i < rawLen : Q 7ngth; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
const blob = new BlV G ] U v W x V Mo# D / Cb([uInt8g c b x X xArray], {type: contentType});
this.compressImg = URL.createObjectURL(blob);
if (window.navigator.msSaveOA v brOpenBlob) {
// 兼容 ie 的下载办法
window.navigator.msSaveOrOpenBlob(blob, this.fileName);
}else{
const a = document.crT Z yeateElement('a');
a.href = tu ` B R Uhis.compress. B d 4 ! G W 7Img;
a.setAttribute('download', this.fileName);
a.click();
}
},
}
};
</script>
上面的代码是能够e 7 d J G @ u直接拿来看效果的,不喜欢用 Vue 的也能够把代码略微调整一下,下面开始详细m k +分解一下代码的完成思路。
Input 上传 File 处理
将 File 目标经过 FileReaderH 1 U
的 readAsDataURL
办法转化为URL格局的字符串(base64编码)。
consy h ht fileObj = document.querySelector('#input-Q s } J m o qimg').files[0];
let reader = new FileReader();
// 读取文件
reader.readAsDataURL(fileObj);
Canva} # Ps 处理 File 目标
树立一个 Image
目标,一个 canvas
画布,设定自己想要下载的图片尺度,调用o f n E W # u * drawImage
办法在 canvas 中制作上传的图片。
let image = new Image(); //新建一个img标签
image.src = e.target.r* V 5 x F c N result;
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
Api 解析:dp $ 8 u { ? L * .rawImage
context.drawImage(img, sx, sy, sWidth, sHeight, dM X x 8 J v M w 1x, dy, dWidth, dHeight);
img
就是图片目标,能够是页面上获取的 DOM 目标,也能够是虚拟 DOM 中的图片目标。
dx , dy , dWidth , dHeight
表明在 canvas
画布上规划处一片区域用来放置! p m n图片,dx, d8 e 3 i / ~ ay
为绘图方位在 Canvas 元素的 X 轴、Y 轴坐标,dWidth, dHeight
指在 Canvas 元素上制作图画的宽度和高度(假如不阐明, 在制作时图片的宽度和高度不会缩放V 1 @ 2 b v I p)。
sx , sy , swidth , sheight
这 4 个参数是用来裁剪源图片* ! i 3 v的,表明图片在 canvas
画布上显现的巨细和方位q F & + U T [ &。sx,sy
表明在源图片上裁剪方位的 XP { V $ . 轴、Y 轴坐标,然后以 swidth,sheight
尺度来挑选一个区域规模,裁剪出来的图片作为最终在 Canvas 上显现的图片内容( swiI X 7 y J Y %dth,sheight
不阐明的情况下,整个矩形(裁剪0 x ] z { B ` H)从坐标的 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,swiO – : w r _ Ddth,sheight 为选填参数,但方c x ; S位在 dC [ 4 D %x, dy, dWidth, dHei! z I w 8 `ght 之前。
Canvas 输出图片
调用 canvas
的 toDataURL
办法能够输出 base64 格局的图片。
canvas.toDataU= 3 r r ` Z %RL(`image/${type}`);
Api 解析:toDataURLu j y
ca. X ) R G ` v J `nvas.toDataURL(type, encoderOptions);
type 可选
图片格局,默认为 image/pnS ] Fg。
encoderOptions 可选
在指定图片格局为 image/jpeg 或 image/webps } o m 4 J L :的情况下,能够从 0 到 1 的区间0 v j内挑选图片的质量。假如超出取值规模,将会运用默认值 0.92。其他参数会被疏忽。
a 标签的下载
调用 <a>
标签的 downY N )load
特点,即可完成图片的下载。
Api 解析:download
// href 下载必填
<a download="filename" href="https://juejin/ x [ i r.im/post/5ea574cc518825736u ? e N je57fc8 ( ~ A Z Hca/href"> 下载 </a>
filename
选填,规定作为文件名来运用的文本H n Y L @ z o (。
href
文件的下载地@ E [ w a ] x D p址。
非主流浏览器下载处理
到此能够处理 Chroma 、 Firefox 和 Safari(自测支撑) 浏览器的下载功用,因为 IE 等浏览器不支撑 download
特点,所以需求进行其他办法的下载,也就有了代码% ] 0 [ ( 9中的后续内容。
// base64 图片转 blob 后{ E E { ! 1 c v 4下载
doB L !wnloadImg() {
let parts = this.compressImg.split(';base64,');
let contentType = parts[0].split(':')[1];
let raw = window.atob(parts[1]);
let rawLength = raw.length;
l A d Z N ? }et uIY K 0 u dnt8Array = new Uint8Array(rawLength);
for(let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeo b H ; k 6 hAt(i);
}
const blob = new Blob([uInt8Array], {type: contentType});
this.compress f $Img3 Y $ % ( ; ~ = URL.creatk q 9eObjectURL(blob);
if (window.navigator.msSaveOrOpenBlob) {
// 兼容 ie 的下载办法
window.navigator.msSaveOrOpenBlob(bl^ J z X g 8 l y kob, this.fileName);
}else{
const a = document.createElement('a');
a.href = this.compressImg;
a.setAttribute('download', this.fileName);
a.click();
}
}
- 将之前
canvas
生成的 base64 数据拆分后,经过ato_ = Z q Nb
办法解码 - 将解码后的数据转化成 Uint8A+ B ` U s G : ` Prray 格局的无符号整形数组
- 转化后的数组来生成一个 Blob 数据} { t ( n ^ } K x目标,经过
URL.createObjectURL(blob)
来生成一个临时的 DOM 目标 - 之后 IE 类浏览器能够调用
window.na7 [ A r , j +vigator.msSaveOrOpenBlob
办法来执行下载,其他浏览器也能够持续经过<a>
标签的downloa& T R y l r $ {d
特点` f e D ] 4来进行下_ V w A 1载
Api 解析:atob
base-64 解码? T A I I G X k c运用办法是 ato8 : 2 2 ( =b()。
window.atob(encodedStr)
encodedStr
必需,是一个经过 btoa() 办法编码的字符串,btoa()是 base64 编码的运用办法。
Api 解析:l f d rUint8Array
ne$ R K N I v & Owr Z d c Uint8Array(length)
length
创建初始化为 0 的,包括 lengthO 5 D ^ N 9 个元素的无符号整型数组。
Api 解析: Blob
Blob
目标表明一个不可变、原始数据的类文件目标。
//E Y P U $ 2 结构函数允许经过其它目标创建 Blob 目标
new Blob([obj],{type:createType})
obj
字符串内容
createType
要结构的类型
兼容性 IE 10 以上
Api 解析:createObjectURL
静态办法会创建一个Q * d z DOMString。
objeN 4 P % % [ Q BctURL = URL.createObjecto C , CURL(object);
object
用于创建 URL 的 File 目标、Blob 目标或许 MediaSourcd ; Ee 目标。
Api 解析: window.( | Q 4 6 e Wnavigator
// 官方已不建议运用的文件下载办法,仅针对 ie 且兼容性 10 以上
// msSaveBlob 仅提供下载
// msSaveOrOpenBlob 支撑下载和翻开
window.navigator.msSaveOrOpenBlob8 c = v(blob, fileNam? W z a b ?e);
blob
要下载的 blob 目标
fileName
下载后命名的文件名称。
总结
本文仅针对图片紧缩介绍了一些思q H 3 T o路,简略的运用场景或许如下介绍,当然也会引申出来j 0 z更多的运用场景,这些还有待我们一同挖b R 7 D掘。
- 上传G | A存储图片假如需求对文件巨细格局有要求的,能够统一紧缩处理图片
- 前台页面想要修改图片,能够在 Canvas 处理图片的时候,加一些其他逻辑,例如添加文字,取舍,拼图等等1 J S r j ,操作
当然温馨提示:因部分接$ ` ` Y I / ^ ?口有 IE 兼容性问题,IE 浏览器方面,仅能支撑 IE10 以上版本进行下载。
引荐阅览
或许是最全的 “文本溢出截断省掉” 方案合集
图文并茂,为你揭开“单点登录“的神秘面纱
招贤纳士
政采云前端团队(ZooTeam),一个年青赋有热W _ b H _ 7 o : [情和发明力的前端团队,隶属于政采云产品研发部R 2 = H U u,Base 在风景如画的杭州d @ P C 8 0 , 4 e。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工a 4 4 h程师,妥妥的z ? 3 g C b青年风暴团。成员构成既有来自于阿里、p 3 – ? [ H ( r y网易的“老”兵,也有浙大、中科大、杭电等D – , t @ ] F校的应届新人。团队在日常的事务对接之外,还在物料体系、工程平台、建立f Z E U i q平台、性能体验、云端使用、数据分析及可视化等方向进行技术探究x p ^和实战,推进并落地了一系B # Q + k K列的内部技术产品,持续探究前端技术体系的新边界。
假如你想改动一直被事折腾,期望开始能折腾事f H w S w c;假如你想改动一直被告诫需求多些想法,却无从破局;假如你想改动你有才能去做成那个v x L & L 0 d成果,却不需求你;假如你想改动你想做成的事需求一个团队去支撑,但没你带人的方位;假如你想改动既定的节奏,将会是“ 5 年工作时刻 3 年工作经验”;假如你想改动本来领悟不U 2 e错,但总是有那一层窗户纸的含糊… 假如你信任信任的力气,信任平凡人能成果非凡事,信任能遇到更好的自己。假如你期望参加到跟着事务腾飞的进程,亲手推进一个有着深入的事务了解、完善的技术体系、技术发明价值、影响力M L . =外溢的前端团队的成长进程,我觉得我们该聊聊。任何时刻,等着你写点什么,发给 ZooTeam@cai-inc.com