PNG毛刺的艺术

2020-09-19 03:13:34

PNG是一种图像格式,从1995年开始就有了发展的历史,至今仍是一种流行的、经久不衰的格式。通常,它以其诸如无损压缩和处理透明像素的能力而闻名。然而,我们不会从一般的角度来看待图像格式,而是考虑如何使其出现故障。当我们从毛刺的角度来看待巴新时,它有什么样的奇特之处呢?

我们应该首先研究一下CRC32算法的校验和系统。它用于确认损坏的图像,当它检测到图像文件中的损坏时,正常的查看器应用程序拒绝显示该图像文件。因此,不可能使用简单的方法(如使用文本编辑器或二进制编辑器重写部分二进制数据)生成毛刺(您将完全失败)。换句话说,PNG格式很难出错。我们需要根据PNG规范创建毛刺,以避免此故障。这意味着我们必须在解码CRC32之后重写数据,重新计算,并将其附加到编辑后的数据上。

接下来,我们想看看PNG的转码过程。下面显示的图表是PNG编码流程的简化说明。

上面显示的四个状态中的每一个都可能是毛刺目标。然而,第一个“原始数据”出现故障与BMP出现故障是一样的,因此从技术上讲,它不是PNG故障(最后,它与应用了“无”过滤器的PNG相同)。我将在下一节中解释这一点)。由于我上面提到的校验和系统,最后的“格式化PNG”故障将不起作用。这意味着当“过滤数据”或“压缩数据”被操纵时,可能会出现PNG故障。我将在下一小节中解释有关筛选器的内容。当“过滤数据”出现故障时,它会显示出独特的效果;看起来像花瓣的图案散布在图像周围。当“过滤的数据”出现毛刺时,过滤器之间的区别就变得清晰起来。另一方面,“压缩数据”毛刺是由它们自己的压缩算法(即Deflate压缩)来添加味道的。它显示出类似于雪噪波图像的效果。

除了代码转换过程之外,还有其他因素也会影响毛刺的外观,例如透明像素和交错。

最能表征毛刺外观的因素是被称为滤波器的过程。该滤波器使用一定的算法对每条扫描线的未压缩像素数据进行转换,以提高压缩效率。有五种类型的过滤器,包括称为Sub、Up、Average和Paeth的四种算法,也有None(即不应用过滤器)。PNG图像通常在对每条扫描线应用最合适的滤波器后进行压缩,因此在生成PNG图像时会合并所有五个滤波器。这五个滤波器通常只对压缩效率有贡献,因此无论应用哪个滤波器,输出结果总是相同的。但是,当过滤的数据损坏时,输出结果会出现明显的差异。当图像经过优化并将所有五个滤镜组合在一起时,很难识别滤镜的差异,但当对每条扫描线应用相同的单个滤镜时,当图像出现毛刺时,差异会变得明显。稍后我将展示每个滤镜的不同效果,但当我们仔细观察结果时,我们会了解哪个滤镜导致了PNG的哪一部分美丽的毛刺(是的,它们是美丽的)。

我在上面展示了两张PNG图像:一张是出现故障之前的图像,另一张是出现故障的图像。这是一个过滤后的数据故障,我在上一节中解释了这一点。原始PNG对应用于每条扫描线的滤镜进行了优化,并且所有五个滤镜都已合并。这一故障揭示了五个过滤器在组合时是如何平衡的。

上图应用了“无(无过滤器)”,这意味着这是一个原始数据故障。每个像素在此状态下都是独立的,并且与其他像素没有任何关系,因此单个重写字节不会有大范围的影响。

这是对每条扫描线应用了滤镜“Sub”的毛刺图像。应用Sub算法时,目标像素会通过引用其旁边的像素来重写自身。这就是故障模式向右侧雪崩的原因。

这是过滤器“向上”。此过滤器类似于Sub,但其参考方向为顶部和底部。

过滤器“Average”指的是对角线方向。它显示了一条流星般的尾巴,从受损的像素开始。柔和的渐变效果也是该滤波器的特点之一。当应用平均过滤器时,PNG毛刺的结果是缺少毛刺的毛刺,也是PNG毛刺中最微妙的部分。

与其他滤波器相比,“Paeth”滤波器具有最复杂的算法。它还具有最复杂的毛刺效应。即使是最小的字节重写,该故障也会影响范围很广的区域。PNG毛刺的基调效果就是由这个滤镜造成的;原图中显示的身影保持不变,但同时又被强烈破坏。

这是我在上一节中称为压缩数据的状态的故障。出现暴风雪效果,很难辨认出图像中的原始身影。很少需要显示滤镜的效果。图像通常会被完全毁掉。

透明度是一种效果。尤其是滤镜的“平均值”似乎逐渐混合了透明像素。100%的透明像素聚集的处理方式与纯色部分相同。您可以看出滤镜“向上”通常应用于纯色部分。(较新的通用图像格式可能会根据图像是纯色部分还是复杂图像(如照片)来切换其每个部分的压缩方案。使用包含纯色部分的图像来测试毛刺是一种有效的方法。WebP就是一个例子。)。

使用基于8x8像素的Adam7算法将PNG隔行扫描划分为七个过程。当隔行扫描的PNG出现毛刺时,我们能够直观地观察到该算法。我们还可以确认缝合效果,并且其角度已变得接近平均滤镜(见附录B)。

与JPEG或其他新的图像格式相比,PNG是一种非常简单的格式。过滤算法就像玩具一样,它的压缩方式和老式的Zip压缩一样。然而,这种简单的图像格式显示的毛刺变化范围之广令人惊讶。我们可能只需要一个例子来解释JPEG故障,但是我们需要许多不同类型的样本来解释什么是PNG故障。PNG是作为GIF的另一种格式开发的。然而,当谈到故障时,GIF是一种太差的格式,无法与PNG相提并论。巴新准备了令人惊讶的丰富结果,这些结果长期以来一直被校验和障碍所掩盖。

作者在2010年发布了PNG Gitch的一个小脚本。当时,它只是在内部数据出现故障后移除CRC32并将其重新添加回来。从那以后,作者继续重写剧本,并制作改进版本,目的是在自己的作品中使用它,但他决定在2014年制作一个采用他的诀窍的库。结果就是Ruby库PNGlitch问世了。本文中出现的每个毛刺图像都是使用该库制作的。

附录A说明如何使用PNGlitch库。(用户必须具备一定程度的Ruby语言知识才能理解代码片段示例。)。

上面的代码也可以用不同的方式编写,如下图所示。

GLitch方法将压缩和解压缩的数据作为单个字符串实例进行处理。它很方便,但另一方面,内存使用量可能会变得非常大。当内存使用有问题时,用户可以编写使用IO而不是字符串的代码,如下所示。

PNGlitch.open(';/path/to/your/image.png';)do|png|buf=2**18 png.glitch_as_io do|io|直到io.eof?Do d=io.read(Buf)io.pos-=d.size io.print(d.gsub(/\d/,';x';))end end png.save';/path/to/rupted/image.png';end。

第一个使用Gitch方法的示例有时会破坏表示筛选器类型的字节,因此它可能会输出某些查看器应用程序无法打开的文件。Each_Scanline方法要安全得多,并且内存使用率也很低。这是一种彻底的方法,但它比毛刺方法需要更多的时间。

用户可以通过运行下面的命令来确认PNG文件的过滤器类型。在内部,过滤器类型None、Sub、Up、Average和Paeth都由0到4之间的数值表示。

上面的示例已将每个筛选器类型更改为3(平均值)。CHANGE_FILTER正确应用新的筛选器类型。此处理不会导致出现毛刺,因为过滤器已重新计算,并且PNG将被正确格式化。这也意味着产生的图像在我们的眼睛看来是一样的。

PNGlitch.open(Infile)do|png|png.each_Scanline DO|Scanline|scanline.change_filter 3 end png.glitch do|data|data.gsub/\d/,';x';x';end png.save outfile1endPNGlitch.open(Infile)do|png|png.each_Scanline do|scanline|scanline.change_filter 4 end png.glitch do|data|data.gsub/\d/,';x';end png.save outfile2end。

上述两个样本的输出结果完全不同。不同之处在于过滤器。

我解释的代码示例都是对“筛选数据”状态进行的操作。当用户想要破坏PNGlitch中的“压缩数据”时,他们必须使用GLITCH_AFTER_COMPRESS方法。

附录B包括正文中未涉及的故障变体列表。这个目录将揭示PNG故障表达式的种类有多广。我将定义3个简单的方法来销毁数据。

提出了五种类型的滤波器,即:SUB滤波器、UP滤波器、Average滤波器、Paeth滤波器和优化组合滤波器。它还显示了是否存在Alpha、是否隔行扫描以及哪种状态出现故障的120种组合模式。生成脚本显示在末尾。

需要';pnglitch';count=0infiles=%w(lena.png Lena-alpha.png)infiles。每个都执行|file|alpha=/alpha/=~file[false,true]。每个执行|compress|[false,true]。每个执行|interlace|infile=file if interlace system(";Convert-interlace plan%s tmp.png";%infile)infile=';tmp.png';End[:Optimized,:Sub,:Up,:Average,:Paeth].Each Do|Filter|[:Replace,:Transpose,:Defect].Each Do|Method|Count+=1 PNG=PNGlitch.open infile png.change_all_filter除非filter=:优化选项=[filter.to_s]选项<;<;';alpha';if alpha选项<;<;';隔行扫描';if交错选项<;<;';压缩';如果压缩选项<;<;method.to_s outfile=";lena-%03d-%s.png";%[count,options.join(';-';)]process=lambda do|data,range|case method When:Replace range do data[rand(data.size)]=';x';结束数据当:转置x=data.size/4 data[0,x]+data[x*2,x]+data[x*1,x]+data[x*3..-1]当:缺陷(范围/5).time do data[rand(data.size)]=';';end data end end除非压缩png.glitch do|data|process.call data,50 end png.glitch_After_compress do|data|process.call data,10 end png.save outfile png.close end endFile.unlink';Tmp.png';

PNG扫描线由过滤器类型字节和已过滤像素数据的组合组成。故意进行不正确的组合是PNG故障的另一种技术。

上面的图像是由下面的代码生成的。在PNGlitch中,准备了嫁接方法,以便用户可以将错误的过滤器类型附加到扫描线。

该技术非常方便,即使对于检查每个滤波器的毛刺效果有多不同也是如此。接下来的五个图像是在不修改扫描线数据的情况下对每条扫描线应用一个特定过滤器类型字节的结果。

需要';pnglitch';(0..4)。每个DO|Filter|PNGlitch.open(';png.png';)Do|png|png。每个_Scanline DO|line|line。嫁接筛选器结束png.save";png-glitch-grag-#{filter}.png";endend。

如果实施了不正确的过滤器,会发生什么情况?PNGlitch旨在允许用户自由更改过滤方法,因此用户可以测试在该状态下发生的情况。使用标准过滤方法的普通查看器应用程序正在解码由独特过滤方法编码的PNG图像。这可能会产生算法故障(我不会争论我们是否应该称之为故障)。下面的图像是此类生成的图像的一部分。

需要';pnglitch';PNGlitch.open(';png.png';)Do|p|p.each_Scanline do|l|l.register_filter_encoder do|data,prev|data.size.times.verse_each do|i|x=data.getbyte(I)v=prev?Prev.getbyte(i-1):0 data.setbyte(i,(x-v)&;0xff)结束数据end p.output';png-不正确-filter01.png';end。

需要';pnglitch';PNGlitch.open(';png.png';)Do|p|p.Change_All_Filters 4 p.Each_Scanline Do|l|l.register_filter_encoder Do|data,prev|data.size.times.verse_each Do|i|x=data.getbyte(I)v=prev?Prev.getbyte(i-6):0 data.setbyte(i,(x-v)&;0xff)结束数据end p.output';png-不正确-filter02.png';end。

需要';pnglitch';PNGlitch.open(';png.png';)do|png|png.change_all_filter 4 SAMPLE_SIZE=pNG.SAMPLE_SIZE pNG。Each_Scanline do|l|l.register_filter_encoder do|data,prev|data.size.times.verse_each do|i|x=data.getbyte I is_a_eXist=i>;=Sample_Size is_b_eXist=!prep.nil?A=存在吗?Data.getbyte(i-sample_size):0b=IS_b_EXIST?Prev.getbyte(I):0c=is_a_eXist&;&;is_b_eXist?Prev.getbyte(i-sample_size):0 p=a+b-c pa=(p-a).abs pb=(p-b).abs pc=(p-c).abs pr=pa<;=pb&;&;pa<;=pc?A:PB<;=PC?B:C数据。setbyte I,(x-pr)&;0xfe结束数据结束png.output';png-不正确-filter03.png';end。

需要';pnglitch';PNGlitch.open(';png.png';)Do|p|p.Change_All_Filters 2 p.Each_Scanline Do|l|l.register_filter_encoder Do|data,prev|data.size.times.verse_each Do|i|x=data.getbyte(I)v=prev?Prev.getbyte(I):0 data.setbyte(i,(x-v)&;0xfe)end data end p.output';png-inright-filter04.png';end。

后藤武弘的原创摄影、目录上的Lena支持大江真人的日英翻译

编辑:在本文发表后,我们有机会讨论如何使用Lena图像进行技术演示。这张照片有一段奇怪的历史,让人产生了争议。我们希望读者了解人民的反应和这篇文章的立场为莉娜。Https://github.com/ucnv/pnglitch/pull/2。

编辑2:本文件被选为第19届日本媒体艺术节艺术部评审团。