关于PNG的一个谜题

发表于2017-11-13
评论0 4.1k浏览

翻译:袁笠凯(°Sinmere)    审校:王成林(麦克斯韦的麦斯威尔)


上一篇文章太长了,涵盖的东西太多了。这一篇我们只研究一个问题。

如果要显示感知上(视觉上)的“半灰色”,在一张sRGBPNG图片里存储的值应该是多少呢?是0.5alpha值吗?

假如你是一个对PNG和图像感知以及alpha的绝对专家,这就是你需要的所有信息。对于这个问题,确保你能达成以下共识:

1、在屏幕上感知为半灰色的值是(187187187),而不是(128,128,128)。下面我们会使用JohnHabel文章中的图片证实这一点。

2、PNG的颜色是存储在sRGB空间。鲜少会有gamma = 1.0png格式会被使用

3、alpha值是线性的PNG规范指出,gamma值对alpha采样值没有影响,alpha采样在不透明时一直会是线性的

4、PNG的alpha值总是不关联的,它们不会与其颜色值进行预乘。如果以黑色为底色显示sRGBPNG颜色时,你必须用未关联Alpha的颜色值来相乘


那么,你要在PNG图片中存储什么信息才能使用alpha0.5的值来显示半灰色呢?这里会有一些提示,而答案在下面的图片下面。

水平纯黑线和纯白线相结合构成半灰色,即187代表的颜色,这是在sRGB空间的效果:

John Hable的图片

提示#1alpha值为1.0(完全不透明)的半灰色存储在PNG中为(187187187255)。

提示#2:如果PNG可以存储一个预乘颜色,答案是(187187187128)。

提示#3如果把一个预乘颜色转换成一个独立的颜色,只需用它的alpha值除以这个颜色

就是,我希望我知道你和答案只有一步之遥。

答案是(255255255128),由麦克·查克(网名friedlinguini)在我的文章评论区提出 - 见下方的评论。我的答案是明显不对的,当然我会解释为什么是这个答案。

PNG说明书提到这种计算应使用亮度样本(而不是gamma编码的样本)。因此,要显示的sRGB编码的PNG,必须做到以下几点:

1.  转换sRGB色彩为线性空于(255255255128),这是1.0,1.0,1.0)。

2.  现在乘以alpha,得到一个线乘以128/255 - > 0.5得到了(0.5,0.5,0.5)。

3.  转换此值回sRGB然后示。得到187187187)要示的色。

我觉得使用sRGB值和alpha值的PNG是通过简单地将sRGB值和其中存储的alpha值相乘显示的。错误!至少,在规范中是这样。我的思路为何如此疯狂?因为我测试的每一个查看器和浏览器都告诉我PNG就是这样显示的。

所以,我很高兴地发现PNG的的世界并没有崩溃; 它只是没有人正确地实现它。如果你确实知道一些软件,程序会显示此图像正确(您的浏览器没有),让我知道-这将是我的事情应该如何工作的例子。

更新:事实上Jim Blinn早在18年前就认识到了这个问题。他的文章A Ghost in a Snowstorm(在书中收集的Notation, Notation,Notation,这篇文章大部分可以在这里 找到)讲到正确的方式(线性化),以及各种对alphasRGB进行编码引起的错误。感谢肖恩·巴雷特指出来。

我的结论依旧不变:如果你想尝试有趣的谜题并且你靠近大城市,看看The Puzzled Pint,一个很棒且免费的社会性解谜活动,每月都会举行。


回顾记录,这是我原来错误的答案:

答案是(373373373128)。要正确显示此RGBA,你乘以alpha(除以255,因为128值代表0.5),以获得(187187187)。

简单点说这是sRGBPNG格式存在的重大缺陷:你不能在PNG 8位存储中存储37316位也没用:PNG格式存储其值的范围为[0.0,1.0]的分数。

没有线性化或过滤或运算顺序或任何其他事涉及,只是一个简单的问题。不幸的是,PNG失败。

错误答案包括:

·         187187187128 - 如果PNG有一个乘模式,这个答案就没问题。然并没有这种模式,所以色值将与0.5相乘得到的(94,94,94)来示。就是,如果你有一个封的系统而且没有其他人会用你的PNG,这是个不错的储存数据的方式。

·         187187187255 - 这会显示正确,但不保留alpha

·         255255255128 - 这给了你128,128,128)的色的Hable示不是一个视觉认知的半灰色。如果你使用PNG伽马块,并置伽玛值1.0是可行的。几乎没有人使会用这种伽玛设置(它会带状化,除非您使用16位)而且它基本不被大多数工具所支持。

·         255255255187 - 你用sRPG校正alpha违背了PNG规范。实际上这个将会显示正确的(187187187)。如果你使用alpha将其它图片合成为这张图片,这个错误的alpha不可行。

·         同样是(255255255187 - 你决定记住alpha值是经过sRGB校正的,并在其他地方使用它之前将它校正回来。如果你想打破范,最好存储一个预乘的色,就像第一个错误答案。这种修正是令人困惑的。

·         同样是(255255255128)您存正确的alpha值,但你需要在应用alpha值之前你首先要把存色从sRGB转换到线性空间,然后再将颜色转换sRGB进行显示。这个可行,但它违背了光alpha,它是纠结的,耗性能的,超混乱的,而不是如何实现PNG的显示,也不是如何去这篇规范,按照我的理解。最好只存一个色。


我希望我的结论是错误的,但我看不到任何一个在PNG规范中除解决方案以外的新板块。我更希望看到的是添加存储预乘值的板块。

在此期间,如果你想解决难题,而且你是在一个大城市附近,看The Puzzled Pint,,一个每个月都有免费益智社会事件的网站。


附录

扎普安德森和我在Facebook上对这个谜题讨论很多,在这非常感谢他。他更倾向于(255255255128)的答案,“在后面”应用alpha。为了说明白,下面是PNG通常的分析方法(我认为这遵循该规范,但我很乐意被证明是错误,因为即使没有浏览器或浏览器据我所知能正确地实现它,PNG依旧能正常工作):

想要以SRGB显示PNGRGBA:你用RGB颜色乘以alpha值(表示小数)。

SRGB显示PNGRGBA的那个“在后面应用alpha”的方法:您sRGB数字转换存储称一个线性值,然后应用alpha,然后你转换这种线性值到sRGB空间显示。

我很喜欢这一点,就像它令人费解,使PNG工作(我真的不希望看到PNG失败)。这种解决方案的问题是,我不认为任何人都不会这样做浏览器当然不会这样做

扎普指出另外一件有趣的事情,这个有趣的网页。它指向这个相关页面。我的观点是,我不应该讨论187灰色作为感知平均灰度; 128灰色确实看起来视觉上更容易接受(这就是为什么通常伽玛校正是有道理的,即人类的感知与显示器之间为非线性关系-我忘了)。这实际上没有改变以上任何内容,半覆盖像素的例子还是应该得到187。这一点可以通过平均为187的全黑和全白直线交替出现来确定。


【版权声明】

原文作者未做权利声明,视为共享知识产权进入公共领域,自动获得授权。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引