1 /**
2 *
3 * Image handling tools, (c) AJK 2001-2005
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <ctype.h>
25 #ifdef _WIN32
htonl(unsigned i)26 static inline unsigned htonl(unsigned i)
27 {
28 return (i >> 24) | ((i & 0x00ff0000) >> 8) | ((i & 0x0000ff00) << 8) | (i << 24);
29 }
30 #else
31 #include <arpa/inet.h>
32 #endif
33 #include "image.h"
34
35 #include <unistd.h>
36
37 #define INTERLACE
38 #define CLEAR
39 #define USEZLIB
40
41 #ifdef USEZLIB
42 #include <zlib.h>
43 #endif
44
ImageNew(int w,int h,int c)45 Image *ImageNew(int w, int h, int c)
46 { // create a new blank image
47 Image *i = NULL;
48 if (!w || !h)
49 goto err_out;
50 i = calloc(1, sizeof(*i));
51 if (!i)
52 goto err_out;
53 i->W = w;
54 i->L = w + 1;
55 i->H = h;
56 i->C = c;
57 i->Image = calloc(h, w + 1);
58 if (!i->Image)
59 goto err_out;
60 if (c) {
61 i->Colour = calloc(c, sizeof(Colour));
62 if (!i->Colour)
63 goto err_out;
64 }
65 return i;
66
67 err_out:
68 ImageFree(i);
69 return 0;
70 }
71
ImageFree(Image * i)72 void ImageFree(Image * i)
73 { // free an image
74 if (i) {
75 free(i->Image);
76 free(i->Colour);
77 free(i);
78 }
79 }
80
81 // PNG code
82
83 /* Table of CRCs of all 8-bit messages. */
84 static unsigned int crc_table[256];
85
86 /* Make the table for a fast CRC. */
make_crc_table(void)87 static void make_crc_table(void)
88 {
89 unsigned int c;
90 int n, k;
91 for (n = 0; n < 256; n++) {
92 c = (unsigned int)n;
93 for (k = 0; k < 8; k++) {
94 if (c & 1)
95 c = 0xedb88320L ^ (c >> 1);
96 else
97 c = c >> 1;
98 }
99 crc_table[n] = c;
100 }
101 }
102
writecrc(int fh,const char * ptr,int len,unsigned int c)103 static unsigned int writecrc(int fh, const char *ptr, int len, unsigned int c)
104 {
105 write(fh, ptr, len);
106 while (len--)
107 c = crc_table[(c ^ *ptr++) & 0xff] ^ (c >> 8);
108 return c;
109 }
110
writechunk(int fh,const char * typ,const void * ptr,int len)111 static void writechunk(int fh, const char *typ, const void *ptr, int len)
112 {
113 unsigned int v = htonl(len), crc;
114 write(fh, &v, 4);
115 crc = writecrc(fh, typ, 4, ~0);
116 if (len)
117 crc = writecrc(fh, ptr, len, crc);
118 v = htonl(~crc);
119 write(fh, &v, 4);
120 }
121
122 #ifndef USEZLIB
adlersum(const unsigned char * p,int l,unsigned int adler)123 static unsigned int adlersum(const unsigned char *p, int l, unsigned int adler)
124 {
125 unsigned int s1 = (adler & 65535), s2 = (adler >> 16);
126 while (l--) {
127 s1 += *p++;
128 s2 += s1;
129 }
130 s1 %= 65521; // can be delayed due to sensible "l" values...
131 s2 %= 65521;
132 return (s2 << 16) + s1;
133 }
134 #endif
135
136 // write PNG image
ImageWritePNG(Image * i,int fh,int back,int trans,const char * comment)137 void ImageWritePNG(Image * i, int fh, int back, int trans, const char *comment)
138 {
139 make_crc_table();
140 write(fh, "\211PNG\r\n\032\n", 8); // PNG header
141 { // IHDR
142 struct {
143 unsigned int width;
144 unsigned int height;
145 unsigned char depth;
146 unsigned char colour;
147 unsigned char compress;
148 unsigned char filter;
149 unsigned char interlace;
150 } ihdr = {
151 0, 0, 8, 3, 0, 0, 0};
152 ihdr.width = htonl(i->W);
153 ihdr.height = htonl(i->H);
154 writechunk(fh, "IHDR", &ihdr, 13);
155 }
156 { // PLTE
157 unsigned int v = htonl(i->C * 3), crc, n;
158 write(fh, &v, 4);
159 crc = writecrc(fh, "PLTE", 4, ~0);
160 for (n = 0; n < i->C; n++) {
161 v = htonl(i->Colour[n] << 8);
162 crc = writecrc(fh, (void *)&v, 3, crc);
163 }
164 v = htonl(~crc);
165 write(fh, &v, 4);
166 }
167 if (back >= 0) { // bKGD
168 unsigned char b = back;
169 writechunk(fh, "bKGD", &b, 1);
170 }
171 if (*comment) { // tEXt
172 static const char c[] = "Comment";
173 unsigned int v = htonl(strlen(c) + strlen(comment) + 1), crc;
174 write(fh, &v, 4);
175 crc = writecrc(fh, "tEXt", 4, ~0);
176 crc = writecrc(fh, c, strlen(c) + 1, crc);
177 crc = writecrc(fh, comment, strlen(comment), crc);
178 v = htonl(~crc);
179 write(fh, &v, 4);
180 }
181 { // tRNS
182 unsigned char alpha[256];
183 int n;
184 for (n = 0; n < i->C; n++)
185 // 4th palette byte treated as 0=opaque, 255-transparren
186 alpha[n] = 255 - (i->Colour[n] >> 24);
187 if (trans >= 0 && trans < i->C)
188 // manual set of specific transparrent colour
189 alpha[trans] = 0;
190 writechunk(fh, "tRNS", alpha, i->C);
191 }
192 #ifndef USEZLIB
193 { // IDAT
194 unsigned int v = htonl(i->H * (i->L + 5) + 6),
195 crc, adler = 1, n;
196 unsigned char *p = i->Image;
197 write(fh, &v, 4);
198 crc = writecrc(fh, "IDAT", 4, ~0);
199 crc = writecrc(fh, "\170\001", 2, crc); // zlib header for deflate
200 n = i->H;
201 while (n--) {
202 unsigned char h[5];
203 h[0] = (n ? 0 : 1); // last chunk in deflate, un compressed
204 h[1] = (i->L & 255); // Len, LSB first as per deflate spec
205 h[2] = (i->L / 256);
206 h[3] = ~(i->L & 255); // Inverse of Len
207 h[4] = ~(i->L / 256);
208 *p = 0; // filter 0 (NONE)
209 crc = writecrc(fh, h, 5, crc);
210 crc = writecrc(fh, p, i->L, crc);
211 adler = adlersum(p, i->L, adler);
212 p += i->L;
213 }
214 v = htonl(adler);
215 crc = writecrc(fh, (void *)&v, 4, crc);
216 v = htonl(~crc);
217 write(fh, &v, 4);
218 }
219 #else
220 { // IDAT
221 unsigned char *temp;
222 unsigned long n;
223 for (n = 0; n < i->H; n++)
224 i->Image[n * i->L] = 0; // filter 0
225 n = i->H * i->L * 1001 / 1000 + 12;
226 temp = malloc(n);
227 if (compress2(temp, &n, i->Image, i->L * i->H, 9) != Z_OK)
228 fprintf(stderr, "Deflate error\n");
229 else
230 writechunk(fh, "IDAT", temp, n);
231 free(temp);
232 }
233 #endif
234 writechunk(fh, "IEND", 0, 0); // IEND
235 }
236