summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2010-04-05 23:02:37 +0200
committerAlexander Larsson <alexl@redhat.com>2010-04-05 23:02:37 +0200
commitcaebcf6baa307bc1ae01e4ee0c7835b68cffe2b7 (patch)
tree5e2cba844eaeba216dc05b90cd7b434adc92bbf4
parent6de2fa5fe423a5ddec80fef78f6a9d84d7784ae8 (diff)
RBG png generation
-rw-r--r--daemon.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/daemon.c b/daemon.c
index 434515a..0b44602 100644
--- a/daemon.c
+++ b/daemon.c
@@ -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);