ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] # RGB介绍 > RGB颜色模型: 最常见的颜色模型,设备相关。R、G、B分别代表红、绿和蓝色三种颜色通道,取值均为[0,255]。 > RGB 8位色: 表示使用8位(bit)表示颜色,一共能表示2^8 = 128种颜色。 依次类推RGB 16位色,RGB 24位色,RGB 32位色,使用的位数越多,能表示的颜色越多,24位能表示的颜色数量已经很多了,称之为“真彩色”。 > 32位和24位能表示的颜色一样多,多一个了透明度。 > Android Bitmap使用的三种颜色格式: >- ALPHA_8–每个像素占1个字节,存储透明度信息,没有颜色信息。 >- RGB_565--每个像素占2个字节存储颜色信息,R 5位,G 6位,B 5位,能表示2^16种颜色。 >- ARGB_8888--每个像素占4个字节存储颜色信息,A R G B各一个字节,能表示2^24种颜色,还有一个字节存储透明度信息。  # 压缩原理 在 `Android` 中进行图片压缩是非常常见的开发场景,主要的压缩方法有两种:其一是下 **采样压缩**,其二是 **质量压缩**。 - 前者是降低图像尺寸,改变图片的存储体积; - 后者则是在不改变图片尺寸的情况下,通过损失颜色精度,达到相同目的; ## 压缩Bitmap磁盘占用空间的大小 ```java //如果成功地把压缩数据写入输出流,则返回true。 public boolean compress( Bitmap.CompressFormat format, //图像的压缩格式; int quality,//图像压缩率,0-100。 0 压缩100%,100意味着不压缩; OutputStream stream) ;//写入压缩数据的输出流; ``` - `Bitmap.CompressFormat.PNG` ,那不管第二个值如何变化,图片大小都不会变化,不支持 `png图片` 的压缩。因为 `PNG` 格式是无损的,它无法再进行质量压缩,`quality `这个参数就没有作用了,会被忽略,所以最后图片保存成的文件大小不会有变化; - `CompressFormat.WEBP` ,这个格式是 `google` 推出的图片格式,它会比 `JPEG` 更加省空间。官方表示能节省 `25%-34%` 的空间; ## 压缩Bitmap占用内存的大小 要知道怎么压缩才能使 `Bitmap` 占用的内存变小,首先需要知道 `Bitmap` 的内存占用怎么计算。 [计算图片的内存占用](https://www.kancloud.cn/book/stven\_king/stven\_king\_android\_interview\_topic/preview/Bitmap/%E8%AE%A1%E7%AE%97%E5%9B%BE%E7%89%87%E7%9A%84%E5%86%85%E5%AD%98%E5%8D%A0%E7%94%A8.md) 这篇文章有详细讲解。 ### 使用inSampleSize进行压缩 ```java // 设置参数 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // 只获取图片的大小信息,而不是将整张图片载入在内存中,避免内存溢出 BitmapFactory.decodeFile(imagePath, options); int height = options.outHeight; int width= options.outWidth; int inSampleSize = 2; // 默认像素压缩比例,压缩为原图的1/2 int minLen = Math.min(height, width); // 原图的最小边长 if(minLen > 100) { // 如果原始图像的最小边长大于100dp(此处单位我认为是dp,而非px) float ratio = (float)minLen / 100.0f; // 计算像素压缩比例 inSampleSize = (int)ratio; } options.inJustDecodeBounds = false; // 计算好压缩比例后,这次可以去加载原图了 options.inSampleSize = inSampleSize; // 设置为刚才计算的压缩比例 Bitmap bm = BitmapFactory.decodeFile(imagePath, options); // 解码文件 ``` 图片尺寸的修改其实就是通过修改像素数,放大的过程称之为**上采样**,缩小的过程称之为**下采样**。 `Android` 使用的 `inSampleSize` 计算采样率使用的采样算法是**邻近采样(Nearest Neighbour Resampling)**, `x`(`x` 为 2 的倍数)个像素最后对应一个像素。比如采样率设置为 `1/2` ,所以是两个像素生成一个像素。邻近采样的方式比较粗暴,直接选择其中的一个像素作为生成像素,另一个像素直接抛弃。 ### 使用createScaledBitmap或Matrix ```java Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test.png"); Bitmap compress = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth()/2, bitmap.getHeight()/2, true); //或者直接使用 matrix 进行缩放,查看Bitmap.createScaledBitmap源码其实就是使用 matrix 缩放 Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test.png"); Matrix matrix = new Matrix(); matrix.setScale(0.5f, 0.5f); bm = Bitmap.createBitmap(bitmap, 0, 0, bit.getWidth(), bit.getHeight(), matrix, true); ``` 同样是图片宽高各为原来的`1/2`,这种方式采用**双线性采样(Bilinear Resampling)**,这个算法不像邻近采样算法直接粗暴的选择一个像素,而是参考了源像素相应位置周围 `2x2` 个点的值,根据相对位置取对应的权重,经过计算之后得到目标图像。 不同的采样算法会产生不同效果,除了 `Android` 中这两种常用的采样算法之外,还有比较常见如:`双立方/双三次采样(Bicubic Resampling)` 和 `Lanczos Resampling` 等。如果对 `Android` 使用的这两种采样算法效果不满意,必要时可以引入其他的算法。 ### BitmapFactory.Options三件套 > `inScaled` + `inDensity` + `inTargetDensity` 当**inScaled**设置为true时(设置此标志时),如果**inDensity**与**inTargetDensity**不为0,Bitmap就会在加载的时候直接进行缩放以匹配inTargetDensity,而不是绘制的时候进行缩放。(加载到堆内存时已经缩放了大小了,`.9图` 会忽略此标志) **inDensity**:加载图片的原始宽度,如果此密度与`inTargetDensity`不匹配,则在返回Bitmap前会将它缩放至目标密度。 **inTargetDensity** :目标图片的显示宽度,它与`inScaled`与`inDensity`结合使用,确定如何在返回`Bitmap`前对其进行缩放。 [计算图片的内存占用](https://www.kancloud.cn/book/stven_king/stven_king_android_interview_topic/preview/Bitmap/%E8%AE%A1%E7%AE%97%E5%9B%BE%E7%89%87%E7%9A%84%E5%86%85%E5%AD%98%E5%8D%A0%E7%94%A8.md) 这篇文章中尝试将相同图片加载放到不同的 `drawable-dpi` 的文件目录下去加载到内存中的 `Bitmap` 大小不同,其原因就是 `inDensity` 和 `inTargetDensity` 不一致导致。 ***** 文章到这里就全部讲述完啦,若有其他需要交流的可以留言哦~!~! 想阅读作者的更多文章,可以查看我 [个人博客](http://dandanlove.com/) 和公共号:![振兴书城](https://imgconvert.csdnimg.cn/aHR0cDovL3VwbG9hZC1pbWFnZXMuamlhbnNodS5pby91cGxvYWRfaW1hZ2VzLzEzMTk4NzktNjEyYzRjNjZkNDBjZTg1NS5qcGc?x-oss-process=image/format,png)