]>
Commit | Line | Data |
---|---|---|
1 | #include <string.h> | |
2 | #include <stdint.h> | |
3 | #include <arpa/inet.h> | |
4 | #include <zlib.h> | |
5 | #include <stdio.h> | |
6 | #include <stdlib.h> | |
7 | ||
8 | #include "png.h" | |
9 | ||
10 | #define CHUNK 16384 | |
11 | #define WIDTH 320 | |
12 | #define HEIGHT 234 | |
13 | ||
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 | { | |
66 | unsigned char screen_conv[(WIDTH*HEIGHT*3)+HEIGHT]; /* 320*234 RGB + scanline filter byte */ | |
67 | unsigned char *pos; | |
68 | unsigned char lut[256][3]; | |
69 | unsigned char *screen_deflated; | |
70 | int deflated_size; | |
71 | unsigned char *image = NULL; | |
72 | unsigned char *outpos; | |
73 | static const unsigned char png[] = {137, 80, 78, 71, 13, 10, 26, 10}; | |
74 | static unsigned char idat[] = {'I', 'D', 'A', 'T'}; | |
75 | static unsigned char iend[] = {'I', 'E', 'N', 'D'}; | |
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 */ | |
82 | 0x00, /* Adaptive, Filter method */ | |
83 | 0x00 /* No interlace, Interlace method */ | |
84 | }; | |
85 | uint32_t l; | |
86 | int i; | |
87 | int ret; | |
88 | int toalloc = 0; | |
89 | int flush; | |
90 | z_stream strm; | |
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 | ||
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]; | |
106 | } | |
107 | ||
108 | strm.zalloc = Z_NULL; | |
109 | strm.zfree = Z_NULL; | |
110 | strm.opaque = Z_NULL; | |
111 | if (deflateInit(&strm, Z_BEST_COMPRESSION) != Z_OK) { | |
112 | perror("deflateInit"); | |
113 | exit(EXIT_FAILURE); | |
114 | } | |
115 | ||
116 | strm.avail_in = sizeof(screen_conv); | |
117 | strm.next_in = screen_conv; | |
118 | ||
119 | toalloc = 0; | |
120 | strm.avail_out = 0; | |
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; | |
148 | ||
149 | deflateEnd(&strm); | |
150 | ||
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 | return NULL; | |
159 | } | |
160 | ||
161 | outpos = image; | |
162 | ||
163 | /* PNG signature */ | |
164 | memcpy(outpos, png, sizeof(png)); | |
165 | outpos += sizeof(png); | |
166 | ||
167 | /* IHDR */ | |
168 | l = htonl(sizeof(ihdr) - 4); /* "IHDR" is not counted */ | |
169 | memcpy(outpos, &l, sizeof(l)); | |
170 | outpos += sizeof(l); | |
171 | memcpy(outpos, ihdr, sizeof(ihdr)); | |
172 | outpos += sizeof(ihdr); | |
173 | l = htonl(crc(ihdr, sizeof(ihdr))); | |
174 | memcpy(outpos, &l, sizeof(l)); | |
175 | outpos += sizeof(l); | |
176 | ||
177 | /* IDAT */ | |
178 | l = htonl(deflated_size); | |
179 | memcpy(outpos, &l, sizeof(l)); | |
180 | outpos += sizeof(l); | |
181 | memcpy(outpos, idat, sizeof(idat)); | |
182 | outpos += sizeof(idat); | |
183 | memcpy(outpos, screen_deflated, deflated_size); | |
184 | free(screen_deflated); | |
185 | outpos +=deflated_size; | |
186 | l = htonl(crc(outpos-deflated_size-sizeof(idat), deflated_size+sizeof(idat))); | |
187 | memcpy(outpos, &l, sizeof(l)); | |
188 | outpos += sizeof(l); | |
189 | ||
190 | /* IEND */ | |
191 | l = htonl(sizeof(iend) - 4); /* "IEND" is not counted */ | |
192 | memcpy(outpos, &l, sizeof(l)); | |
193 | outpos += sizeof(l); | |
194 | memcpy(outpos, iend, sizeof(iend)); | |
195 | outpos += sizeof(iend); | |
196 | l = htonl(crc(iend, sizeof(iend))); | |
197 | memcpy(outpos, &l, sizeof(l)); | |
198 | outpos += sizeof(l); | |
199 | ||
200 | *len = (int)(outpos - image); | |
201 | return image; | |
202 | } |