
/*
 *  dragon-logo.c -- one-shot program to generate the dragon-logo.png image
 *
 *  2007-11-22 (marcelk) Created from scratch
 *  2007-11-23 (marcelk) Fixed pixel layout problem in logo
 *
 *  Compile:
 *      gcc --std=c99 -Wall -lz dragon-logo.c -o dragon-logo
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "zlib.h"

#define WIDTH 0x4d
#define HEIGHT 0x2f

static
unsigned char head[] = {
/* PNG signature */
        0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,

/* IHDR -- Image header */

        0, 0, 0, 0x0d,
        'I', 'H', 'D', 'R',
        0, 0, 0, WIDTH, // width
        0, 0, 0, HEIGHT,// height
        1,              // bit depth
        3,              // colour type: 3=indexed-colour
        0,              // compression method: 0=deflate
        0,              // filter method
        0,              // interlace method
        0x9c, 0xfb, 0xd5, 0xa2, // CRC-32

/* PLTE -- palette */

        0, 0, 0, 6,
        'P', 'L', 'T', 'E',

        255, 255, 255,      // white
        0x40, 0x40, 0x40,   // grey
        0xa3, 0xfd, 0x50, 0x2b, // CRC-32

/* tRNS -- transparancy data */

        0, 0, 0, 1,
        't', 'R', 'N', 'S',
        0,                      // the first palette entry is fully transparant
        0x40, 0xe6, 0xd8, 0x66, // CRC-32

/* IDAT */

        0, 0, 0, 84,
        'I', 'D', 'A', 'T',

        // CMF = 0x28 
        // .CM = %1000 = 8 (compression method: 8 deflate)
        // .CINFO = %0010 (window size: 1024)
        // FLG = 0xcf
        // .FCHECK %01111 (checksum: 0x28cf = 10447 = 337 * 31 OK)
        // .FDICT = %0 = no dictionary
        // .FLEVEL = %11 = max compression


        0x28, 0xcf, 0x63, 0x62, 0x60, 0xfc, 0xff, 0x9f,
        0x81, 0xfd, 0xff, 0x1f, 0x06, 0x06, 0x26, 0x06,
        0x38, 0x00, 0x32, 0x1b, 0x59, 0x18, 0xfe, 0x33,
        0x0a, 0xa0, 0x8b, 0x0e, 0x10, 0xf3, 0xff, 0x3f,
        0x06, 0x86, 0xff, 0x3f, 0xff, 0x7f, 0x40, 0x15,
        0x3d, 0xc8, 0xd8, 0xf0, 0x97, 0x91, 0x9d, 0x91,
        0x65, 0x90, 0x38, 0xd2, 0xfe, 0x7f, 0x03, 0x03,
        0x30, 0x34, 0xff, 0x30, 0x48, 0x20, 0x8b, 0x32,
        0x32, 0x02, 0x45, 0x7f, 0x0e, 0x9a, 0x90, 0x84,
        0xd2, 0xcc, 0xff, 0x1f, 0x20, 0x89, 0x02, 0x00,
        0x1e, 0x02, 0x15, 0x65,

        0x83, 0x3b, 0xf9, 0x20, // CRC-32

/* IEND */

        0, 0, 0, 0,
        'I', 'E', 'N', 'D',
        // no data
        0xae, 0x42, 0x60, 0x82, // CRC-32
};

static
char bitmap[HEIGHT][WIDTH] = {
"---------------#################-------------#################---------------",
"---------------#################-------------#################---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"---------------##-------------##-------------##-------------##---------------",
"#################-------------################################---------------",
"#################-------------################################---------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"##-------------------------------------------##------------------------------",
"#################----------------------------#################-------------##",
"#################----------------------------#################-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------##-------------##",
"------------------------------------------------------------#################",
"------------------------------------------------------------#################",
};

int main(void)
{
        FILE *fp = fopen("dragon-logo.png", "wb");
        if (!fp) abort();

        int r = fwrite(head, 1, sizeof head, fp);
        if (r != sizeof head) perror("fwrite");

        unsigned char previous[99] = {0, };

        unsigned char out[999];
        int out_ix = 0;

        for (int y=0; y<HEIGHT; y++) {

                out[out_ix++] = 2; /* filter-type 'Up' */

                /* convert pixels to bytes */

                unsigned char current[99];

                int byte_ix = 0;
                int byte = 0;
                int bits = 0;
                for (int x=0; x<WIDTH; x++) {
                        if (bitmap[y][x] == '#') {
                                byte |= 1 << (7 - bits);
                        }
                        bits++;

                        if (bits == 8) {
                                current[byte_ix] = byte;
                                byte_ix++;
                                byte = 0;
                                bits = 0;
                        }
                }
                if (bits > 0) {
                        current[byte_ix] = byte;
                        byte_ix++;
                }

                /* filter algorithm */

                for (int ix=0; ix<byte_ix; ix++){ 
                        int byte_out = (current[ix] - previous[ix]) & 0xff;
                        out[out_ix++] = byte_out;
                }

                memcpy(previous, current, byte_ix);
        }

        /* compression */

        unsigned char zipped[1024];

        z_stream strm; 
        strm.zalloc = Z_NULL;
        strm.zfree = Z_NULL;
        strm.opaque = Z_NULL;

        r = deflateInit2(&strm,
                9,              // level
                Z_DEFLATED,     // method
                10,             // windowBits
                1,              // memLevel
                Z_DEFAULT_STRATEGY // strategy
        );
        if (r != Z_OK) exit(r);

        strm.next_in = out;
        strm.avail_in = out_ix;
        strm.next_out = zipped;
        strm.avail_out = sizeof(zipped);

        r = deflate(&strm, Z_FINISH);
        if (r != Z_STREAM_END) exit(r);

        printf("compressed:");
        int zipped_bytes = (sizeof zipped) - strm.avail_out;
        for (int i=0; i<zipped_bytes; i++) {
                printf(" 0x%02x,", zipped[i]);
        }
        printf("\n%d bytes\n", zipped_bytes);

        deflateEnd(&strm);

        fclose(fp);
        return 0;
}
