I was always interested in glitching images - but was frustrated with the checksum/read errors. I took a slightly different approach with JPGCrunk (http://www.mrspeaker.net/dev/jpgcrunk/): instead of modifying the image then trying to display it, randomly mess with the internals of the encoder (I used a JavaScript implementation so it was easy to modify https://github.com/mrspeaker/jpgcrunk/blob/master/scripts/en...)
This way the "glitching" happens inside the encoder algorithm, and then there's nothing to have to repair!
Reminds me a bit of a video codec technique to exaggerate the motion frames and compression ala "datamoshing".
Keyframes are removed which leaves only information from the previous frame to be updated by motion frames. Than update/motion frames are reiterated sequentially which creates an effect that just further saturates the previous frame and looks like a fluid melting effect.
They're all (except the detail thumbnails) initally loaded as a blank.png and then substituted in with javascript for absolutely no reason. That kind of thing gets me to close the tab real fast.
I didn't know PNG was so simple. Encode scanlines in terms of each other, then pass the whole thing to DEFLATE... and it is effective. That's very elegant.
PNG is one of my favourite file formats. It also has a chunking system which lets you store extra data, which isn't really covered here. Definitely worth looking into if you're interested in binary format design.
The other image format that's worth knowing is TIFF, because it's an insanely simple and flexible format to write out if you don't have access to a library. It lets you re-order the image data by tiles or scan lines, and lets you put various tables almost anywhere in the file, which makes it great for outputting large images from a parallel renderer: you can chop it up however is suitable for the algorithm, write out the parts to disk as you get them, and then write out a table at the end describing the order at the end of the file, without having to seek.
In particular PNG may have a chunk that store the gamma information of the file, that is important to correct the differences between the standard configuration of PC and Mac monitors. This value is difficult to find, and some programs ignore it and other use it. I had a few nightmares cases trying to make a webpage look right until I realize that the PNG has a hidden gamma value.
Actually it is (or at least used to be) more like "what Photoshop supports". Libtiff implementers often look to what Photoshop does to see how to implement something. But libtiff has a very large influence too. (I don't think Photoshop supports BigTIFF yet.)
It's effective, but it's not /very/ effective. A 1D byte-level compression like deflate is an inappropriate tool for images.
As an experiment I just opened a screenshot in Preview.app and exported to PNG with and without an alpha channel - adding alpha makes it 335KB vs 300KB. Since the alpha contains no information, there's no excuse for it to be 30KB compressed!
ffv1 or your favorite video codec with a lossless mode will produce much smaller files and decode much faster than png.
Now you've got me curious what the compression ratio would be if you just re-ordered an image's pixels using a Hilbert curve (so that in e.g. a 100x100 image, the first 100px scanline contains the first 100px of the Hilbert path through the original image) before passing it to PNG for compression.
That idea isn't too bad, it probably works most places but fails very badly in a few spots. So it might be good for lossy compression - I actually tried this once, but lost the code a while back...
In this case, PNG's filtering makes it kind of 2D-aware, so that probably works better on the original. But if you tried splitting it into 8x8 blocks, then predicting each one from the left-upperleft-upper neighbors, well, you'd have the basics to modern DCT codecs.
In my own experiments compressing pixel art, I found that gzipped .bmp files were smaller than the output of pngcrush just as often as they were larger. On average the pngs were slightly smaller, but you can tar together a whole bunch of similar bmps and gzip the lot, and then gzip really blows png out of the water. For a compressed file format specialised for images, I found png's performance very disappointing and decided not to use it.
I also stopped at that figure and thought “I really like this one — I get it”, which surprised me because the other examples looked too trivial to appreciate or too messy for me to understand.
The problem isn't lazy-loading. The problem is webpage authors who don't specify the width and height attributes on <image> tags, which allows the browser to correctly flow them before they load.
The interesting part about PNG is that since it uses the DEFLATE algorithm, and only applies compression per row/line, with no awareness of relationships between lines, is that in most cases, the effective compression is nearly the same as if you took apart each row of uncompressed pixels as an individual image, and took all those separate images and put them in a zip file.
Disregarding the cruft of headers and other file format overhead, there would be a direct relationship between the size of a PNG image, and the raw, uncompressed row-level data zipped up and handled in a similar way.
So first of all this whole article is essentially about the "filters" that are used to encode the data more efficiently based on the surrounding data, before it's passed to deflate. Basically compute some kind of a delta from the pixel compared to the pixel up of it, left of it, or a combination of the two, with the deltas generally compressing better than the raw data would have. That's already a big difference to compressing each row separately.
Second, the deflate compression does not happen individually for each row. It happens individually for each IDAT block, but those blocks can be of fairly arbitrary size. Using a separate IDAT block for each row would seem very odd. (Can you even use filters in that case, or does the state reset with each new block?)
This way the "glitching" happens inside the encoder algorithm, and then there's nothing to have to repair!