---
参考链接: "[ASTC图片压缩技术浅析 - 知乎](https://zhuanlan.zhihu.com/p/1898042738022285491)"
参考链接2: "[深入理解ASTC](https://zhuanlan.zhihu.com/p/707250800)"
tags:
  - ASTC
  - 压缩
---
# 浅析

### ASTC是什么

有了上面的简单说明铺垫，接下来正式介绍一下ASTC是什么：
	ASTC（[Adaptive Scalable Texture Compression](https://zhida.zhihu.com/search?content_id=256803808&content_type=Article&match_order=1&q=Adaptive+Scalable+Texture+Compression&zhida_source=entity)）是一种高级纹理压缩技术，由 ARM 和 AMD共同开发。其设计目标是提供更高效的压缩率和更高的图像质量，并且支持多种块尺寸和位深度。
	ASTC的核心优势在于其可变块大小系统，支持从4x4到12x12的任意大小块（包括非正方形块），以及3D纹理的压缩和广泛的硬件支持。这种技术能够适应不同的纹理特征和压缩率需求，从而在保持图像质量的同时，显著减少纹理数据的大小。

### 常规的压缩方法
- **减少颜色数量**：图片是由许多像素组成的，每个像素都有一个颜色值。常规压缩技术会减少颜色的数量，比如把256种颜色减少到16种，然后用这16种颜色来近似原来的颜色。这样，存储颜色信息的数据量就减少了。根据权重算出Block里主要颜色，相似的颜色用这个主要颜色来储存，达到减少颜色的目的。
- **去除冗余信息**：图片中往往有很多重复的内容，比如一片蓝色的天空。压缩技术会识别这些重复的部分，只存储一次，然后在需要的地方引用它，这样也能减少数据量。

### ASTC核心思想
- **根据不同区域的特点，灵活地选择压缩方式**
	- **分块处理**：ASTC把图片分成很多小块，每个小块独立处理。就像把大画分成很多小区域一样，每个小块可以根据自己的内容选择合适的压缩方式。
	- **自适应性**：对于简单的内容（比如一片纯色的天空），ASTC可以用很少的颜色来表示；对于复杂的内容（比如人物的面部细节），ASTC会用更多的颜色来保持细节。这种自适应性使得ASTC在保持较高图像质量的同时，还能实现较高的压缩率。

### ASTC压缩算法工作原理
- 将这张大图切成很多小块。
	- ASTC允许我们选择块的大小，比如选择块的大小为4x4，那么512x512的大图就会被切成（512x512）➗（4x4）=16384块。再比如选择块的大小为8x8，512x512的大图就会被切成4096块。
	- 这里要注意一个点，**ASTC中，无论每个块覆盖的像素数量是多少，大小都固定为128比特（16字节）**。
- 选择颜色
	- 对于已经切割好的每个矩形块，ASTC算法会智能地选择两个颜色端点，来定义这个矩形块里的颜色范围（比如一块天空的颜色主要是浅蓝到深蓝，那么两个端点就是浅蓝色和深蓝色）；有时候矩形块里的颜色比较多样，ASTC算法就会使用更多的颜色端点，来代表整个方块的颜色范围。
- 颜色渐变
	- 在选择了颜色端点后，ASTC算法会通过插值计算每个像素的颜色。值插值方法通常是线性的，即根据像素在块内的位置，计算其颜色值在两个端点之间的比例。例如，靠近浅蓝色端点的像素会更接近浅蓝色，而靠近深蓝色端点的像素会更接近深蓝色。
	- 对于包含许多颜色的块，ASTC则会使用多维插值的方法。例如，如果一个块中有红色、绿色和蓝色的渐变，ASTC会分别在红、绿、蓝三个颜色通道上进行插值，以生成更自然的颜色过渡。
- 存储信息
	- 对于每一个矩形块，记录下它的颜色端点，插值权重以及其他的辅助信息。
	- 在存储时，还会采用更高效的编码方式来存储这些信息。例如，颜色端点可以使用较少的位数来表示，而插值权重则根据块内颜色的复杂度动态分配位数。这种编码方式确保了数据量的最小化，同时尽可能保留图像的视觉质量。
	- 除了颜色端点和插值权重，ASTC还会存储一些索引信息，用于快速定位每个像素的颜色值。这些索引信息通常以紧凑的格式存储，进一步减少了数据量。
	- BISE（Bounded Integer Sequence Encoding）
		- 这个是ASTC压缩算法里面一个很核心的算法，它的基本原理就是用一串一定范围内数值大的数来表示一串固定数量的数值小的数，Color Endpoint和weight的数据都是用这种方式编码的。
		- 这里首先抛开ASTC，先把BISE说清楚。举例来说会更清楚:
			- 比如现在有三个数字需要编码{40，50，70}，一般情况下，我们可能想到的使用二进制来编码这三个值，这三个值在128以内，所以，可以每个数用7bit来编码，那么也就是需要21bit位。那这里我们可以用BISE来减少编码的位数，以此来压缩数据量。BISE会把数分为高位和地位，高位使用Trits（三进制）或者Quints（五进制）来表示，多少值范围内的数如何分割表示是有个最佳实践的，这里可以查表来确定，为了简单，这里直接给出例子中的结论，它们是在80（查找表中的固定值）以内的数字，所以使用4bit的Bits表示低位，高位用Quints来表示。那它们的低位就是{101000，110010，1000110}，这个直接编码就可以了，高位的值为{2，3，4}，然后把这三个值拼到一个大数值上，因为高位用Quints表示的，三位的Quints就能表示125（5*5*5）以内的数字，我们可以用7bit（128）来表示，这样原本要24（3\*8）bit的三个数字就用了4\*3 + 7 = 19bit来表示了。
- 解压缩
	- 当需要在屏幕上显示这张画布时，解压缩算法会读取每个块的压缩数据，恢复颜色端点和插值权重。然后，根据这些信息，通过插值计算每个像素的颜色值，从而重建出原始图像。
	- 这里需要了解ASTC的一个重要特点：**硬件加速**。现代GPU通常内置了对ASTC解压缩的支持，能够快速高效地解压缩图像数据，从而在不显著增加计算负担的情况下，实现高质量的图像显示。

### ASTC压缩使用建议
目前使用人数比较多的工具是 Arm ASTC Encoder（astcenc）
可以从这里获取 [https://github.com/ARM-software/astc-encoder.git](https://link.zhihu.com/?target=https%3A//github.com/ARM-software/astc-encoder.git)
其主要的特点有：支持BMP、JPEG、PNG、TGA等多种图像格式；提供多种质量预设；开源
在使用ASTC技术时，需要合理选择块大小和平衡视觉质量，以下是一些建议：
- 一般情况的合适的块大小
	- 4×4块：适用于颜色变化复杂或细节丰富的区域，如**法线贴图**或**高精度纹理**。这种块大小可以提供较高的图像质量，但压缩率较低。
	- 5×5或6×6块：**适合一般的纹理，很多手游都用这个**，能够在质量和压缩率之间取得较好的平衡。
	- 8×8、10×10、12×12块：适用于尺寸较大但细节要求不高的纹理，如**背景图或大面积的填充纹理**。这些块大小可以显著提高压缩率，但可能会牺牲一些图像质量。
- 考虑纹理类型
	- 法线贴图：建议使用4×4或5×5的块大小，以避免丢失过多细节。
	- 带Alpha通道的贴图：推荐使用5×5的块大小。
	- 无Alpha通道的贴图：可以选择8×8的块大小。