[关闭]
@TryLoveCatch 2022-05-05T09:41:56.000000Z 字数 2336 阅读 644

Android知识体系之Bitmap压缩原理

Android知识体系


基础知识

RGB颜色模型

RGB颜色模型是最常见的颜色模型,设备相关。R、G、B分别代表红、绿和蓝色三种颜色通道,取值均为[0,255]。

RGB 8位色: 表示使用8位(bit)表示颜色,一共能表示2^8 = 128种颜色。

Android Bitmap的图片编码格式

如果我们以ARGB_8888作为基准来进行对比

压缩原理

在Android中进行图片压缩是非常常见的开发场景,主要的压缩方法有两种:
其一是下采样压缩,降低图像尺寸,改变图片的存储体积;
其二是质量压缩,在不改变图片尺寸的情况下,通过损失颜色精度,达到相同目的。

下采样压缩

图片尺寸的修改其实就是通过修改像素数,放大的过程称之为上采样,缩小的过程称之为下采样。
在这里,我们只讨论下采样。下采样压缩是通过减少图片的像素数的来减小Bitmap内存占用。

使用Options.inSampleSize

  1. BitmapFactory.Options options = new BitmapFactory.Options();
  2. options.inSampleSize = 2 ;
  3. Bitmap bitmap = BitmapFactory.decodeFile( "/sdcard/test.png" );
  4. Bitmap compress = BitmapFactory.decodeFile( "/sdcard/test.png" , options);

当采样率为inSampleSize = 2时,Bitmap内存宽高各减少一半,内存占用是不缩放情况下的1/4。

这种方式使用的采样算法是邻近采样(Nearest Neighbour Resampling)

x(x 为 2 的倍数)个像素最后对应一个像素。
比如采样率设置为1/2,所以是两个像素生成一个像素。
邻近采样的方式比较粗暴,直接选择其中的一个像素作为生成像素,另一个像素直接抛弃。

举例:一个200*200白黑像素相间的图片,sampleSize=2,原图和采样图的对比如下:

使用createScaledBitmap或Matrix

  1. Bitmap bitmap = BitmapFactory.decodeFile( "/sdcard/test.png" );
  2. Bitmap compress = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth()/ 2 , bitmap.getHeight()/ 2 , true );
  3. 或者直接使用 matrix 进行缩放,Bitmap.createScaledBitmap源码其实就是使用 matrix
  4. Bitmap bitmap = BitmapFactory.decodeFile( "/sdcard/test.png" );
  5. Matrix matrix = new Matrix();
  6. matrix.setScale( 0 .5f, 0 .5f);
  7. bm = Bitmap.createBitmap(bitmap, 0 , 0 , bit.getWidth(), bit.getHeight(), matrix, true );

同样是图片宽高各为原来的1/2,这种方式采用双线性采样(Bilinear Resampling)

这个算法不像邻近采样算法直接粗暴的选择一个像素,而是参考了源像素相应位置周围 2x2 个点的值,根据相对位置取对应的权重,经过计算之后得到目标图像,距离越近对目标像素影响越大。

同样使用一个200*200白黑像素相间的图片作采样测试:

小结

不同的采样算法会产生不同效果,除了 Android 中这两种常用的采样算法之外,还有比较常见如:双立方/双三次采样(Bicubic Resampling) 和 Lanczos Resampling等。如果对Android使用的这两种采样算法效果不满意,必要时可以引入其他的算法。

质量压缩

质量压缩的原理损失颜色精度,不减少图片本身的像素,它在保持像素的前提下该变图片的位深以及透明度,来达到压缩图片的目的,压缩后的文件大小会有所改变,但是导入成 bitmap后所占内存是不会变化的,由于要保持像素不变,所以它无法无限压缩,达到一个极限值后就不会继续变小了。

所以这个方法,不适合缩略图,也不适合想通过压缩图片来减少内存的占用。它仅仅适用在想保证图片质量的前提下,同时减少文件大小的情况而已。

  1. ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  2. //quality 为0~100,0表示最小体积,100表示最高质量,对应体积也是最大
  3. bitmap.compress(Bitmap.CompressFormat.JPEG, 80 , outputStream);

参考

https://blog.csdn.net/TO_BE_RM/article/details/79859540
https://blog.csdn.net/u013620306/article/details/123654927

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注