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