Output a solid PNG from scratch Input: An RGBA hex color c (ex. FFFF00FF) and an integer > 0 and &lt; 1000 n (ex. 200).

Output: Raw bytes of a PNG file such that when the output is saved to a file and opened in an image viewer, an n by n image filled with the color c is displayed.

Specification: Your program should output exactly:


a PNG header (89504E470D0A1A0A in hex)
an IHDR chunk containing these specifications:

width: the previous input n
height: the previous input n
bit depth: 8 (RGBA)
color type: 6 (truecolor with alpha)
compression method: 0
filter method: 0
interlace method: 0

one or more IDAT chunks containing the image data (a solid image of color previously input c); may be compressed or uncompressed
an IEND image end chunk


Further details available on Wikipedia, on the W3 site, or via a Google search.

Restrictions:


You may not use any image libraries or functions designed to work with images of any kind.
Your program must run in under 3 minutes and output a file under 10 MB for all inputs (sanity check).
This is code-golf, so the shortest code in bytes will win!
Perl, 181

/ /;use String::CRC32;use Compress::Zlib;sub k{$_=pop;pack'Na*N',y///c-4,$_,crc32$_}$_="\x89PNG\r\n\cZ\n".k(IHDR.pack NNCV,$',$',8,6).k(IDAT.compress pack('CH*',0,$`x$')x$').k IEND


Size is 180 bytes and option -p is needed (+1). Score is then 181.

The arguments are given via STDIN in a line, separated by a space,
the color as hex value (16 chars) and the number of pixels for width/height, e.g.:

 echo "FFFF00FF 200" | perl -p solidpng.pl &gt;yellow200.png




The file size is 832 bytes. The maximal sized image (n=999) with the same color has 6834 bytes (way below 10 MB).

The solution uses two libraries:


use Digest::CRC crc32; for the CRC32 values at the chunk ends.
use IO::Compress::Deflate deflate; to compress the image data.


Both libraries are not related to images.

Ungolfed:

# Perl option "-p" adds the following around the program:
#     LINE:
#     while (&lt;&gt;) {
#         ... # the program goes here
#     } continue {
#         print or die "-p destination: $!\n";

/ /;    # match the separator of the arguments in the input line
        # first argument, color in hex:  $`
        # second argument, width/height: $'                              #'

# load the libraries for the CRC32 fields and the data compression
use String::CRC32;
use Compress::Zlib;

# function that generates a PNG chunk:
#   N (4 bytes, big-endian: data length
#   N:                      chunk type
#   a* (binary data):       data
#   N:                      CRC32 of chunk type and data
sub k {
    $_ = pop; # chunk data including chunk type and
              # excluding length and CRC32 fields
    pack 'Na*N',
        y///c - 4,   # chunk length                                      #/
                     # netto length without length, type, and CRC32 fields
        $_,          # chunk type and data
        crc32($_)    # checksum field
}

$_ =                      # $_ is printed by option "-p".
    "\x89PNG\r\n\cZ\n"    # PNG header
        # IHDR chunk: image header with
        #   width, height,
        #   bit depth (8), color type (6),
        #   compresson method (0), filter method (0), interlace method (0)
    . k('IHDR' . pack NNCV, $', $', 8, 6)
        # IDAT chunk: image data
    . k('IDAT' .
          compress        # compress/deflate data
          pack('CH*',     # scan line with filter byte
              0,          # filter byte: None
              ($` x $')   # pixel data for one scan line                 #'`
          ) x $'          # n lines                                      #'
      )
        # IHDR chunk: image end
    . k('IEND');


Edits


use IO::Compress::Deflate':all'; is replaced by use Compress::Zlib;. The latter does export the deflate function compress by default. The function
does not need references as arguments and also returns the
result directly. That allows to get rid of variable $o.


Thanks for Michael's answer:


Function k: A call of pack could be removed by using template Na*N for the first pack in the function.
pack template NNCV with four values optimizes NNC3n with six values.


Thanks for VadimR's comment with lots of tips:


use String::CRC32; is shorter than use Digest::CRC crc32;.
y///c-4 is shorter than -4+y///c. 
The scan line is now constructed by the template CH* with the repetition in the value.
Removal of $i by using a value reference.
Bare words instead of strings for the chunk types.
Options now read by matching a STDIN input line (option -p) with matching
the space separator / /. Then the first option is in $&grave; and the second argument goes in $'.
Option -p also automatically prints $_.
"\cZ" is shorter than "\x1a".


Better compression

At the cost of code size the image data can be further compressed, if filtering is applied.


Unfiltered file size for FFFF0FF 200: 832 bytes
Filter Sub (horizontal pixel differences): 560 bytes

$i = (                            # scan line:
         "\1"                     # filter "Sub"
         . pack('H*',$c)          # first pixel in scan line
         . ("\0" x (4 * $n - 4))  # fill rest of line with zeros
      ) x $n;                     # $n scan lines

Filter Sub for the first line and Up for the remaining lines: 590 bytes

$i = # first scan line
     "\1"                     # filter "Sub"
     . pack('H*',$c)          # first pixel in scan line
     . ("\0" x (4 * $n - 4))  # fill rest of line with zeros
     # remaining scan lines 
     . (
           "\2"               # filter "Up"  
           . "\0" x (4 * $n)  # fill rest of line with zeros
       ) x ($n - 1);

First unfiltered line, then filter Up: 586 bytes

$i = # first scan line
     pack('H*', ("00" . ($c x $n)))  # scan line with filter byte: none
     # remaining scan lines 
     . (
           "\2"               # filter "Up"
           . "\0" x (4 * $n)  # fill rest of line with zeros
       ) x ($n - 1);

Also Compress::Zlib can be tuned; the highest compression level can be set by additional option for the compression level in function compress at the cost of two bytes:

compress ..., 9;


File size of example yellow200.png without filtering decreases from 832 bytes to 472 bytes.
Applied to the example with Sub filter, the file size shrinks from 560 bytes to 445 bytes (pngcrush -brute can't compress further).