Mark Xu 的博客

记录精彩的程序人生

Android 图片加载(一)-- 图片基础知识

图片加载在 Android 应用开发中,也算是很重要的一块了。移动设备的内存都是很宝贵的,而图片又是内存占用大户,所以如何优化图片加载,优化 App 内存占用,是一个 Android 开发工程师的基本必备技能了。最近准备写一系列图片加载相关的文章,查漏补缺,提升自己的开发实力。

图片的本质

题图是台风 “山竹” 来临前一天拍摄的,晴空万里,五彩缤纷,异常宁静。这张图使用手上的红米手机拍摄,原图尺寸为 4000 * 3000px,存储大小为 5.32M(本文有对该图进行裁剪)。图片是人对视觉感知的物质再现。说简单点,比如我们看到眼前的风景很漂亮,想把它分享给大家看,此时可以拿手机或相机把它拍下来,当然你也可以使用画笔把它画在画布上。这样后面我们就可以拿出手机或者画布再次欣赏了。

我们拿手机把风景拍下来,它是如何在手机中存储的呢?当我们想要欣赏时,又是如何加载出来的呢?本文我们来一一揭开图片的秘密。

图片是由像素点组成的,每一个像素点表达一种颜色,那么世间总共有多少种颜色呢,貌似就那么几种,也貌似数不清。其实,对于一张图片来说,有多少种颜色是固定的。

我们知道,每种颜色都是由红、黄、蓝三基色合成而组成。可以这么理解,我们在拍摄(绘制)一副画时,是一个一个像素点进行绘制,每个像素点需要蘸取红色、黄色、蓝色的涂料进行绘制,每次蘸取的每种颜色涂料量都是不一样的,所以有了五彩缤纷的颜色。

图片的加载

当我们想在手机中欣赏拍摄的照片时,是需要将相应的图片加载到手机内存中的,那么在不做任何处理的情况下,直接加载一张图片需要的内存空间是多大呢?

占用内存空间 = 横向像素点数 * 纵向像素点数 * 一个像素点占用的内存大小

这个公式大家应该都比较熟悉了,那么一个像素点所占用的内存大小是多少?

颜色模式

我们通常使用的 RGB 颜色模式,是通过对红 (R)、绿(G)、蓝(B) 三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的。在 Android 中还有包含透明度 Alpha 通道的颜色模型,即 ARGB。除了 RGB 模式,还有 YUV 模式等应用于其他领域。

前面说到,在绘制每一个像素点时,蘸取的红黄蓝三种颜色的量是不同的,在计算机世界里,模拟出了红、黄、蓝三个通道,每个通道有一个颜色值。

色彩深度可以来描述图像能够包含的最大色彩数,色彩深度越大,能够描述的颜色数越多,描述出来的颜色越接近于实际颜色。经常使用的色彩深度为 24 位色,把每一种红色进行编号,从 0 号开始一直到 255 号。在计算机看来是 00000000 - 11111111,需要 8 位二进制才可以描述到底是几号红色,黄蓝同理。所以描述一个 24 位颜色需要 24 位的空间。

24 位色的图片加载到内存中时,需要内存空间来描述每个像素点的颜色值,每一个像素点需要 24 位,也就是 3 个字节的空间来描述这个像素点到底是什么颜色。

Android 中 Bitmap 支持如下几种色彩深度:

public enum Config {
    ALPHA_8     (1),
    RGB_565     (3),
    @Deprecated
    ARGB_4444   (4),
    ARGB_8888   (5),
    RGBA_F16    (6),
    HARDWARE    (7);
    final int nativeInt;
    //...
}

其中:

  • ALPHA_8 仅存储透明通道,不存储颜色
  • RGB_565 不含透明通道,红色占 5bit,绿色占 6bit,蓝色占 5bit,共 2 个字节。适用于不透明,对颜色质量要求不高的图片
  • ARGB_4444 由于颜色质量过低,目前已不推荐使用,包含透明通道,透明通道和红黄蓝各占用 4bit,推荐使用 ARGB_8888 代替
  • ARGB_8888 包含透明通道,每个通道各占用 8bit,共 4 个字节。颜色质量好,推荐在各种可能的情况下使用

所以,文中上图如果不经处理直接展示,所占用的内存为:

4000 * 3000 * 4 = 48,000,000 Byte = 46875 KB = 45.77 MB

图片的存储

上文图片直接加载到内存中需要 45 兆的空间,而它在我手机中保存着的时候,却仅仅占用了 5.32 兆。为什么呢?因为有压缩算法啊。下面我们来看看 Android 开发中常见的几种图片存储格式。

JPEG、PNG 与 Webp

我们先来看看无损压缩和有损压缩的区别:

  • 有损压缩的特点是删除图像中的部分颜色,我们在看一张图片时,大脑会根据丢失颜色附近的颜色自动进行脑补。有损压缩的图片查看时无法准确还原原图
  • 无损压缩的特点是相同信息的颜色只保存一次,渐变的颜色采用差异值及更复杂的算法来进行记录,无损压缩过的文件可以准确的还原出原图

JPEG、PNG 大家应该都很熟悉了,在这里说下二者的区别:

  • JPEG 使用有损压缩,只有 RGB 三通道,无透明通道
  • PNG 使用无损压缩,有 PNG8、PNG24、PNG32 三种
  • PNG8 可以描述 2^8-1 种颜色,外加 1 位透明通道。PNG8 将图片所用到的每种颜色存储在一个长度为 255 的数组中,每个像素点记录的该像素点颜色在数组中的索引值。此处还有点问题?
  • PNG24 可以描述 2^24 种颜色,无透明通道
  • PNG32 可以描述 2^24 种颜色,外加 8 位透明通道,即 2^8 种透明值

WebP 是谷歌主导的一种图片压缩格式,具有更优的图像压缩算法,使得图片体积更小,拥有肉眼识别无差异的图像质量,在 Android 开发中对于一些大图、引导图等可以进行使用,可以有效减小安装包体积。在此处安利下腾讯的图片转换工具 -- 智图,很好用。

留下你的脚步