Search code examples
imagepngfilesizergba

How can you make an image file as dense as possible?


Suppose I have an image file that I know is going to end up being 1024 x 1024, and I want to make that file as big (diskspace-wise) as possible. Assuming a 72-dpi resolution PNG file, what would I fill this file with to make it as information-dense as possible? Are certain colors more expensive to store than others? Patterns? Alpha-levels? I'm thinking about a PNG file specifically, but interested to know about GIF and JPG files, too.


Solution

  • In general PNG employs "lossless" compression, which usually works by finding repeated RGB values and/or repeated tiles or scanlines in the file. You can read more here:

    http://www.libpng.org/pub/png/book/chapter09.html

    In general, to defeat pretty much any lossless compressor, all you would have to do is to fill the image with random RGB noise, in such a way that RGB values of the pixels come outwildly different per scanline and per neighbouring pixel - that is, produce as few as possible repeating sequences of pixel color values. Knowing that you will be working with a file that has 1048576 pixels in total, which is just over a million, and 24 bit PNG gives you 16777216 colors to choose from (24-bit color, 8 bit per channel) you could try to sample every 16th color adjusting it's value ever slightly up and down when you sample, and just write it into the image.

    For more interesting info on the topic see Concept check: any lossless data compression can be "defeated', right?

    For a simple example, let's generate a PNG of your dimensions and fill it with random noise:

    require 'rubygems'
    require 'chunky_png'
    
    dimension = 1024
    png = ChunkyPNG::Image.new(dimension, dimension)
    
    total_colors = 2 ** (8*(3+1)) # 3 + 1 because we have alpha too!
    rng = Random.new
    (0...dimension).each do | x |
      (0...dimension).each do | y |
        r = rng.rand(0..total_colors) 
        png[x, y] = r
      end
    end
    
    png.save('/tmp/noise.png')
    `open /tmp/noise.png`
    

    This gives me a 4.2 megabyte file on OSX. When I run pngcrush on it to put in some compression I get a file of the same size. If you want to make an existing image non-compressible you could try mixing in noise in the same fashion.