diff options
author | Alexander Larsson <alexl@redhat.com> | 2010-04-05 23:02:37 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2010-04-05 23:02:37 +0200 |
commit | caebcf6baa307bc1ae01e4ee0c7835b68cffe2b7 (patch) | |
tree | 5e2cba844eaeba216dc05b90cd7b434adc92bbf4 | |
parent | 6de2fa5fe423a5ddec80fef78f6a9d84d7784ae8 (diff) |
RBG png generation
-rw-r--r-- | daemon.c | 166 |
1 files changed, 166 insertions, 0 deletions
@@ -293,12 +293,178 @@ handler (GThreadedSocketService *service, return res; } +/* Table of CRCs of all 8-bit messages. */ +static unsigned long crc_table[256]; + +/* Flag: has the table been computed? Initially false. */ +static int crc_table_computed = 0; + +/* Make the table for a fast CRC. */ +static void +make_crc_table(void) +{ + unsigned long c; + int n, k; + + for (n = 0; n < 256; n++) { + c = (unsigned long) n; + for (k = 0; k < 8; k++) { + if (c & 1) + c = 0xedb88320L ^ (c >> 1); + else + c = c >> 1; + } + crc_table[n] = c; + } + crc_table_computed = 1; +} + +static unsigned long +update_crc(unsigned long crc, unsigned char *buf, int len) +{ + unsigned long c = crc; + int n; + + if (!crc_table_computed) + make_crc_table(); + for (n = 0; n < len; n++) { + c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c; +} + +static unsigned long +crc(unsigned char *buf, int len) +{ + return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL; +} + +#define BASE 65521 /* largest prime smaller than 65536 */ +static unsigned long +update_adler32(unsigned long adler, unsigned char *buf, int len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int n; + + for (n = 0; n < len; n++) { + s1 = (s1 + buf[n]) % BASE; + s2 = (s2 + s1) % BASE; + } + return (s2 << 16) + s1; +} + +/* Return the adler32 of the bytes buf[0..len-1] */ + +static unsigned long adler32(unsigned char *buf, int len) +{ + return update_adler32(1L, buf, len); +} + +guchar * +to_png_rgb (int w, int h, int stride, guint32 *data, gsize *size_out) +{ + guchar header[] = {137, 80, 78, 71, 13, 10, 26, 10}; + guchar ihdr[13+12] = {0, 0, 0, 13, 'I', 'H', 'D', 'R', + /* w: */ 0, 0, 0, 0, /* h: */ 0,0,0,0, + /* bpp: */ 8, /* color type: */ 2, + 0, 0, 0}; + guchar idat_start[8] = { /* len: */0, 0, 0, 0, 'I', 'D', 'A', 'T' }; + guchar iend[12] = {0, 0, 0, 0, 'I', 'E', 'N', 'D', 0xae, 0x42, 0x60, 0x82}; + gsize data_size, row_size; + char row_header[6]; + guint8 *png, *p, *p_row, *p_idat; + guint32 *row; + unsigned long adler; + guint32 pixel; + int x, y; + + *(guint32 *)&ihdr[8] = GUINT32_TO_BE(w); + *(guint32 *)&ihdr[12] = GUINT32_TO_BE(h); + *(guint32 *)&ihdr[21] = GUINT32_TO_BE(crc(&ihdr[4], 13 + 4)); + + row_size = 1 + w * 3; + row_header[0] = 0; + row_header[1] = row_size & 0xff; + row_header[2] = (row_size >> 8) & 0xff; + row_header[3] = ~row_header[1]; + row_header[4] = ~row_header[2]; + row_header[5] = 0; + + data_size = 2 + (6 + w * 3) * h + 4; + + *(guint32 *)&idat_start[0] = GUINT32_TO_BE(data_size); + + *size_out = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend); + png = g_malloc (*size_out); + + p = png; + memcpy (p, header, sizeof(header)); + p += sizeof(header); + memcpy (p, ihdr, sizeof(ihdr)); + p += sizeof(ihdr); + memcpy (p, idat_start, sizeof(idat_start)); + p += sizeof(idat_start); + + /* IDAT data: + + zlib header: 0x78, 0x01 , + h * scanline: row_header[] + width * r,g,b + checksum: adler32 + */ + + p_idat = p - 4; + + /* zlib header */ + *p++ = 0x78; + *p++ = 0x01; + + adler = 1; + + /* scanline data */ + for (y = 0; y < h; y++) { + if (y == h - 1) + row_header[0] = 1; /* final block */ + memcpy (p, row_header, sizeof(row_header)); + p += sizeof(row_header); + p_row = p - 1; + row = data; + data += stride; + for (x = 0; x < w; x++) { + pixel = *row++; + *p++ = (pixel >> 16) & 0xff; /* red */ + *p++ = (pixel >> 8) & 0xff; /* green */ + *p++ = (pixel >> 0) & 0xff; /* blue */ + } + adler = update_adler32(adler, p_row, p - p_row); + } + + /* adler32 */ + *(guint32 *)p = GUINT32_TO_BE(adler); + p += 4; + *(guint32 *)p = GUINT32_TO_BE(crc(p_idat, p - p_idat)); + p += 4; + + memcpy (p, iend, sizeof(iend)); + p += sizeof(iend); + + g_assert(p - png == *size_out); + + return png; +} + int main (int argc, char *argv[]) { GSocketService *service; GOptionContext *context; GError *error = NULL; + guint32 pixel[4] = {0xffffff, 0xff0000, 0xff00ff, 0x00ff00}; + guchar *data; + gsize data_size; + + data = to_png_rgb (2, 2, 2, pixel, &data_size); + //g_file_set_contents ("mini.png", (char *)data, data_size, NULL); g_type_init (); g_thread_init (NULL); |