每个开发者都应该了解的位图






4.48/5 (19投票s)
这是一篇关于位图基础知识的简短博文,对大多数人来说已经足够,对其他人来说也是一个很好的起点。
引言
几乎所有的开发者在编程时都会用到位图。或者即便不在编程中使用,也会在网站、博客或家庭照片中用到。然而,我们中的许多人并不知道 GIF、JPEG 或 PNG 文件之间的权衡——它们之间存在着巨大的差异。这是一篇关于基础知识的简短博文,对大多数人来说已经足够,对其他人来说也是一个很好的起点。我学到的这些大部分是在游戏开发(包括 Enemy Nations)时,那时你需要深入理解图形。
位图
位图基本上存储了每个像素的颜色。但其中有三个关键组成部分:
- 存储颜色值本身。我们大多数人都熟悉 RGB,它存储每个颜色的红、绿、蓝分量。这实际上是最有效的方法,因为人眼对某些颜色光谱的细微差别比其他颜色更敏感。同时,对于许多常见的颜色操作,如提亮,它也是效率低下的。但对于大多数常见的编程任务来说,它是最简单的,因此已成为标准。
- 每个像素的透明度。这对于非矩形图像的边缘至关重要。一条对角线为了达到最佳效果,将是线条颜色和下方像素颜色的一种组合。每个像素都需要设置其透明度(或实际是不透明度)级别,从 0%(显示下方像素)到 100%(仅显示图像中的像素)。
- 位图元数据。这是关于图像的信息,可以从颜色表和分辨率到图像的拥有者。
压缩
位图需要大量数据。或者更确切地说,它们会占用大量字节。多年来,压缩一直是新的位图格式的主要驱动力。压缩有三种形式:调色板缩减、有损和无损。
在早期,调色板缩减是最常见的方法。有些程序使用黑白位图,每像素 1 位。现在这已经很难满足需求了。到了 Windows 3.1 时代,16 色图像(每像素 4 位)仍在使用。但主要的用法是每位图 8 位/256 色。这 256 种颜色会映射到位图的一部分调色板,而该调色板为每个条目保存一个 24 位颜色。这使得程序可以选择最能显示图片的整个颜色光谱中的 256 种颜色。
这种方法相当不错,但对于表面过渡非常缓慢的平面来说,效果不佳。同时,它在网络和窗口操作系统早期遇到了一个主要问题——因为显卡也是 8 位系统,整个屏幕只有一个调色板。对于拥有整个屏幕的游戏来说没问题,但对于来自不同来源的图像共享屏幕时就不行了。解决办法是创建了一个标准的网络调色板,大多数浏览器等会在出现调色板冲突时使用该调色板。
最后,有一些中间解决方案,例如 16 位/像素,它提供了整个光谱,但粒度很粗,人眼可以看到色调变化的跳跃。由于内存价格下降,显卡在一年内迅速从 8 位跳到 24 位,这种方法使用很少。
接下来是有损压缩。压缩是找到文件中重复的模式,然后在第二种情况下,只需指向第一个运行。如果你有一行 20 个像素,而第二个运行的唯一区别是两个像素比第一个红了 1 的值?人眼看不到这种差异。所以你将第二个运行改为与第一个匹配,然后,你就可以压缩它了。大多数有损压缩方案允许你设置有损级别。
当使用单一颜色来表示透明度时,这种方法有一个严重的问题。如果该颜色移动了一位,它就不再是透明的了。这就是为什么有损格式几乎专门用于图片,而从不在游戏中使用。
最后是无损。这是程序对图像进行压缩,而不丢失任何信息。我不会深入探讨它的原理,只是想指出压缩图像比解压缩图像花费的时间要多得多。所以显示压缩图像——快。压缩图像——不那么快。这可能导致出于性能原因,你不想在实时过程中以无损格式存储。
透明度
透明度有三种形式。(如果你认识创作网络内容的艺术家——让他们读读这一部分。令人惊讶的是,有多少人对此问题感到困惑。)第一种是无——位图是一个矩形,会遮挡它下面的所有像素。
第二种是位图,其中指定的颜色值(大多数使用品红色,但也可以是任何颜色)表示透明。因此,其他颜色被绘制,品红色像素不被绘制,从而显示下方的像素。这需要将图像渲染在选定的背景色上,边缘像素应该是部分图像和部分背景像素,然后它们会部分变为背景色。你在 256 色图标中看到这种情况,它们在白色背景上有完美的边缘,但在黑色背景上边缘却有一种奇怪的白色光晕效果。
第三种是每像素 8 位透明度(即,0-100% 的 256 个值)。这就是所谓的 32 位位图;它是 24 位颜色和 8 位透明度。这提供了人眼无法分辨的更精细的渐变。与艺术家交谈时要有一个警告——他们都能制作“32 位位图”。但其中 95% 的人制作的位图中,每个像素的不透明度都设置为 100%,并且对整个过程和透明度的需求一无所知。(游戏艺术家是一个显著的例外——他们一直都在这样做。)一个如何正确操作的好例子,可以看看 Icon Experience——我认为他们的位图非常出色。
分辨率
许多格式都有分辨率,通常用 DPI(每英寸点数)描述。查看照片时,这通常不是问题。但以位图渲染的图表为例。你希望图表中的文本可读,并且希望它能在 600 DPI 打印机上清晰打印,但在屏幕上,你希望占用一英寸的 600 个点只显示 96 个像素。分辨率提供了这种能力。有些格式不存在 DPI,有些格式是可选的(注意:任何格式都不是必需的,但 PNG 很少缺失)。
DPI 的重要之处在于,在渲染位图时,用户可能希望能够放大和/或以打印机的分辨率打印,但以较低的分辨率显示——你需要为调用程序提供设置 DPI 的能力。有一个非常强大的图表程序,除了标准显示器观看外,几乎没有用处——因为它以 96 DPI 渲染,仅此而已。不要限制你的用途。
文件格式
好的,那么你应该使用什么文件格式呢?我们按从最有用到最不有用的顺序排列。
- PNG - 32 位(或更低),无损压缩,文件体积小——有什么不喜欢的呢?某些旧版浏览器(如 Internet Explorer)会以偏白色显示透明像素,但新版本处理得很好。将此(32 位模式,使用 8 位进行透明度)用于一切。
- ICO - 这是用于表示桌面应用程序等的图标文件。它是位图的集合,每个位图都可以是任何分辨率和位深。对于这些,使用 16x16 到 256x256 的 32 位 PNG 文件构建。如果你的操作系统或应用程序需要较低的位深,它会在运行时进行缩减——并保留 8 位透明度。
- JPEG - 仅 24 位(即无透明度),有损(可以是无损,但压缩效果会大打折扣),文件体积小。除非你有大量用户使用旧浏览器,否则没有理由使用这种格式。它不是一种糟糕的格式,但它不如 PNG,没有任何优势。
- GIF - 8 位,无损(但 8 位通常意味着退化),文件体积非常小。GIF 有两个独特的功能。首先,你可以在单个文件中放置多个 GIF 位图,并在每个之间设置延迟。然后它会播放这些,给你一个动画位图。这在所有浏览器(回溯到 0.9 版本)上都能工作,并且文件体积比 Flash 文件小。另一方面,它只有 8 位,在当今世界,这往往显得不好(尽管有些艺术家可以仅用 8 位创造出令人惊叹的东西)。它还有一个固定的颜色作为透明色,因此它原生支持透明度(开/关的类型)。如果你想要动画位图而又不想有 Flash 的开销,或者带宽是主要问题,那么这个很有用。
- BMP(也称为 DIB)- 从 1 位到 32 位无损(但低于 24 位通常意味着退化),文件体积大。有一种情况应该使用它——当速度是首要问题时。许多 2D 游戏程序,尤其是在当前的图形卡出现之前,会以 BMP/DIB 格式存储所有位图,因为不需要解压缩,而在尝试以 60 帧/秒的速度显示游戏时,节省时间至关重要。
- TIFF - 32 位(或更低),无损压缩,文件体积小——而且不比 PNG 好。基本上,政府和一些大公司认为他们需要一个“标准”,以便将来的软件仍然可以读取这些旧文件。这个论点毫无意义,因为 PNG 符合要求。但对于一些客户(如联邦政府),他们会选择 TIFF 而不是 PNG。当客户要求时使用此格式(但否则使用 PNG)。
- 其他所有格式——过时。如果你正在创建一个位图编辑器,那么请务必支持读取/写入所有现有的格式。但对于其他用途——坚持使用上面提到的 2+4 种格式。
另一种观点
下面的评论引发了关于不同位图格式的良好讨论。这绝对是一个“群体智慧”的例子。总结一下下方的观点:
- 始终使用适合你用途的格式(我同意)。
- 即使在高带宽的世界里,高流量的网站也会发现 JPEG(相对于 PNG)文件体积的减小非常有价值。
- JPEG 是摄影界和现实生活图片(YouTube 嵌入式截图)的首选,并且很可能在可预见的未来一直如此。
- TIFF 对于某些特定用例非常有价值,包括压缩的黑白文档图像。另一个人也不同意 TIFF 过时的说法(但同意它确实过时了)。
- GIF 在很少的情况下可以胜过其他格式。(我认为大多数人都同意我,GIF 正在走向消亡。)
我从评论中吸取了两点。首先,JPEG 可能与 PNG 一起继续广泛使用。它在不断发展,这对它的未来是一个好兆头。其次,我们可能会一直有人使用历史上发明的每一种位图格式。
是的,这篇文章是关于位图的入门,而不是百科全书。但它不是“你应该知道的一切”;而是“每位开发者都应该知道的”——换句话说,它是每个人都应该知道的基础信息。话虽如此,我认为对于那些刚开始接触位图编程的人来说,这是一个非常好的基础。
最初发布于:每位开发者都应该了解的位图知识。