怎样有效压缩图片?图片压缩的基本原理

发布日期:2020-06-04 13:49

图片格式

在计算机领域中,图片可分为两大类,一类是位图,一类是矢量图。

位图比较容易理解,又称点阵图/像素图,由许多的"点"构成,这些"点"就是我们常说的"像素"。在位图模式下,计算机会保存图片的每个像素点。当位图放大到一定程度时,我们就可以看到图片上的一个个小方块(像素点),比如一张8px*8px的图片,就有64个像素点。位图的常用后缀:

1.jpg(Joint Photographic Experts Group),有损压缩图片格式,只有颜色没有透明度,它用有损压缩方式去除冗余的图像和彩色数据,在获得极高的压缩率的同时能展现十分丰富生动的图像,也就是说,它可以用较少的磁盘空间得到较好的图片质量。

2.png(Portable Network Graphics),便携式网络图形,是一种无损压缩的位图片形格式。PNG使用从LZ77派生的无损数据压缩算法,压缩比高,生成文件体积小。

3.gif(Graphics Interchange Format),图形交换格式,用于以超文本标志语言(Hypertext Markup Language)方式显示索引彩色图像,在因特网和其他在线服务系统上得到广泛应用,主要用于动图。

4.bmp(bitmap),是Windows操作系统中的标准图像文件格式。这种格式的特点是包含的图像信息较丰富,几乎不对数据进行压缩,但也因此导致bmp格式的图片体积太大,主要应用于各种Windows应用程序。

相比较位图,矢量图则抽象一些,是计算机图形中用点,直线或者多边形等基于数学方程的几何图元表示的图像。例如规定起点,终点和颜色,控制计算机画一条直线。这样计算机存储非常少的内容就能显示一根无限长的直线或者其他图案,特别适用于文字设计、图案设计、版式设计、标志设计、计算机辅助设计(CAD)、工艺美术设计、插图等。

矢量图常用后缀有.ai、.cdf、.swf等,都是一些设计软件或者UI软件自定的格式,矢量图因为本身就是通过数学函数计算出来的图片,所以它的占用空间比较小,不存在压缩问题,主要缺点是兼容性差,几乎每种矢量图都要用特定的标准软件打开。


图片显示和压缩

本文主要介绍位图压缩,这里介绍几个概念:

1.色深


色深指的是每一个像素点用多少bit来存储ARGB值,属于图片自身的一种属性。色深可以用来衡量一张图片的色彩处理能力。

图片的色深越大,能展示的不同颜色越多,比如ARGB8888用8bit的色深,每一个属性占有2的8次方位变化,能展现1677万(256*256*256)种颜色和256种透明度,被称为真彩色。而缩水的ARGB4444用16bit的色深,只能展现4096(16*16*16)种颜色和16种透明度,色彩表现能力极为寒酸,已被建议弃用。处于两者之间的还有显示器领域的6bit显示器,能展现2的6次方种颜色26万(64*64*64)种颜色,而RGB565用节省色深为ARGB的一半,但是去掉透明度,把颜色分配给红绿蓝三个颜色,能展现65536(32*64*32)种颜色,虽然不高,但是对色彩要求不高的图片中已经够用。而高端显示器已经开始用10bit来存储单个颜色,能展现的色彩类别超过了10亿种(1024*1024*1024)。

2.位深


指的是在对Bitmap进行压缩存储时存储每个像素所用的bit数,主要用于存储。由于是“压缩”存储,所以位深一般小于或等于色深。jpg,png等图片就是通过压缩算法把较大的色深转换为较小的位深去存储,显示图片,把加载到内存中处理的时候,大小会还原为它相应格式的色深。

3.ARGB


Alpha Channel代表透明度,Red三原色中的红色,Green三原色中的绿色,Blue三原色中的蓝色。

位图的完整大小有个很简单的计算方法,就是宽度乘以高度乘以色深。bmp图片没有进行压缩,它的大小基本上符合这个公式,所以bmp适合作为原始文件存储,方便处理,不适合传播。

jpg是有损压缩,直接抛弃透明度,也就是ARGB中的A不存,直接抛弃,大小减少四分之一,另外对图片进行DCT变换(离散余弦变换),舍弃高频系数,一般保存的是图像的边界、纹理信息(又抛弃一部分不存),保留低频信息,主要是保存的图像中平坦区域信息。然后通过量化表存储处理后的每个位的色值,再用霍夫曼编码减少常用字节的存储空间占用量。这样一张图就可以压缩到很小,很可能是原图的10%-30%。(jpg后来也推出了无损压缩方式,但是不常用)

png的是无损压缩,压缩过程分为两个阶段:Prediction和Compression。Prediction每次会处理图片中一行的数据,首先过滤一遍这一行中每一个的像素点中每条通道的值,也就是ARBG。再交给差分处理器来重新计算该通道的值。差分处理会根据这个像素点上通道和之前或者之上像素点对应通道值之间的差异,进行差分编码,也就是说,如果原本相邻像素点之间通道的值之间很接近,那么我们就会获得很多的1,0,-1这种很小的值。这里有两点需要注意:整个Prediction阶段的目的,也就是选择合适的差分处理器,让最终的编码结果出现尽可能多的零值和重复值,这样需要存储的内容会非常小。差分编码器比较的是像素点之间对应通道的值,而并不是整个像素点。在Prediction处理完毕之后进行Compression,将Prediction的转换的结果输出给Deflate,Deflate执行真正的压缩操作,它会通过LZ77和霍夫曼编码对图像进行处理。最后将处理之后的结果保存。

gif的也是无损压缩,它生成单图的时候压缩效率不如png,所以基本上不会用来做单图展示,主要用来做动图。因为是动图,也就是连续几帧相似的图片依次播放,相邻的图片的变化会很小,所以gif把一张图所用到的颜色用LZW压缩算法生成调色盘,调色盘是对各帧用到的颜色的索引,只有256种常用颜色(其他颜色通过字符串存储),比原始色值要小很多,因为动图每一帧的相似性很高,所以这个索引的复用率也会很高,另外gif会对比每一帧无变化的部分,只有第一帧存储完整的信息,后面的帧都直接无视和前面帧相同的部分,只存储变化的部分。


总结

因为图片的原始大小是宽乘以高乘以色深,所以最直观的压缩方式是对宽高进行压缩,特别是图片用于展示的时候,手机拍出的照片都是4K级别的(手机的镜头比较差,但是为了堆参数会把摄像头做到1200万像素,1600万像素,最近小米还自嗨1亿像素),但是不论是手机还是电脑,屏幕分辨率很少有达到这个级别的,所以如果单纯的为了展示图片,完全可以压缩到2k或者1080p的分辨率。

色深压缩在一些场景下也是有必要的,针对一些网页和app的使用场景对色彩要求不高,但是对文件大小要求较高,并不需要1677万真彩色,也不是所有图片都需要透明度,如果只是一个普通的图片,不追求色彩丰富,RGB565的6万色显示,人眼有时候也很难察觉到与1677万色的区别。

除了上述基本压缩方式,还有各种图片标准用一堆算法和编码进行组合的方式来压缩,可以根据实际情况选择jpg,png,gif,还有谷歌出的webp等格式,比如jpg适合网站和app的素材用途,那些素材大部分颜色单一没有透明度,png适合大部分对图片有一定要求的场景,动图则用gif,而webp号称压缩算法比gif和png好,压缩率更高。另外png和gif的压缩都是针对行进行扫描压缩的,所以宽高比大的图片会比宽高比小的图片压缩率更高。

不论是什么语言什么算法实现的图片压缩,一定绕不开宽度,高度,色深三个基本参数,这三个参数越小图片的大小上限就越小。在上述三个值确定的基础上,压缩的方式则可以概况为这几个思路:
  • 抛弃部分对质量影响不大的数据(有损压缩)
  • 采用霍夫曼等编码方式减少常用色值的存储大小
  • 采用差分算法借用相邻色值的结果减少附近相似色值的存储大小