]>
Commit | Line | Data |
---|---|---|
3df14711 MG |
1 | #include <string.h> |
2 | #include <stdint.h> | |
3 | #include <arpa/inet.h> | |
4 | #include <zlib.h> | |
070fd3ff MG |
5 | #include <stdio.h> |
6 | #include <stdlib.h> | |
3df14711 MG |
7 | |
8 | #include "png.h" | |
9 | ||
e8e713c3 MG |
10 | #define CHUNK 16384 |
11 | #define WIDTH 320 | |
12 | #define HEIGHT 234 | |
13 | ||
3df14711 MG |
14 | /* Table of CRCs of all 8-bit messages. */ |
15 | static unsigned long crc_table[256]; | |
16 | ||
17 | /* Flag: has the table been computed? Initially false. */ | |
18 | static int crc_table_computed = 0; | |
19 | ||
20 | /* Make the table for a fast CRC. */ | |
21 | static void make_crc_table(void) | |
22 | { | |
23 | unsigned long c; | |
24 | int n, k; | |
25 | ||
26 | for (n = 0; n < 256; n++) { | |
27 | c = (unsigned long) n; | |
28 | for (k = 0; k < 8; k++) { | |
29 | if (c & 1) | |
30 | c = 0xedb88320L ^ (c >> 1); | |
31 | else | |
32 | c = c >> 1; | |
33 | } | |
34 | crc_table[n] = c; | |
35 | } | |
36 | crc_table_computed = 1; | |
37 | } | |
38 | ||
39 | /* Update a running CRC with the bytes buf[0..len-1]--the CRC | |
40 | should be initialized to all 1's, and the transmitted value | |
41 | is the 1's complement of the final running CRC (see the | |
42 | crc() routine below). */ | |
43 | ||
44 | static unsigned long update_crc(unsigned long crc, unsigned char *buf, | |
45 | int len) | |
46 | { | |
47 | unsigned long c = crc; | |
48 | int n; | |
49 | ||
50 | if (!crc_table_computed) | |
51 | make_crc_table(); | |
52 | for (n = 0; n < len; n++) { | |
53 | c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); | |
54 | } | |
55 | return c; | |
56 | } | |
57 | ||
58 | /* Return the CRC of the bytes buf[0..len-1]. */ | |
59 | static unsigned long crc(unsigned char *buf, int len) | |
60 | { | |
61 | return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL; | |
62 | } | |
63 | ||
64 | unsigned char *lcd2png(unsigned char *lcd, int *len) | |
65 | { | |
e8e713c3 MG |
66 | unsigned char screen_conv[(WIDTH*HEIGHT*3)+HEIGHT]; /* 320*234 RGB + scanline filter byte */ |
67 | unsigned char *pos; | |
3df14711 | 68 | unsigned char lut[256][3]; |
e8e713c3 MG |
69 | unsigned char *screen_deflated; |
70 | int deflated_size; | |
7ba4ad35 | 71 | unsigned char *image = NULL; |
3df14711 MG |
72 | unsigned char *outpos; |
73 | static const unsigned char png[] = {137, 80, 78, 71, 13, 10, 26, 10}; | |
e8e713c3 MG |
74 | static unsigned char idat[] = {'I', 'D', 'A', 'T'}; |
75 | static unsigned char iend[] = {'I', 'E', 'N', 'D'}; | |
3df14711 MG |
76 | static unsigned char ihdr[] = {'I', 'H', 'D', 'R', |
77 | 0x00, 0x00, 0x01, 0x40, /* 320 - Width */ | |
78 | 0x00, 0x00, 0x00, 0xea, /* 234 - Height */ | |
79 | 0x08, /* Bit depth */ | |
80 | 0x02, /* RGB Truecolor, Colour type */ | |
81 | 0x00, /* Deflate, Compression method */ | |
e8e713c3 | 82 | 0x00, /* Adaptive, Filter method */ |
3df14711 MG |
83 | 0x00 /* No interlace, Interlace method */ |
84 | }; | |
3df14711 MG |
85 | uint32_t l; |
86 | int i; | |
e8e713c3 | 87 | int ret; |
3df14711 | 88 | int toalloc = 0; |
e8e713c3 | 89 | int flush; |
070fd3ff | 90 | z_stream strm; |
3df14711 MG |
91 | |
92 | for(i = 0; i < 256; i++) { | |
93 | lut[i][0] = ((i >> 6) * 0x55); | |
94 | lut[i][1] = ((((i >> 3) & 7) * 0x49) >> 1); | |
95 | lut[i][2] = (((i & 7) * 0x49) >> 1); | |
96 | } | |
97 | ||
e8e713c3 MG |
98 | pos = screen_conv; |
99 | for(i = 0; i < (WIDTH*HEIGHT); i++) { | |
100 | if ((i % WIDTH) == 0) { | |
101 | *pos++ = 0x00; /* No adaptive filter */ | |
102 | } | |
103 | *pos++ = lut[lcd[i]][0]; | |
104 | *pos++ = lut[lcd[i]][1]; | |
105 | *pos++ = lut[lcd[i]][2]; | |
3df14711 MG |
106 | } |
107 | ||
070fd3ff MG |
108 | strm.zalloc = Z_NULL; |
109 | strm.zfree = Z_NULL; | |
110 | strm.opaque = Z_NULL; | |
e8e713c3 | 111 | if (deflateInit(&strm, Z_BEST_COMPRESSION) != Z_OK) { |
070fd3ff MG |
112 | perror("deflateInit"); |
113 | exit(EXIT_FAILURE); | |
114 | } | |
115 | ||
e8e713c3 MG |
116 | strm.avail_in = sizeof(screen_conv); |
117 | strm.next_in = screen_conv; | |
118 | ||
119 | toalloc = 0; | |
7ba4ad35 | 120 | strm.avail_out = 0; |
e8e713c3 MG |
121 | screen_deflated = NULL; |
122 | flush = Z_NO_FLUSH; | |
123 | ||
124 | do { | |
125 | if (strm.avail_out == 0) { | |
126 | toalloc += CHUNK; | |
127 | screen_deflated = realloc(screen_deflated, toalloc); | |
128 | if (screen_deflated == NULL) { | |
129 | perror("realloc"); | |
130 | exit(EXIT_FAILURE); | |
131 | } | |
132 | ||
133 | strm.avail_out = CHUNK; | |
134 | strm.next_out = screen_deflated + (toalloc - CHUNK); | |
135 | } | |
136 | ||
137 | ret = deflate(&strm, flush); | |
138 | if (ret == Z_STREAM_ERROR) { | |
139 | perror("deflate"); | |
140 | exit(EXIT_FAILURE); | |
141 | } | |
142 | ||
143 | if(strm.avail_in == 0) { | |
144 | flush = Z_FINISH; | |
145 | } | |
146 | } while(ret != Z_STREAM_END); | |
147 | deflated_size = toalloc - strm.avail_out; | |
070fd3ff | 148 | |
e8e713c3 MG |
149 | deflateEnd(&strm); |
150 | ||
e8e713c3 MG |
151 | image = malloc(sizeof(png) + |
152 | sizeof(ihdr) + 8 + /* 8 = length, csum */ | |
153 | sizeof(idat) + deflated_size + 8 + | |
154 | sizeof(iend) + 8); | |
155 | ||
156 | if (image == NULL) { | |
157 | perror("malloc"); | |
158 | } | |
159 | ||
3df14711 | 160 | outpos = image; |
7ba4ad35 MG |
161 | |
162 | /* PNG signature */ | |
3df14711 MG |
163 | memcpy(outpos, png, sizeof(png)); |
164 | outpos += sizeof(png); | |
165 | ||
7ba4ad35 | 166 | /* IHDR */ |
3df14711 MG |
167 | l = htonl(sizeof(ihdr) - 4); /* "IHDR" is not counted */ |
168 | memcpy(outpos, &l, sizeof(l)); | |
169 | outpos += sizeof(l); | |
170 | memcpy(outpos, ihdr, sizeof(ihdr)); | |
171 | outpos += sizeof(ihdr); | |
e8e713c3 MG |
172 | l = htonl(crc(ihdr, sizeof(ihdr))); |
173 | memcpy(outpos, &l, sizeof(l)); | |
174 | outpos += sizeof(l); | |
175 | ||
7ba4ad35 | 176 | /* IDAT */ |
e8e713c3 MG |
177 | l = htonl(deflated_size); |
178 | memcpy(outpos, &l, sizeof(l)); | |
179 | outpos += sizeof(l); | |
180 | memcpy(outpos, idat, sizeof(idat)); | |
181 | outpos += sizeof(idat); | |
182 | memcpy(outpos, screen_deflated, deflated_size); | |
183 | free(screen_deflated); | |
184 | outpos +=deflated_size; | |
185 | l = htonl(crc(outpos-deflated_size-sizeof(idat), deflated_size+sizeof(idat))); | |
3df14711 MG |
186 | memcpy(outpos, &l, sizeof(l)); |
187 | outpos += sizeof(l); | |
188 | ||
7ba4ad35 | 189 | /* IEND */ |
3df14711 MG |
190 | l = htonl(sizeof(iend) - 4); /* "IEND" is not counted */ |
191 | memcpy(outpos, &l, sizeof(l)); | |
192 | outpos += sizeof(l); | |
193 | memcpy(outpos, iend, sizeof(iend)); | |
194 | outpos += sizeof(iend); | |
e8e713c3 | 195 | l = htonl(crc(iend, sizeof(iend))); |
3df14711 MG |
196 | memcpy(outpos, &l, sizeof(l)); |
197 | outpos += sizeof(l); | |
198 | ||
199 | *len = (int)(outpos - image); | |
200 | return image; | |
201 | } |