本文首先敘述一段經(jīng)歷,然后得出結(jié)論,想看結(jié)論的可以直接跳到最后
經(jīng)歷
用一張帶Alpha通道的PNG圖片作為原始輸入,然后用常用的PNG圖片壓縮工具pngquant處理得到壓縮后的圖片

Original (144 KB).png

Compressed (39 KB).png
(圖片來源: super-mario-odyssey-switch)
壓縮后圖片從144 KB減小到39KB,而且?guī)缀跤^察不到區(qū)別,但這不是本文重點
接下來使用結(jié)構(gòu)相似性算法(Structural Similarity Index,SSIM)求出兩張圖片的相似程度,主要的Python代碼如下(Python 3.8)
from skimage import io, metrics
original_image = io.imread('Original(144 KB).png')
compressed_image = io.imread('Compressed (39 KB).png')
value = metrics.structural_similarity(original_image, compressed_image, multichannel=True)
print('ssim value: %f'%value)
然而求出的相似程度居然只有69%,讓我對結(jié)果產(chǎn)生懷疑。仔細研究一番后發(fā)現(xiàn)某些像素點的RGB值在壓縮之后產(chǎn)生了非常巨大的變化。Alpha等于零的像素,無論它的RGB值是多少,該像素最終都不可見。據(jù)此推斷,壓縮算法利用這個特點,在Alpha等于零的情況下大幅調(diào)整RGB以進一步對圖像進行壓縮
因此,進行圖片相似度評價之前,應(yīng)該將RGB值預(yù)先乘以Alpha值,調(diào)整后的代碼如下
from skimage import io, metrics
def premultiply_alpha(image):
height = image.shape[0]
width = image.shape[1]
for y in range(height):
for x in range(width):
pixel = image[y, x]
alpha = pixel[3]
factor = alpha / 255
image[y, x, 0] *= factor # Red
image[y, x, 1] *= factor # Green
image[y, x, 2] *= factor # Blue
original_image = io.imread('Original(144 KB).png')
compressed_image = io.imread('Compressed (39 KB).png')
premultiply_alpha(original_image)
premultiply_alpha(compressed_image)
value = metrics.structural_similarity(original_image, compressed_image, multichannel=True)
print('ssim value: %f' % value)
最終得到圖片壓縮前后的相似性是98%
結(jié)論
回答標題的問題,PNG格式不支持Premultiplied Alpha原因(不一定準確)
- 對PNG格式而言,(0, 0, 0, 0) 與 (100, 100, 100, 0)沒有區(qū)別,因為它們最終都不可見
- 對Premultiplied Alpha而言,RGB值需要預(yù)先乘以Alpha,因此(100, 100, 100, 0)是不存在的像素,因為RGB在乘以0之后不可能還是100