diff options
Diffstat (limited to 'daemon.c')
-rw-r--r-- | daemon.c | 134 |
1 files changed, 134 insertions, 0 deletions
@@ -368,6 +368,114 @@ to_png_rgb (int w, int h, int stride, guint32 *data) return url; } +char * +to_png_rgba (int w, int h, int stride, guint32 *data) +{ + 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: */ 6, + 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; + gsize png_size; + int x, y; + char *url, *url_base64; + gint state = 0, outlen; + gint save = 0; + + *(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 * 4; + 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 * 4) * h + 4; + + *(guint32 *)&idat_start[0] = GUINT32_TO_BE(data_size); + + png_size = sizeof(header) + sizeof(ihdr) + 12 + data_size + sizeof(iend); + png = g_malloc (png_size); + + 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,a + 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 */ + *p++ = (pixel >> 24) & 0xff; /* alpha */ + } + 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 == png_size); + + url = g_malloc (strlen("data:image/png;base64,") + + ((png_size / 3 + 1) * 4 + 4) + 1); + strcpy (url, "data:image/png;base64,"); + + url_base64 = url + strlen("data:image/png;base64,"); + outlen = g_base64_encode_step (png, png_size, FALSE, url_base64, &state, &save); + outlen += g_base64_encode_close (FALSE, url_base64 + outlen, &state, &save); + url_base64[outlen] = 0; + + g_free (png); + + return url; +} + static void send_image_rgb (GOutputStream *out, int x, int y, int w, int h, int stride, guint32 *data) @@ -393,7 +501,30 @@ send_image_rgb (GOutputStream *out, int x, int y, g_free (url); } +static void +send_image_rgba (GOutputStream *out, int x, int y, + int w, int h, int stride, guint32 *data) +{ + char buf[13]; + gsize len; + char *url; + + buf[0] = 'i'; + base64_uint16(x, &buf[1]); + base64_uint16(y, &buf[4]); + + url = to_png_rgba (w, h, stride, data); + len = strlen (url); + base64_uint32(len, &buf[7]); + g_output_stream_write_all (out, buf, 13, + NULL, NULL, NULL); + + g_output_stream_write_all (out, url, len, + NULL, NULL, NULL); + + g_free (url); +} static void send_boundary (GOutputStream *out) @@ -423,6 +554,7 @@ send_draw_ops (GOutputStream *out) char *header; int i; guint32 pixel[4] = {0xffffff, 0xff0000, 0xff00ff, 0x00ff00}; + guint32 pixela[4] = {0xffffffff, 0x80ffffff, 0x40ffffff, 0x20ffffff}; header = "HTTP/1.1 200 OK\r\n" @@ -444,6 +576,8 @@ send_draw_ops (GOutputStream *out) send_select_surface(cout, 1); send_rgb (cout, 0x00ff00); send_rect (cout, 0, 0, 25, 25); + send_image_rgba (cout, 0, 0, + 2, 2, 2, pixela); send_select_surface(cout, 0); while (1) |