图片格式
前置概念
- 图片格式:图片本质上也是文件,写着一些信息,是一些数据;图片用图片浏览软件打开,是软件解析文件,屏幕绘制的结果。即图片是图片信息的编码后的二进制数据,图片格式表示的是图片用何种编码方法。不同图片格式使用的编码方法不一样和有可能对图片进行压缩,如保存图片为jpeg格式,这种格式的编码方式是有损压缩,即可能会丢失一些信息,而png是无损压缩图不丢失(可恢复)到原来输入的数据。
- 无损压缩:指的是资料经过压缩后,信息不被破坏,还能恢复到压缩前;
- 灰度:从最暗的黑色到最亮的白色之间的各种值。
- 色彩深度或色深:指的是颜色用几位bit来表示,1位两种颜色(黑白),8位256中颜色。
- 位图:又称栅格图,表示使用像素阵列来表示图像,像素是RGB信息或者灰度值信息。位图根据位深度(像素的色彩深度)又划分多种位图:1、4、8、16、24、32等
- RGB颜色通道和Alpha通道:通常RGB表示三种颜色,R红色,G绿色,B蓝色,每种颜色通道用8bit(256种表示,一个像素拥有三种颜色通道即3*8bit为24bit,这种RGB图形称为真彩位图。若额外再加上透明度,即Alpha通道——用8bit来表示,那么一像素就是24bit + 8bit为32bit。
图片格式
- PNG(Protable Network Graphics),便携式网络图形,支持无损压缩的位图图形格式,开发目标就是用来替代GIF作为适合网络传输的格式而不需要专利许可,所以广泛应用在互联网上。
- 根据一个像素的位数可以划分多种格式PNG 8(256种颜色)、 PNG 24(RGB三通道) PNG 32(RGB + Alpha 四颜色通道)和 RGB 48( 16 * 3通道 )、PNG 64(16 * 4通道)等
- 无需专利
- GIF(Graphics Interchange Format),图像互换格式,用的是每个像素有8bit的位图。而且使用无损压缩。早期网速慢时,便于传输。可以插入多帧,做成动画;LZW算法专利收费,如何导致开发出了png。
- JPEG(Joint Photographic Experts Group),联合图像专家小组,也可以成为JPG,采用的时有损压缩。
- WebP,比较新的一种文件格式,设计目标就是减少文件大小的同时又保持图片的又PNG等质量,便于网络种传输。同时提供了有损压缩和无损压缩两种方式。
简单图片压缩的实现
正常的图片压缩,应该是算法的压缩,减少图片一些次要信息,一些颜色信息,达到压缩图片的目的。但是算法复杂度太高,前端可以借助canvas的API的toBlob的实现简单图片压缩。
canvas.toBlob(cb,type,quality)
把整个canvas图形导入为Blob对象,cb为回调函数,type为类型,默认为image/png
,quality为导出的质量;导出的图片的分辨率为96dpi
整体思路为:由input[type=file]
取得图片,把图片绘制进canvas中,使用canvas.toBlob
导出低质量的图片达到压缩的目的,写个dmeo:
取得本地图片,使用
input[type="file"]
,监听onchange
,取inputEl.files[0]
即可(只处理一张)1
2
3
4
5
6
7
8
9
10// 上传文件的元素
const uploadEl = document.querySelector('#upload')
// 待压缩的文件
let file
// 获取文件(只处理一个)
uploadEl.onchange = function (e) {
file = uploadEl.files[0]
}图片绘制进canvas:图片转换成Image元素,再由canvas读取image元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38// 读文件变成base64
function readFile(file) {
return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = function (data) {
console.log('FileReader', data)
resolve(reader.result)
}
reader.onerror = (err) => reject(err)
})
}
// 由base64赋值给image元素的src得到图片的image元素
function createImgEl(fileData) {
return new Promise((resolve, reject) => {
const img = new Image()
img.src = fileData
img.onload = function (e) {
console.log(e)
resolve(img)
}
img.onerror = (err) => reject(err)
})
}
// 图片元素imgEl绘制进canvas
function getCompressCanvas(imgEl) {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = imgEl.naturalWidth
canvas.height = imgEl.naturalHeight
ctx.drawImage(imgEl, 0, 0, canvas.width, canvas.height)
return canvas
}压缩: 执行canvas.toBlob(),输出低质量的图片
1
2
3
4
5
6
7
8
9
10
11async function compress(file, options = { type: 'image/png', quality: 0.8 }) {
const type = options.type || 'image/png'
const quality = options.quality || 0.8
const fileData = await readFile(file)
const imgEl = await createImgEl(fileData)
const canvas = getCompressCanvas(imgEl)
return new Promise((resolve, reject) => {
canvas.toBlob((blob) => resolve(blob), type, quality)
})
}
总结
图片压缩实现:图片==》file==》image元素==》canvas==》canvas减低质量输出==》图片
同时以上只是一个简单的图片压缩思路和demo,dmoe种它还存在缺点:
- 压缩png图片时,有可能出现图片大下增大的情况,可以尝试压缩成其他格式或者缩小图片尺寸达到压缩目的
代码参考demo地址
系列推荐:
随记
其实这里实现只要就是canvas的使用,一个是image到canvas的APIcontext.drawImage()
和canvas输出图形的APIcanvas.toBlob()
。
搜索资料发现,图片加水印,其实就是合成图片,一张是原图,一张是水印。怎么合成?就是使用image到canvas的APIcontext.drawImage()
,先绘制原图再绘制水印,两次或多次即可。大佬们厉害。
参考
- 了解js压缩,这一篇就够了
- 各词条参考Wiki
最后更新: 2021年07月30日 20:15
原始链接: https://idkhts.github.io/2021/07/23/%E5%9B%BE%E7%89%87%E5%8E%8B%E7%BC%A9/