JS 图片简易压缩

这是第 48 篇不掺水的原创,想获取更多原创好文,请扫 上方二维码关注我们吧~

本文首发于前端早早聊大众号:JS 图片简易紧缩

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 UreadAsDataURL 办法转化为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 中的图片目标。

JS 图片简易压缩

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)从坐标的 sxsy 开始,到图片的右下角结束)。

以下为图片制作的实例:

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);
JS 图片简易压缩

Api 中古怪之处在于,sx,sy,swiO – : w r _ Ddth,sheight 为选填参数,但方c x ; S位在 dC [ 4 D %x, dy, dWidth, dHei! z I w 8 `ght 之前。

Canvas 输出图片

调用 canvastoDataURL 办法能够输出 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

JS 图片简易压缩