]> cvs.zerfleddert.de Git - rigol/blobdiff - png.c
don't continue when malloc bails out
[rigol] / png.c
diff --git a/png.c b/png.c
index 98d599371717c7f4fe3062d92328530fc426ad6f..ac09767fb8597d11b910a22db48b3a5dcf804319 100644 (file)
--- a/png.c
+++ b/png.c
@@ -2,9 +2,15 @@
 #include <stdint.h>
 #include <arpa/inet.h>
 #include <zlib.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 #include "png.h"
 
+#define CHUNK 16384
+#define WIDTH 320
+#define HEIGHT 234
+
 /* Table of CRCs of all 8-bit messages. */
 static unsigned long crc_table[256];
 
@@ -57,25 +63,31 @@ static unsigned long crc(unsigned char *buf, int len)
 
 unsigned char *lcd2png(unsigned char *lcd, int *len)
 {
-       unsigned char screen_conv[320*234*3];
+       unsigned char screen_conv[(WIDTH*HEIGHT*3)+HEIGHT]; /* 320*234 RGB + scanline filter byte */
+       unsigned char *pos;
        unsigned char lut[256][3];
-       unsigned char *image;
+       unsigned char *screen_deflated;
+       int deflated_size;
+       unsigned char *image = NULL;
        unsigned char *outpos;
        static const unsigned char png[] = {137, 80, 78, 71, 13, 10, 26, 10};
+       static unsigned char idat[] = {'I', 'D', 'A', 'T'};
+       static unsigned char iend[] = {'I', 'E', 'N', 'D'};
        static unsigned char ihdr[] = {'I', 'H', 'D', 'R',
                0x00, 0x00, 0x01, 0x40, /* 320 - Width */
                0x00, 0x00, 0x00, 0xea, /* 234 - Height */
                0x08, /* Bit depth */
                0x02, /* RGB Truecolor, Colour type */
                0x00, /* Deflate, Compression method */
-               0x00, /* None, Filter method */
+               0x00, /* Adaptive, Filter method */
                0x00  /* No interlace, Interlace method */
                };
-       static unsigned char idat[] = {'I', 'D', 'A', 'T'};
-       static unsigned char iend[] = {'I', 'E', 'N', 'D'};
        uint32_t l;
        int i;
+       int ret;
        int toalloc = 0;
+       int flush;
+       z_stream strm;
 
        for(i = 0; i < 256; i++) {
                lut[i][0] = ((i >> 6) * 0x55);
@@ -83,32 +95,105 @@ unsigned char *lcd2png(unsigned char *lcd, int *len)
                lut[i][2] = (((i & 7) * 0x49) >> 1);
        }
 
-       for(i = 0; i < sizeof(screen_conv); i += 3) {
-               screen_conv[i] = lut[lcd[i/3]][0];
-               screen_conv[i+1] = lut[lcd[i/3]][1];
-               screen_conv[i+2] = lut[lcd[i/3]][2];
+       pos = screen_conv;
+       for(i = 0; i < (WIDTH*HEIGHT); i++) {
+               if ((i % WIDTH) == 0) {
+                       *pos++ = 0x00; /* No adaptive filter */
+               }
+               *pos++ = lut[lcd[i]][0];
+               *pos++ = lut[lcd[i]][1];
+               *pos++ = lut[lcd[i]][2];
+       }
+
+       strm.zalloc = Z_NULL;
+       strm.zfree = Z_NULL;
+       strm.opaque = Z_NULL;
+       if (deflateInit(&strm, Z_BEST_COMPRESSION) != Z_OK) {
+               perror("deflateInit");
+               exit(EXIT_FAILURE);
        }
 
-       image = malloc(320*234*2); /* TODO: FIXME! */
+       strm.avail_in = sizeof(screen_conv);
+       strm.next_in = screen_conv;
+
+       toalloc = 0;
+       strm.avail_out = 0;
+       screen_deflated = NULL;
+       flush = Z_NO_FLUSH;
+
+       do {
+               if (strm.avail_out == 0) {
+                       toalloc += CHUNK;
+                       screen_deflated = realloc(screen_deflated, toalloc);
+                       if (screen_deflated == NULL) {
+                               perror("realloc");
+                               exit(EXIT_FAILURE);
+                       }
+
+                       strm.avail_out = CHUNK;
+                       strm.next_out = screen_deflated + (toalloc - CHUNK);
+               }
+
+               ret = deflate(&strm, flush);
+               if (ret == Z_STREAM_ERROR) {
+                       perror("deflate");
+                       exit(EXIT_FAILURE);
+               }
+
+               if(strm.avail_in == 0) {
+                       flush = Z_FINISH;
+               }
+       } while(ret != Z_STREAM_END);
+       deflated_size = toalloc - strm.avail_out;
+
+       deflateEnd(&strm);
+
+       image = malloc(sizeof(png) +
+               sizeof(ihdr) + 8 + /* 8 = length, csum */
+               sizeof(idat) + deflated_size + 8 +
+               sizeof(iend) + 8);
+       
+       if (image == NULL) {
+               perror("malloc");
+               return NULL;
+       }
+       
        outpos = image;
+
+       /* PNG signature */
        memcpy(outpos, png, sizeof(png));
        outpos += sizeof(png);
 
+       /* IHDR */
        l = htonl(sizeof(ihdr) - 4); /* "IHDR" is not counted */
        memcpy(outpos, &l, sizeof(l));
        outpos += sizeof(l);
        memcpy(outpos, ihdr, sizeof(ihdr));
        outpos += sizeof(ihdr);
-       l = crc(ihdr, sizeof(ihdr));
+       l = htonl(crc(ihdr, sizeof(ihdr)));
+       memcpy(outpos, &l, sizeof(l));
+       outpos += sizeof(l);
+
+       /* IDAT */
+       l = htonl(deflated_size);
+       memcpy(outpos, &l, sizeof(l));
+       outpos += sizeof(l);
+       memcpy(outpos, idat, sizeof(idat));
+       outpos += sizeof(idat);
+       memcpy(outpos, screen_deflated, deflated_size);
+       free(screen_deflated);
+       outpos +=deflated_size;
+       l = htonl(crc(outpos-deflated_size-sizeof(idat), deflated_size+sizeof(idat)));
        memcpy(outpos, &l, sizeof(l));
        outpos += sizeof(l);
 
+       /* IEND */
        l = htonl(sizeof(iend) - 4); /* "IEND" is not counted */
        memcpy(outpos, &l, sizeof(l));
        outpos += sizeof(l);
        memcpy(outpos, iend, sizeof(iend));
        outpos += sizeof(iend);
-       l = crc(iend, sizeof(iend));
+       l = htonl(crc(iend, sizeof(iend)));
        memcpy(outpos, &l, sizeof(l));
        outpos += sizeof(l);
 
Impressum, Datenschutz