PNGlitch

The Art of PNG Glitch

Overview

PNG is an image format that has a history of development beginning in 1995, and it is still a popular, long living format. Generally, it is known for its features such as lossless compression and the ability to handle transparent pixels.
However, we do not look at image formats from a general point of view, but rather think of ways to glitch them. When we look at PNG from the point of view of glitch, what kind of peculiarity does it have?

Checksum

We should first look into the checksum system of the CRC32 algorithm. It is used to confirm corrupted images, and when it detects corruption in an image file, normal viewer applications refuse to display it. Therefore, it is impossible to generate glitches using simple methods such as rewriting part of the binary data using text editors or binary editors (you will completely fail). In other words, the PNG format is difficult to glitch.
We need to create glitches accordingly to the PNG specification in order to avoid this failure. This means that we must rewrite the data after decoding CRC32, re-calculate it and attach it to the edited data.

State

Next we want to look at the transcode process of PNG. The chart shown below is a simplified explanation of how PNG encoding flows.

Figure 1)  PNG encoding flow
Figure 1) PNG encoding flow

Each of the four states that are shown above can be glitch targets. However, glitching the the first “Raw Data” is the same as glitching BMP, so it technically isn’t a PNG glitch (at the end, it is the same as PNG with the None filter applied. I will explain this in the next section). The final “Formatted PNG” glitch will not work because of the checksum system I mentioned above.
This means that PNG glitches can be made when the “Filtered Data” or “Compressed Data” is manipulated. I will explain about filters in the following subsection. When “Filtered Data” is glitched, it shows a distinctive effect; patterns that look like flower petals scatter around the image. The difference between the filters become clear when the “Filtered Data” is glitched. On the other hand, “Compressed Data” glitches are flavored by their own compression algorithm, which is Deflate compression. It shows an effect similar to a snow noise image.

There are elements else besides the transcoding process that could also influence the appearance of glitches such as transparent pixels and interlaces.

Five filters

The factor that characterizes the appearance of glitches the most is the process called filter. The filter converts the uncompressed pixel data of each scanline using a certain algorithm in order to improve the compression efficiency. There are five types of filters that include four algorithms called Sub, Up, Average and Paeth, and also None (which means no filter applied). PNG images are usually compressed after the most suitable filter is applied to each scanline, and therefore all five filters are combined when PNG images are made.
These five filters usually only contribute to the compression efficiency, so the output result is always the same no matter which filter is applied. However, a clear difference appears in the output result when the filtered data is damaged. It is difficult to recognize the difference of the filters when an image is optimized and has all five filters combined, but the difference becomes obvious when an image is glitched when the same, single filter is applied to each scanline.
I will show the difference of the effect that each filter has later on, but when we look close into the results, we will understand which filter is causing which part of the beauty of PNG glitches (yes, they are beautiful) to occur.

I will show the actual glitch results in the next section.

Glitching: In practice

Figure 2) Original PNG image
Figure 2) Original PNG image
Figure 3) Glitched PNG image
Figure 3) Glitched PNG image

I have shown two PNG images above: one is an image before it has been glitched, and one is an image that has been glitched.
This is a Filtered Data glitch, which I explained in the previous section.
The original PNG has optimized filters applied to each scanline, and all of the five filters have been combined. The glitch reveals how the five filters were balanced when they were the combined.

Difference between filters

Lets look into the difference between each filter type.

Figure 4) Glitched PNG, filtered with None
Figure 4) Glitched PNG, filtered with None
Figure 5) Magnified view of fig. 4
Figure 5) Magnified view of fig. 4

The image above has applied “None (no filter)”, meaning that it is a raw data glitch. Each pixel stands alone in this state and do not have any relationship with the others, so a single re-wrote byte does not have a wide range influence.

Figure 6) Glitched PNG, filtered with Sub
Figure 6) Glitched PNG, filtered with Sub
Figure 7) Magnified view of fig. 6
Figure 7) Magnified view of fig. 6

This is a glitched image that has the filter “Sub” applied to each scanline. When the Sub algorythm is applied, the target pixel rewrites itself by refering to the pixel that is right next to it. This is why the glitch pattern avalanches towards the right side.

Figure 8) Glitched PNG, filtered with Up
Figure 8) Glitched PNG, filtered with Up
Figure 9) Magnified view of fig. 8
Figure 9) Magnified view of fig. 8

This is the filter “Up”. This filter is similar to Sub, but its reference direction is the top and bottom.

Figure 10) Glitched PNG, filtered with Average
Figure 10) Glitched PNG, filtered with Average
Figure 11) Magnified view of fig. 10
Figure 11) Magnified view of fig. 10

The filter “Average” refers to a diagonal direction. It shows a meteor like tail that starts from the damaged pixel. The soft gradation effect is also one of the peculiarities of this filter. The result of a PNG glitch when the Average filter is applied is a glitch that lacks glitchiness, and is also the most delicate portion of PNG glitching.

Figure 12) Glitched PNG, filtered with Paeth
Figure 12) Glitched PNG, filtered with Paeth
Figure 13) Magnified view of fig. 12
Figure 13) Magnified view of fig. 12

The filter “Paeth” has the most complicated algorithm when compared with the others. It also has the most complicated glitch effect. The glitch will affect a wide range of areas even with the least byte re-writing. The keynote effect of PNG glitch is caused by this filter; the figure shown in the original image is maintained, but is intensely destroyed at the same time.

Glitch after compression

Figure 14) Glitched PNG, after compressed
Figure 14) Glitched PNG, after compressed
Figure 15) Magnified view of fig. 14
Figure 15) Magnified view of fig. 14

This is a glitch of the state that I referred to as Compressed Data in the previous section. A snowstorm effect appears, and it is difficult to recognize the original figure in the image. It infrequently remains to show effects of the filters. The image is often completely destroyed.

 

Transparence

Lets look into what happens when an image that includes transparent pixels is glitched.

Figure 16) Original PNG image
Figure 16) Original PNG image with alpha pixels
Figure 17) Glitched PNG, with alpha pixels
Figure 17) Glitched PNG, with alpha pixels

The transparency comes as an effect. Especially the filter “Average” seems to blend transparent pixels gradually. A 100% gathering of transparent pixels is handled in the same way as a solid colored section. You can tell that the filter “Up” is often applied to solid colored sections.
(There is a possibility that newer general-purpose image formats switch their compression scheme of each part depending on if the image is a solid colored section, or else a complicated image such as photographs. The use of images that include solid colored sections for testing glitches is an effective method. One example is a WebP. )

Interlace

Figure 18) Glitched PNG, with interlace
Figure 18) Glitched PNG, with interlace
Figure 19) Magnified view of fig. 18
Figure 19) Magnified view of fig. 18

PNG interlaces are divided into seven passes, using the Adam7 algorithm based on 8x8 pixels. We are able to visualy observe that algorithm when an interlaced PNG is glitched. We can also confirm a stitched effect, and that its angle has become narrow towards the Average filter (see appendix B).

Conclusion

PNG is a very simple format compared to JPEG or other new image formats. The filter algorithms are like toys, and its compression method is the same as oldschool Zip compression. However, this simple image format shows a surprisingly wide range of glitch variations. We would perhaps only need one example to explain a JPEG glitch, but we need many different types of samples in order to explain what a PNG glitch is.
PNG was developed as an alternative format of GIF. However, when it comes to glitching, GIF is a format that is too poor to be compared with PNG. PNG has prepared surprisingly rich results that have been concealed by the checksum barrier for a long time.


Appendix A: PNGlitch library

The author released a tiny script for PNG glitch in 2010. Back then, it only removed the CRC32 and added it back again after the internal data was glitched.
Since then, the author has continued to rewrite the script and make improved versions of it for the purpose of using it in his own work, but he decided to make a library that adopts his know-how in 2014. The Ruby library PNGlitch came out as the result.
Every glitch image that appears in this article is made by using this library.

Appendix A explains how to use the PNGlitch library.
(The user must have a certain level of knowledge of the Ruby language in order to understand the code snippet samples.)

How to use this library: The Simple Way

png = PNGlitch.open '/path/to/your/image.png'
png.glitch do |data|
  data.gsub /\d/, 'x'
end
png.save '/path/to/broken/image.png'
png.close
        

The code above can also be written in a different way, like the one below.

PNGlitch.open('/path/to/your/image.png') do |png|
  png.glitch do |data|
    data.gsub /\d/, 'x'
  end
  png.save '/path/to/broken/image.png'
end
        

The glitch method handles compressed and decompressed data as a single string instance. It is handy, but on the other hand the memory usage amount can become enormous. When the memory usage is an issue, the user can write a code that uses IO instead of String like the one below.

PNGlitch.open('/path/to/your/image.png') do |png|
  buf = 2 ** 18
  png.glitch_as_io do |io|
    until io.eof? do
      d = io.read(buf)
      io.pos -= d.size
      io.print(d.gsub(/\d/, 'x'))
    end
  end
  png.save '/path/to/broken/image.png'
end
        

PNGlitch also provides a method to manipulate each scanline.

PNGlitch.open('/path/to/your/image.png') do |png|
  png.each_scanline do |scanline|
    scanline.gsub! /\d/, 'x'
  end
  png.save '/path/to/broken/image.png'
end
        

The first example that uses the glitch method sometimes destroys bytes that express the filter type, so it might output a file that cannot be opened by certain viewer applications. The each_scanline method is much safer, and the memory usage is also low. It is a thorough method, but it takes more time than the glitch method.

How to use this library: Complex Manipulatin

Scanline data is made out of pixel data and the filter type value.

The user can also rewrite pixel data using Scanline#replace_data.

png.each_scanline do |scanline|
  data = scanline.data
  scanline.replace_data(data.gsub(/\d/, 'x'))
end
        

The user can also use Scanline#gsub! and do treatments like String#gsub!.

png.each_scanline do |scanline|
  scanline.gsub! /\d/, 'x'
end
        

The user can confirm the filter type of the PNG file by running the command below. Internally, the filter types None, Sub, Up, Average and Paeth are all expressed by numeric values between 0 and 4.

puts png.filter_types
        

The user can also check each filter type using each_scanline.

png.each_scanline do |scanline|
  puts scanline.filter_type
  scanline.change_filter 3
end
        

The sample above has had each filter type changed to 3 (Average). change_filter properly applies the new filter type. This treatment will not cause glitches to occur because the filter is re-calculated and the PNG will be properly formatted. This also means that the resulting image will appear as the same to our eyes.

However, the difference of each filter has a large influence on the glitches.

PNGlitch.open(infile) do |png|
  png.each_scanline do |scanline|
    scanline.change_filter 3
  end
  png.glitch do |data|
    data.gsub /\d/, 'x'
  end
  png.save outfile1
end

PNGlitch.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 outfile2
end
        

The output results of the two samples above are completely different. The difference is in the filters.

The code examples that I have explained are all manipulations done to the “Filtered Data” state. When the users want to glitch “Compressed Data” in PNGlitch, they must use the glitch_after_compress method.

png.glitch_after_compress do |data|
  data[rand(data.size)] = 'x'
  data
end
        

"The PNGlitch library is released as open source.
https://github.com/ucnv/pnglitch

Appendix B: PNG glitch catalogue

Appendix B includes a list of glitch variations that were not covered in the main article. This catalogue will reveal how wide the variety of PNG glitch expressions can be.
I will define 3 simple methods to destroy data.

Replace:
Randomly rewrite the byte string.
Transpose:
Divide the byte string into large chunks and re-arrange them.
Defect:
Randomly delete the byte string (to rewrite as an empty string).

It mentions five types of filters which are: Sub, Up, Average, Paeth, and the optimized and combined filter.
It also shows 120 patterns of combinations of if there is an alpha or not, if it is interlaced or not, and which state was glitched.
The generating script is shown at the end.

Figure B.1) Glitched PNG
Glitch method: Replace / Filter: Optimized / Interlace: None / Glitched on: Filtered data
Figure B.2) Glitched PNG
Glitch method: Transpose / Filter: Optimized / Interlace: None / Glitched on: Filtered data
Figure B.3) Glitched PNG
Glitch method: Defect / Filter: Optimized / Interlace: None / Glitched on: Filtered data
Figure B.4) Glitched PNG
Glitch method: Replace / Filter: Sub / Interlace: None / Glitched on: Filtered data
Figure B.5) Glitched PNG
Glitch method: Transpose / Filter: Sub / Interlace: None / Glitched on: Filtered data
Figure B.6) Glitched PNG
Glitch method: Defect / Filter: Sub / Interlace: None / Glitched on: Filtered data
Figure B.7) Glitched PNG
Glitch method: Replace / Filter: Up / Interlace: None / Glitched on: Filtered data
Figure B.8) Glitched PNG
Glitch method: Transpose / Filter: Up / Interlace: None / Glitched on: Filtered data
Figure B.9) Glitched PNG
Glitch method: Defect / Filter: Up / Interlace: None / Glitched on: Filtered data
Figure B.10) Glitched PNG
Glitch method: Replace / Filter: Average / Interlace: None / Glitched on: Filtered data
Figure B.11) Glitched PNG
Glitch method: Transpose / Filter: Average / Interlace: None / Glitched on: Filtered data
Figure B.12) Glitched PNG
Glitch method: Defect / Filter: Average / Interlace: None / Glitched on: Filtered data
Figure B.13) Glitched PNG
Glitch method: Replace / Filter: Paeth / Interlace: None / Glitched on: Filtered data
Figure B.14) Glitched PNG
Glitch method: Transpose / Filter: Paeth / Interlace: None / Glitched on: Filtered data
Figure B.15) Glitched PNG
Glitch method: Defect / Filter: Paeth / Interlace: None / Glitched on: Filtered data
Figure B.16) Glitched PNG
Glitch method: Replace / Filter: Optimized / Interlace: Interlaced / Glitched on: Filtered data
Figure B.17) Glitched PNG
Glitch method: Transpose / Filter: Optimized / Interlace: Interlaced / Glitched on: Filtered data
Figure B.18) Glitched PNG
Glitch method: Defect / Filter: Optimized / Interlace: Interlaced / Glitched on: Filtered data
Figure B.19) Glitched PNG
Glitch method: Replace / Filter: Sub / Interlace: Interlaced / Glitched on: Filtered data
Figure B.20) Glitched PNG
Glitch method: Transpose / Filter: Sub / Interlace: Interlaced / Glitched on: Filtered data
Figure B.21) Glitched PNG
Glitch method: Defect / Filter: Sub / Interlace: Interlaced / Glitched on: Filtered data
Figure B.22) Glitched PNG
Glitch method: Replace / Filter: Up / Interlace: Interlaced / Glitched on: Filtered data
Figure B.23) Glitched PNG
Glitch method: Transpose / Filter: Up / Interlace: Interlaced / Glitched on: Filtered data
Figure B.24) Glitched PNG
Glitch method: Defect / Filter: Up / Interlace: Interlaced / Glitched on: Filtered data
Figure B.25) Glitched PNG
Glitch method: Replace / Filter: Average / Interlace: Interlaced / Glitched on: Filtered data
Figure B.26) Glitched PNG
Glitch method: Transpose / Filter: Average / Interlace: Interlaced / Glitched on: Filtered data
Figure B.27) Glitched PNG
Glitch method: Defect / Filter: Average / Interlace: Interlaced / Glitched on: Filtered data
Figure B.28) Glitched PNG
Glitch method: Replace / Filter: Paeth / Interlace: Interlaced / Glitched on: Filtered data
Figure B.29) Glitched PNG
Glitch method: Transpose / Filter: Paeth / Interlace: Interlaced / Glitched on: Filtered data
Figure B.30) Glitched PNG
Glitch method: Defect / Filter: Paeth / Interlace: Interlaced / Glitched on: Filtered data
Figure B.31) Glitched PNG
Glitch method: Replace / Filter: Optimized / Interlace: None / Glitched on: Compressed data
Figure B.32) Glitched PNG
Glitch method: Transpose / Filter: Optimized / Interlace: None / Glitched on: Compressed data
Figure B.33) Glitched PNG
Glitch method: Defect / Filter: Optimized / Interlace: None / Glitched on: Compressed data
Figure B.34) Glitched PNG
Glitch method: Replace / Filter: Sub / Interlace: None / Glitched on: Compressed data
Figure B.35) Glitched PNG
Glitch method: Transpose / Filter: Sub / Interlace: None / Glitched on: Compressed data
Figure B.36) Glitched PNG
Glitch method: Defect / Filter: Sub / Interlace: None / Glitched on: Compressed data
Figure B.37) Glitched PNG
Glitch method: Replace / Filter: Up / Interlace: None / Glitched on: Compressed data
Figure B.38) Glitched PNG
Glitch method: Transpose / Filter: Up / Interlace: None / Glitched on: Compressed data
Figure B.39) Glitched PNG
Glitch method: Defect / Filter: Up / Interlace: None / Glitched on: Compressed data
Figure B.40) Glitched PNG
Glitch method: Replace / Filter: Average / Interlace: None / Glitched on: Compressed data
Figure B.41) Glitched PNG
Glitch method: Transpose / Filter: Average / Interlace: None / Glitched on: Compressed data
Figure B.42) Glitched PNG
Glitch method: Defect / Filter: Average / Interlace: None / Glitched on: Compressed data
Figure B.43) Glitched PNG
Glitch method: Replace / Filter: Paeth / Interlace: None / Glitched on: Compressed data
Figure B.44) Glitched PNG
Glitch method: Transpose / Filter: Paeth / Interlace: None / Glitched on: Compressed data
Figure B.45) Glitched PNG
Glitch method: Defect / Filter: Paeth / Interlace: None / Glitched on: Compressed data
Figure B.46) Glitched PNG
Glitch method: Replace / Filter: Optimized / Interlace: Interlaced / Glitched on: Compressed data
Figure B.47) Glitched PNG
Glitch method: Transpose / Filter: Optimized / Interlace: Interlaced / Glitched on: Compressed data
Figure B.48) Glitched PNG
Glitch method: Defect / Filter: Optimized / Interlace: Interlaced / Glitched on: Compressed data
Figure B.49) Glitched PNG
Glitch method: Replace / Filter: Sub / Interlace: Interlaced / Glitched on: Compressed data
Figure B.50) Glitched PNG
Glitch method: Transpose / Filter: Sub / Interlace: Interlaced / Glitched on: Compressed data
Figure B.51) Glitched PNG
Glitch method: Defect / Filter: Sub / Interlace: Interlaced / Glitched on: Compressed data
Figure B.52) Glitched PNG
Glitch method: Replace / Filter: Up / Interlace: Interlaced / Glitched on: Compressed data
Figure B.53) Glitched PNG
Glitch method: Transpose / Filter: Up / Interlace: Interlaced / Glitched on: Compressed data
Figure B.54) Glitched PNG
Glitch method: Defect / Filter: Up / Interlace: Interlaced / Glitched on: Compressed data
Figure B.55) Glitched PNG
Glitch method: Replace / Filter: Average / Interlace: Interlaced / Glitched on: Compressed data
Figure B.56) Glitched PNG
Glitch method: Transpose / Filter: Average / Interlace: Interlaced / Glitched on: Compressed data
Figure B.57) Glitched PNG
Glitch method: Defect / Filter: Average / Interlace: Interlaced / Glitched on: Compressed data
Figure B.58) Glitched PNG
Glitch method: Replace / Filter: Paeth / Interlace: Interlaced / Glitched on: Compressed data
Figure B.59) Glitched PNG
Glitch method: Transpose / Filter: Paeth / Interlace: Interlaced / Glitched on: Compressed data
Figure B.60) Glitched PNG
Glitch method: Defect / Filter: Paeth / Interlace: Interlaced / Glitched on: Compressed data
Figure B.61) Glitched PNG
Glitch method: Replace / Filter: Optimized / Interlace: None / Glitched on: Filtered data
Figure B.62) Glitched PNG
Glitch method: Transpose / Filter: Optimized / Interlace: None / Glitched on: Filtered data
Figure B.63) Glitched PNG
Glitch method: Defect / Filter: Optimized / Interlace: None / Glitched on: Filtered data
Figure B.64) Glitched PNG
Glitch method: Replace / Filter: Sub / Interlace: None / Glitched on: Filtered data
Figure B.65) Glitched PNG
Glitch method: Transpose / Filter: Sub / Interlace: None / Glitched on: Filtered data
Figure B.66) Glitched PNG
Glitch method: Defect / Filter: Sub / Interlace: None / Glitched on: Filtered data
Figure B.67) Glitched PNG
Glitch method: Replace / Filter: Up / Interlace: None / Glitched on: Filtered data
Figure B.68) Glitched PNG
Glitch method: Transpose / Filter: Up / Interlace: None / Glitched on: Filtered data
Figure B.69) Glitched PNG
Glitch method: Defect / Filter: Up / Interlace: None / Glitched on: Filtered data
Figure B.70) Glitched PNG
Glitch method: Replace / Filter: Average / Interlace: None / Glitched on: Filtered data
Figure B.71) Glitched PNG
Glitch method: Transpose / Filter: Average / Interlace: None / Glitched on: Filtered data
Figure B.72) Glitched PNG
Glitch method: Defect / Filter: Average / Interlace: None / Glitched on: Filtered data
Figure B.73) Glitched PNG
Glitch method: Replace / Filter: Paeth / Interlace: None / Glitched on: Filtered data
Figure B.74) Glitched PNG
Glitch method: Transpose / Filter: Paeth / Interlace: None / Glitched on: Filtered data
Figure B.75) Glitched PNG
Glitch method: Defect / Filter: Paeth / Interlace: None / Glitched on: Filtered data
Figure B.76) Glitched PNG
Glitch method: Replace / Filter: Optimized / Interlace: Interlaced / Glitched on: Filtered data
Figure B.77) Glitched PNG
Glitch method: Transpose / Filter: Optimized / Interlace: Interlaced / Glitched on: Filtered data
Figure B.78) Glitched PNG
Glitch method: Defect / Filter: Optimized / Interlace: Interlaced / Glitched on: Filtered data
Figure B.79) Glitched PNG
Glitch method: Replace / Filter: Sub / Interlace: Interlaced / Glitched on: Filtered data
Figure B.80) Glitched PNG
Glitch method: Transpose / Filter: Sub / Interlace: Interlaced / Glitched on: Filtered data
Figure B.81) Glitched PNG
Glitch method: Defect / Filter: Sub / Interlace: Interlaced / Glitched on: Filtered data
Figure B.82) Glitched PNG
Glitch method: Replace / Filter: Up / Interlace: Interlaced / Glitched on: Filtered data
Figure B.83) Glitched PNG
Glitch method: Transpose / Filter: Up / Interlace: Interlaced / Glitched on: Filtered data
Figure B.84) Glitched PNG
Glitch method: Defect / Filter: Up / Interlace: Interlaced / Glitched on: Filtered data
Figure B.85) Glitched PNG
Glitch method: Replace / Filter: Average / Interlace: Interlaced / Glitched on: Filtered data
Figure B.86) Glitched PNG
Glitch method: Transpose / Filter: Average / Interlace: Interlaced / Glitched on: Filtered data
Figure B.87) Glitched PNG
Glitch method: Defect / Filter: Average / Interlace: Interlaced / Glitched on: Filtered data
Figure B.88) Glitched PNG
Glitch method: Replace / Filter: Paeth / Interlace: Interlaced / Glitched on: Filtered data
Figure B.89) Glitched PNG
Glitch method: Transpose / Filter: Paeth / Interlace: Interlaced / Glitched on: Filtered data
Figure B.90) Glitched PNG
Glitch method: Defect / Filter: Paeth / Interlace: Interlaced / Glitched on: Filtered data
Figure B.91) Glitched PNG
Glitch method: Replace / Filter: Optimized / Interlace: None / Glitched on: Compressed data
Figure B.92) Glitched PNG
Glitch method: Transpose / Filter: Optimized / Interlace: None / Glitched on: Compressed data
Figure B.93) Glitched PNG
Glitch method: Defect / Filter: Optimized / Interlace: None / Glitched on: Compressed data
Figure B.94) Glitched PNG
Glitch method: Replace / Filter: Sub / Interlace: None / Glitched on: Compressed data
Figure B.95) Glitched PNG
Glitch method: Transpose / Filter: Sub / Interlace: None / Glitched on: Compressed data
Figure B.96) Glitched PNG
Glitch method: Defect / Filter: Sub / Interlace: None / Glitched on: Compressed data
Figure B.97) Glitched PNG
Glitch method: Replace / Filter: Up / Interlace: None / Glitched on: Compressed data
Figure B.98) Glitched PNG
Glitch method: Transpose / Filter: Up / Interlace: None / Glitched on: Compressed data
Figure B.99) Glitched PNG
Glitch method: Defect / Filter: Up / Interlace: None / Glitched on: Compressed data
Figure B.100) Glitched PNG
Glitch method: Replace / Filter: Average / Interlace: None / Glitched on: Compressed data
Figure B.101) Glitched PNG
Glitch method: Transpose / Filter: Average / Interlace: None / Glitched on: Compressed data
Figure B.102) Glitched PNG
Glitch method: Defect / Filter: Average / Interlace: None / Glitched on: Compressed data
Figure B.103) Glitched PNG
Glitch method: Replace / Filter: Paeth / Interlace: None / Glitched on: Compressed data
Figure B.104) Glitched PNG
Glitch method: Transpose / Filter: Paeth / Interlace: None / Glitched on: Compressed data
Figure B.105) Glitched PNG
Glitch method: Defect / Filter: Paeth / Interlace: None / Glitched on: Compressed data
Figure B.106) Glitched PNG
Glitch method: Replace / Filter: Optimized / Interlace: Interlaced / Glitched on: Compressed data
Figure B.107) Glitched PNG
Glitch method: Transpose / Filter: Optimized / Interlace: Interlaced / Glitched on: Compressed data
Figure B.108) Glitched PNG
Glitch method: Defect / Filter: Optimized / Interlace: Interlaced / Glitched on: Compressed data
Figure B.109) Glitched PNG
Glitch method: Replace / Filter: Sub / Interlace: Interlaced / Glitched on: Compressed data
Figure B.110) Glitched PNG
Glitch method: Transpose / Filter: Sub / Interlace: Interlaced / Glitched on: Compressed data
Figure B.111) Glitched PNG
Glitch method: Defect / Filter: Sub / Interlace: Interlaced / Glitched on: Compressed data
Figure B.112) Glitched PNG
Glitch method: Replace / Filter: Up / Interlace: Interlaced / Glitched on: Compressed data
Figure B.113) Glitched PNG
Glitch method: Transpose / Filter: Up / Interlace: Interlaced / Glitched on: Compressed data
Figure B.114) Glitched PNG
Glitch method: Defect / Filter: Up / Interlace: Interlaced / Glitched on: Compressed data
Figure B.115) Glitched PNG
Glitch method: Replace / Filter: Average / Interlace: Interlaced / Glitched on: Compressed data
Figure B.116) Glitched PNG
Glitch method: Transpose / Filter: Average / Interlace: Interlaced / Glitched on: Compressed data
Figure B.117) Glitched PNG
Glitch method: Defect / Filter: Average / Interlace: Interlaced / Glitched on: Compressed data
Figure B.118) Glitched PNG
Glitch method: Replace / Filter: Paeth / Interlace: Interlaced / Glitched on: Compressed data
Figure B.119) Glitched PNG
Glitch method: Transpose / Filter: Paeth / Interlace: Interlaced / Glitched on: Compressed data
Figure B.120) Glitched PNG
Glitch method: Defect / Filter: Paeth / Interlace: Interlaced / Glitched on: Compressed data

require 'pnglitch'

count = 0
infiles = %w(lena.png lena-alpha.png)
infiles.each do |file|
  alpha = /alpha/ =~ file
  [false, true].each do |compress|
    [false, true].each do |interlace|
      infile = file
      if interlace
        system("convert -interlace plane %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_filters filter unless filter == :optimized
          options = [filter.to_s]
          options << 'alpha' if alpha
          options << 'interlace' if interlace
          options << 'compress' if compress
          options << method.to_s
          outfile = "lena-%03d-%s.png" % [count, options.join('-')]
          process = lambda do |data, range|
            case method
            when :replace
              range.times do
                data[rand(data.size)] = 'x'
              end
              data
            when :transpose
              x = data.size / 4
              data[0, x] + data[x * 2, x] + data[x * 1, x] + data[x * 3..-1]
            when :defect
              (range / 5).times do
                data[rand(data.size)] = ''
              end
              data
            end
          end
          unless compress
            png.glitch do |data|
              process.call data, 50
            end
          else
            png.glitch_after_compress do |data|
              process.call data, 10
            end
          end
          png.save outfile
          png.close
        end
      end
    end
  end
end
File.unlink 'tmp.png'
          

Appendix C: Incorrect filters

A PNG scanline consists of a combination of a filter type byte and filtered pixel data. Deliberately making an incorrect combination is another technique in PNG glitching.

Figure C.1)
Figure C.1) PNG applied wrong filter types

The image above is generated by the code below.
In PNGlitch, the method graft is prepared so that the user can attach an incorrect filter type to a scanline.

require 'pnglitch'
PNGlitch.open('png.png') do |png|
  png.each_scanline do |line|
    line.graft rand(5)
  end
  png.save "png-glitch-graft.png"
end
        

This technique is convenient, even for checking how different the glitching effect of each filter is. Next five images are the results that applied one particular filter type byte to every scanline, without modifying scanline data.

Figure C.2)
Figure C.2) PNG applied wrong filter types, changing every filter type as None
Figure C.3)
Figure C.3) PNG applied wrong filter types, changing every filter type as Sub
Figure C.4)
Figure C.4) PNG applied wrong filter types, changing every filter type as Up
Figure C.5)
Figure C.5) PNG applied wrong filter types, changing every filter type as Average
Figure C.6)
Figure C.6) PNG applied wrong filter types, changing every filter type as Paeth
require 'pnglitch'
(0..4).each do |filter|
  PNGlitch.open('png.png') do |png|
    png.each_scanline do |line|
      line.graft filter
    end
    png.save "png-glitch-graft-#{filter}.png"
  end
end
        

Implementation of an incorrect filter

What will happen if an incorrect filter is implemented? PNGlitch is designed to allow the user to freely change filter methods, so the user can test what happens at that state. A normal viewer application that uses a standard filter method is decoding a PNG image that is encoded by a distinctive filter method. This will perhaps generate an algorithmic glitch (I will not argue about if we should call that a glitch or not). The images below are part of such generated images.

Figure C.7) PNG encoded with an incorrect filter 1
Figure C.7) PNG encoded with an incorrect filter 1
require 'pnglitch'
PNGlitch.open('png.png') do |p|
  p.each_scanline do |l|
    l.register_filter_encoder do |data, prev|
      data.size.times.reverse_each do |i|
        x = data.getbyte(i)
        v = prev ? prev.getbyte(i - 1) : 0
        data.setbyte(i, (x - v) & 0xff)
      end
      data
    end
  end
  p.output 'png-incorrect-filter01.png'
end
        
Figure C.8) PNG encoded with an incorrect filter 2
Figure C.8) PNG encoded with an incorrect filter 2
require '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.reverse_each do |i|
        x = data.getbyte(i)
        v = prev ? prev.getbyte(i - 6) : 0
        data.setbyte(i, (x - v) & 0xff)
      end
      data
    end
  end
  p.output 'png-incorrect-filter02.png'
end
        
Figure C.9) PNG encoded with an incorrect filter 3
Figure C.9) PNG encoded with an incorrect filter 3
require 'pnglitch'
PNGlitch.open('png.png') do |png|
  png.change_all_filters 4
  sample_size = png.sample_size
  png.each_scanline do |l|
    l.register_filter_encoder do |data, prev|
      data.size.times.reverse_each do |i|
        x = data.getbyte i
        is_a_exist = i >= sample_size
        is_b_exist = !prev.nil?
        a = is_a_exist ? data.getbyte(i - sample_size) : 0
        b = is_b_exist ? prev.getbyte(i) : 0
        c = 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
        data.setbyte i, (x - pr) & 0xfe
      end
      data
    end
  end
  png.output 'png-incorrect-filter03.png'
end
        
Figure C.10) PNG encoded with an incorrect filter 4
Figure C.10) PNG encoded with an incorrect filter 4
require '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.reverse_each do |i|
        x = data.getbyte(i)
        v = prev ? prev.getbyte(i) : 0
        data.setbyte(i, (x - v) & 0xfe)
      end
      data
    end
  end
  p.output 'png-incorrect-filter04.png'
end