图片格式

前置概念

  • 图片格式:图片本质上也是文件,写着一些信息,是一些数据;图片用图片浏览软件打开,是软件解析文件,屏幕绘制的结果。即图片是图片信息的编码后的二进制数据,图片格式表示的是图片用何种编码方法。不同图片格式使用的编码方法不一样和有可能对图片进行压缩,如保存图片为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。

图片格式

  1. PNG(Protable Network Graphics),便携式网络图形,支持无损压缩的位图图形格式,开发目标就是用来替代GIF作为适合网络传输的格式而不需要专利许可,所以广泛应用在互联网上。
    • 根据一个像素的位数可以划分多种格式PNG 8(256种颜色)、 PNG 24(RGB三通道) PNG 32(RGB + Alpha 四颜色通道)和 RGB 48( 16 * 3通道 )、PNG 64(16 * 4通道)等
    • 无需专利
  2. GIF(Graphics Interchange Format),图像互换格式,用的是每个像素有8bit的位图。而且使用无损压缩。早期网速慢时,便于传输。可以插入多帧,做成动画;LZW算法专利收费,如何导致开发出了png。
  3. JPEG(Joint Photographic Experts Group),联合图像专家小组,也可以成为JPG,采用的时有损压缩。
  4. 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:

  1. 取得本地图片,使用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]
    }
  2. 图片绘制进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
    }
  3. 压缩: 执行canvas.toBlob(),输出低质量的图片

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    async 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种它还存在缺点:

  1. 压缩png图片时,有可能出现图片大下增大的情况,可以尝试压缩成其他格式或者缩小图片尺寸达到压缩目的

代码参考demo地址

系列推荐:

图片裁剪

图片马赛克

前端抠图?

随记

其实这里实现只要就是canvas的使用,一个是image到canvas的APIcontext.drawImage()和canvas输出图形的APIcanvas.toBlob()

搜索资料发现,图片加水印,其实就是合成图片,一张是原图,一张是水印。怎么合成?就是使用image到canvas的APIcontext.drawImage(),先绘制原图再绘制水印,两次或多次即可。大佬们厉害。

参考

最后更新: 2021年07月30日 20:15

原始链接: https://idkhts.github.io/2021/07/23/%E5%9B%BE%E7%89%87%E5%8E%8B%E7%BC%A9/