1 /* Quat - A 3D fractal generation program */
2 /* Copyright (C) 1997,98 Dirk Meyer */
3 /* (email: dirk.meyer@studserv.uni-stuttgart.de) */
4 /* mail: Dirk Meyer */
5 /* Marbacher Weg 29 */
6 /* D-71334 Waiblingen */
7 /* Germany */
8 /* */
9 /* This program is free software; you can redistribute it and/or */
10 /* modify it under the terms of the GNU General Public License */
11 /* as published by the Free Software Foundation; either version 2 */
12 /* of the License, or (at your option) any later version. */
13 /* */
14 /* This program is distributed in the hope that it will be useful, */
15 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
16 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
17 /* GNU General Public License for more details. */
18 /* */
19 /* You should have received a copy of the GNU General Public License */
20 /* along with this program; if not, write to the Free Software */
21 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h> /* malloc, free */
29 #include <string.h>
30 #include <math.h>
31 #include "png.h"
32
33 void make_crc_table(void);
34 unsigned long update_crc(unsigned long crc, const unsigned char *buf, long len);
35 unsigned long crc(unsigned char *buf, long len);
36 int do_deflate(struct png_internal_struct *i);
37 unsigned char PaethPredictor(unsigned char a, unsigned char b, unsigned char c);
38
39 /* NOTE: In this (new) version of PNG.C the buffer "readbuf" in */
40 /* png_internal_struct is allocated via malloc */
41 /* a call of EndPNG() is needed after use of these structure */
42 /* to deallocate the buffer */
43
44 unsigned char png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
45
46 unsigned long crc_table[256];
47 int crc_table_computed = 0;
48
make_crc_table(void)49 void make_crc_table(void)
50 {
51 unsigned long c;
52 int n, k;
53
54 for (n = 0; n < 256; n++)
55 {
56 c = (unsigned long) n;
57 for (k = 0; k < 8; k++)
58 {
59 if (c & 1) c = 0xedb88320L ^ (c >> 1);
60 else c = c >> 1;
61 }
62 crc_table[n] = c;
63 }
64 crc_table_computed = 1;
65 }
66
update_crc(unsigned long crc,const unsigned char * buf,long len)67 unsigned long update_crc(unsigned long crc, const unsigned char *buf, long len)
68 {
69 unsigned long c = crc;
70 int n;
71
72 if (!crc_table_computed) make_crc_table();
73 for (n = 0; n < len; n++)
74 {
75 c = crc_table[(int)((c ^ (long)buf[n]) & 0xffL)] ^ (c >> 8);
76 }
77 return(c);
78 }
79
crc(unsigned char * buf,long len)80 unsigned long crc(unsigned char *buf, long len)
81 {
82 return(update_crc(0xffffffffL, buf, len) ^ 0xffffffffL);
83 }
84
CorrectLong1(unsigned long * l,unsigned char * Buf)85 int CorrectLong1(unsigned long *l, unsigned char *Buf)
86 {
87 Buf[0] = (unsigned char)(*l>>24 & 0xffL);
88 Buf[1] = (unsigned char)(*l>>16 & 0xffL);
89 Buf[2] = (unsigned char)(*l>>8 & 0xffL);
90 Buf[3] = (unsigned char)(*l & 0xffL);
91
92 return(0);
93 }
94
CorrectLong2(unsigned char * Buf,unsigned long * l)95 int CorrectLong2(unsigned char *Buf, unsigned long *l)
96 {
97 *l = Buf[0]; *l <<= 8;
98 *l |= Buf[1]; *l <<= 8;
99 *l |= Buf[2]; *l <<= 8;
100 *l |= Buf[3];
101
102 return(0);
103 }
104
InitPNG(FILE * png,struct png_info_struct * info,struct png_internal_struct * internal)105 int InitPNG(FILE *png, struct png_info_struct *info, struct png_internal_struct *internal)
106 {
107 unsigned char sig[8], LongBuf[4], infobuf[100];
108 size_t max;
109
110 internal->readbuf_initialized = 0; /* for EndPNG, if no valid file */
111 internal->png = png;
112 fseek(internal->png, 0L, SEEK_SET);
113 fread(sig, 1, 8, internal->png);
114 {
115 int i;
116 for (i=0; i<8; ++i) if (sig[i] != png_signature[i]) return -1;
117 }
118 /* if (strncmp(sig, png_signature, 8)!=0) return(-1); */
119 fread(LongBuf, 1, 4, internal->png);
120 CorrectLong2(LongBuf, &internal->length);
121 fread(internal->chunk_type, 1, 4, internal->png);
122 if (strncmp(internal->chunk_type, "IHDR", 4)!=0) return(-1);
123 max = (size_t)internal->length;
124 if (sizeof(struct png_info_struct)<max) max = sizeof(struct png_info_struct);
125 if (max>100) max = 100; /* should never happen in IHDR! */
126 fread(infobuf, 1, max, internal->png);
127 {
128 unsigned long l;
129 CorrectLong2(&infobuf[0], &l); info->width = l;
130 CorrectLong2(&infobuf[4], &l); info->height = l;
131 }
132 info->bit_depth = infobuf[8];
133 info->color_type = infobuf[9];
134 info->compression = infobuf[10];
135 info->filter = infobuf[11];
136 info->interlace = infobuf[12];
137 fread(LongBuf, 1, 4, internal->png);
138 CorrectLong2(LongBuf, &internal->crc);
139 memcpy(internal, info, sizeof(struct png_info_struct));
140 internal->PLTE = 0;
141 internal->position = 0;
142 internal->zlib_initialized = 0;
143 internal->readbuf_initialized = 0;
144 internal->buf_filled = 0;
145 internal->chunk_pos = 0;
146 internal->readbuf = NULL;
147 return(0);
148 }
149
GetNextChunk(struct png_internal_struct * i)150 int GetNextChunk(struct png_internal_struct *i)
151 {
152 unsigned char LongBuf[4];
153
154 if (i->position==1)
155 fseek(i->png, (long)i->length+4, SEEK_CUR);
156 else if (i->position==2)
157 fseek(i->png, 4L, SEEK_CUR);
158 i->position=1;
159 fread(LongBuf, 1, 4, i->png);
160 CorrectLong2(LongBuf, &i->length);
161 fread(i->chunk_type, 1, 4, i->png);
162 if (strncmp(i->chunk_type, "PLTE", 4)==0) i->PLTE++;
163
164 return(0);
165 }
166
ReadChunkData(struct png_internal_struct * i,byte * mem)167 int ReadChunkData(struct png_internal_struct *i, byte *mem)
168 {
169 unsigned long checksum;
170 unsigned char LongBuf[4];
171
172 if (i->position!=1) return(-1);
173 i->mem_ptr = mem;
174 fread(i->mem_ptr, 1, (size_t)i->length, i->png);
175 fread(LongBuf, 1, 4, i->png);
176 CorrectLong2(LongBuf, &i->crc);
177 checksum = update_crc(0xffffffffL, (unsigned char*)i->chunk_type, 4);
178 checksum = update_crc(checksum, i->mem_ptr, (long)i->length);
179 checksum ^= 0xffffffffL;
180 if (checksum!=i->crc) return(-2);
181 i->position = 0;
182
183 return(0);
184 }
185
do_inflate(struct png_internal_struct * i)186 int do_inflate(struct png_internal_struct *i)
187 {
188 int err;
189
190 if (i->zlib_initialized==0)
191 {
192 i->zlib_initialized = 1;
193 i->d_stream.zalloc = (alloc_func)0;
194 i->d_stream.zfree = (free_func)0;
195
196 err = inflateInit(&i->d_stream);
197 }
198
199 err = inflate(&i->d_stream, Z_NO_FLUSH);
200
201 if (err == Z_STREAM_END)
202 {
203 err = inflateEnd(&i->d_stream);
204 return(10);
205 }
206 return(err);
207 }
208
ReadPNGLine(struct png_internal_struct * i,unsigned char * Buf)209 int ReadPNGLine(struct png_internal_struct *i, unsigned char *Buf)
210 {
211 long toread;
212 int err;
213 int ByPP;
214 unsigned char LongBuf[4];
215
216 /* Test, if chunk is IDAT */
217 if (strncmp(i->chunk_type, "IDAT", 4)!=0) return(-1);
218
219 /* Initialize on first call */
220 if (i->chunk_pos==0) i->checksum = update_crc(0xffffffffL, (unsigned char*)i->chunk_type, 4);
221 if (i->readbuf_initialized==0)
222 {
223 i->readbuf = malloc(BSIZE);
224 if (!i->readbuf) return(-2); /* Memory error */
225 i->readbuf_initialized = 1;
226 }
227
228 if (i->buf_filled==0)
229 {
230 toread = (i->length-i->chunk_pos);
231 if (toread>BSIZE) toread = BSIZE;
232 i->buf_filled = fread(i->readbuf, (size_t)1, (size_t)toread, i->png);
233 if (i->buf_filled == 0L) return(-1);
234 i->buf_pos = 0;
235 i->chunk_pos += i->buf_filled;
236 i->checksum = update_crc(i->checksum, i->readbuf, toread);
237 }
238
239 ByPP = (int)ceil((double)i->bit_depth/8);
240 if (i->color_type==2) ByPP *= 3;
241
242 /* Only decompress a single line & filter byte */
243 i->d_stream.avail_out = (int)(i->width*ByPP+1);
244 i->d_stream.next_out = Buf;
245
246 if (i->color_type==3)
247 {
248 switch (i->bit_depth)
249 {
250 case 1 : i->d_stream.avail_out = (int)(i->width/8+1); break;
251 case 2 : i->d_stream.avail_out = (int)(i->width/4+1); break;
252 case 4 : i->d_stream.avail_out = (int)(i->width/2+1); break;
253 }
254 }
255
256 do
257 {
258 i->d_stream.next_in = i->readbuf+i->buf_pos;
259 i->d_stream.avail_in = i->buf_filled-i->buf_pos;
260 err = do_inflate(i);
261 i->buf_pos = (unsigned int)(i->d_stream.next_in-i->readbuf);
262
263 /* ready ? */
264 if (i->d_stream.avail_out==0) break;
265 /* no process made */
266 if ( i->d_stream.avail_out!=0 || i->buf_pos==i->buf_filled )
267 {
268 /* because chunk at end */
269 if (i->chunk_pos==i->length)
270 {
271 /* verify crc */
272 i->checksum ^= 0xffffffffL;
273 fread(LongBuf, 1, 4, i->png);
274 CorrectLong2(LongBuf, &i->crc);
275 i->position = 0;
276 if (i->checksum!=i->crc) return(-2);
277 /* read next chunk header */
278 fread(LongBuf, 1, 4, i->png);
279 CorrectLong2(LongBuf, &i->length);
280 fread(i->chunk_type, 1, 4,i->png);
281 i->position = 1;
282 /* is it an IDAT chunk? */
283 if (strncmp(i->chunk_type, "IDAT", 4)!=0) return(-3);
284 /* initialize checksum */
285 i->checksum = update_crc(0xffffffffL, (unsigned char*)i->chunk_type, 4);
286 /* prepare reading chunk data */
287 i->chunk_pos = 0;
288 toread = i->length;
289 if (toread>BSIZE) toread = BSIZE;
290 i->buf_filled = fread(i->readbuf, 1, (size_t)toread, i->png);
291 if (i->buf_filled == 0L) return(-1);
292 i->buf_pos = 0;
293 i->chunk_pos += i->buf_filled;
294 i->checksum = update_crc(i->checksum, i->readbuf, toread);
295 }
296 /* because 2K buffer at end */
297 else
298 {
299 toread = (i->length-i->chunk_pos);
300 if (toread>BSIZE) toread = BSIZE;
301 i->buf_filled = fread(i->readbuf, 1, (size_t)toread, i->png);
302 if (i->buf_filled == 0L) return(-1);
303 i->buf_pos = 0;
304 i->chunk_pos += i->buf_filled;
305 i->checksum = update_crc(i->checksum, i->readbuf, toread);
306 }
307 }
308 } while (i->d_stream.avail_out!=0);
309
310 return(0);
311 }
312
PaethPredictor(unsigned char a,unsigned char b,unsigned char c)313 unsigned char PaethPredictor(unsigned char a, unsigned char b, unsigned char c)
314 {
315 int p;
316 unsigned int pa, pb, pc;
317
318 /* a = left, b = above, c = upper left */
319 p = a + b - c;
320 pa = abs(p - a);
321 pb = abs(p - b);
322 pc = abs(p - c);
323 if (pa <= pb && pa <= pc) return a;
324 else if (pb <= pc) return b;
325 else return c;
326 }
327
DoUnFiltering(struct png_internal_struct * i,unsigned char * Buf,unsigned char * Buf_up)328 int DoUnFiltering(struct png_internal_struct *i, unsigned char *Buf, unsigned char *Buf_up)
329 {
330 unsigned long ByPP, uj;
331 long up, prior, upperleft;
332
333 ByPP = (unsigned long)ceil((double)i->bit_depth/8.0);
334 if (i->color_type==2) ByPP *= 3;
335 switch (Buf[0])
336 {
337 case 0: break; /* No filter */
338 case 1: /* Sub */
339 for (uj=ByPP+1; uj<=i->width*ByPP; uj++)
340 Buf[uj] = ((unsigned int)Buf[uj] + (unsigned int)Buf[uj-ByPP]) % 256;
341 Buf[0] = 0;
342 break;
343 case 2: /* Up */
344 if (Buf_up==NULL)
345 {
346 Buf[0] = 0;
347 return(0); /* according to png spec. it is assumed that */
348 /* Buf_up is zero everywhere */
349 }
350 for (uj=1; uj<=i->width*ByPP; uj++)
351 Buf[uj] = ((unsigned int)Buf[uj] + (unsigned int)Buf_up[uj]) % 256;
352 Buf[0] = 0;
353 break;
354 case 3: /* Average */
355 for (uj=1; uj<=i->width*ByPP; uj++)
356 {
357 if (uj>ByPP) prior = Buf[uj-ByPP]; else prior = 0;
358 if (Buf_up!=NULL) up = Buf_up[uj]; else up = 0;
359 Buf[uj] = ((long)Buf[uj] + ((prior+up)>>1)) % 256;
360 }
361 Buf[0] = 0;
362 break;
363 case 4: /* Paeth */
364 for (uj=1; uj<=i->width*ByPP; uj++)
365 {
366 if (Buf_up != NULL) up = Buf_up[uj]; else up = 0;
367 if (uj>ByPP) prior = Buf[uj-ByPP]; else prior = 0;
368 if (uj>ByPP && Buf_up != NULL) upperleft = Buf_up[uj-ByPP];
369 else upperleft = 0;
370 Buf[uj] = ((unsigned int)Buf[uj] + (unsigned int)PaethPredictor(prior,
371 up, upperleft));
372 }
373 Buf[0] = 0;
374 break;
375 }
376 return(0);
377 }
378
DoFiltering(struct png_internal_struct * i,unsigned char * Buf)379 int DoFiltering(struct png_internal_struct *i, unsigned char *Buf)
380 {
381 int ByPP, j, t;
382
383 if (Buf[0]==0) return(0); /* No filter */
384 if (Buf[0]==1) /* Sub */
385 {
386 ByPP = (int)ceil((double)i->bit_depth/8);
387 if (i->color_type==2) ByPP *= 3;
388 for (j=(int)i->width*ByPP; j>=ByPP+1; j--)
389 {
390 t = ((int)Buf[j] - (int)Buf[j-ByPP]);
391 if (t<0) t += 256;
392 Buf[j] = t % 256;
393 }
394 }
395 return(0);
396 }
397
InitWritePNG(FILE * png,struct png_info_struct * info,struct png_internal_struct * i)398 int InitWritePNG(FILE *png, struct png_info_struct *info, struct png_internal_struct *i)
399 {
400 unsigned long length, crc_v;
401 unsigned char Buf[20];
402
403 i->png = png;
404 if ( fwrite(png_signature, 1, 8, png) !=8) return(-1);
405 i->length = length = 13;
406 CorrectLong1(&length, Buf);
407 if ( fwrite(Buf, 1, 4, png) !=4) return(-1);
408 if ( fwrite("IHDR", 1, 4, png) !=4) return(-1);
409 CorrectLong1(&info->width, Buf);
410 CorrectLong1(&info->height, Buf+4);
411 Buf[8] = info->bit_depth;
412 Buf[9] = info->color_type;
413 Buf[10] = info->compression;
414 Buf[11] = info->filter;
415 Buf[12] = info->interlace;
416 if ( fwrite(Buf, 1, 13, png) !=13) return(-1);
417 crc_v = update_crc(0xffffffffL, (unsigned char*)"IHDR", 4);
418 crc_v = update_crc(crc_v, Buf, (long)i->length);
419 crc_v ^= 0xffffffffL;
420 CorrectLong1(&crc_v, Buf);
421 if ( fwrite(Buf, 1, 4, png) !=4) return(-1);
422 memcpy(i, info, sizeof(struct png_info_struct));
423 strncpy(i->chunk_type, "IHDR", 4);
424 i->PLTE = 0;
425 i->position = 0;
426 i->zlib_initialized = 0;
427 i->readbuf_initialized = 0;
428 i->buf_filled = 0;
429 i->chunk_pos = 0;
430 i->readbuf = NULL;
431
432 return(0);
433 }
434
WriteChunk(struct png_internal_struct * i,unsigned char * Buf)435 int WriteChunk(struct png_internal_struct *i, unsigned char *Buf)
436 {
437 unsigned long length, crc_v;
438 unsigned char LongBuf[4];
439
440 length = i->length;
441 CorrectLong1(&length, LongBuf);
442 if ( fwrite(LongBuf, 1, 4, i->png) !=4) return(-1);
443 if ( fwrite(i->chunk_type, 1, 4, i->png) !=4) return(-1);
444 length = fwrite(Buf, 1, (size_t)i->length, i->png);
445 if (length!=i->length) return(-1);
446 crc_v = update_crc(0xffffffffL, (unsigned char*)i->chunk_type, 4);
447 crc_v = update_crc(crc_v, Buf, (long)i->length);
448 crc_v ^= 0xffffffffL;
449 CorrectLong1(&crc_v, LongBuf);
450 if ( fwrite(LongBuf, 1, 4, i->png) !=4) return(-1);
451 i->position = 0;
452
453 return(0);
454 }
455
do_deflate(struct png_internal_struct * i)456 int do_deflate(struct png_internal_struct *i)
457 {
458 int err;
459
460 if (i->zlib_initialized==0)
461 {
462 i->zlib_initialized = 1;
463 i->d_stream.zalloc = (alloc_func)Z_NULL;
464 i->d_stream.zfree = (free_func)Z_NULL;
465 err = deflateInit(&i->d_stream, Z_DEFAULT_COMPRESSION);
466 }
467
468 err = deflate(&i->d_stream, Z_NO_FLUSH);
469
470 return(err);
471 }
472
WritePNGLine(struct png_internal_struct * i,unsigned char * Buf)473 int WritePNGLine(struct png_internal_struct *i, unsigned char *Buf)
474 {
475 int err=err;
476 int ByPP;
477
478 /* Initialize on first call */
479 if (i->chunk_pos==0)
480 {
481 i->checksum = update_crc(0xffffffffL, (unsigned char*)"IDAT", 4);
482 if ( fwrite(i, 1, 4, i->png) !=4) return(-1); /* length as dummy */
483 if ( fwrite("IDAT", 1, 4, i->png) !=4) return(-1);
484 }
485 if (i->readbuf_initialized==0)
486 {
487 i->readbuf = malloc(BSIZE);
488 if (!i->readbuf) return(-2); /* Memory error */
489 i->readbuf_initialized = 1;
490 }
491
492 ByPP = (int)ceil((double)i->bit_depth/8);
493 if (i->color_type==2) ByPP *= 3;
494
495 i->d_stream.avail_in = (int)((i->width)*ByPP+1); /* Only compress a single line */
496 i->d_stream.next_in = Buf;
497
498 if (i->color_type==3)
499 {
500 switch (i->bit_depth)
501 {
502 case 1 : i->d_stream.avail_in = (int)((i->width)/8+1); break;
503 case 2 : i->d_stream.avail_in = (int)((i->width)/4+1); break;
504 case 4 : i->d_stream.avail_in = (int)((i->width)/2+1); break;
505 }
506 }
507
508 do
509 {
510 i->d_stream.next_out = i->readbuf;
511 i->d_stream.avail_out = BSIZE;
512 err = do_deflate(i);
513
514 i->buf_pos = (int)(i->d_stream.next_out-i->readbuf);
515 i->checksum = update_crc(i->checksum, i->readbuf, i->buf_pos);
516 if ( fwrite(i->readbuf, 1, (size_t)i->buf_pos, i->png) != (size_t)i->buf_pos) return(-1);
517 i->chunk_pos += i->buf_pos;
518 } while (i->d_stream.avail_out==0);
519
520 return(0);
521 }
522
EndIDAT(struct png_internal_struct * i)523 int EndIDAT(struct png_internal_struct *i)
524 {
525 int err=err;
526 unsigned long length;
527 unsigned char LongBuf[4];
528
529 if (!i->readbuf) return(-1); /* EndIDAT called too early */
530 do
531 {
532 i->d_stream.next_out = i->readbuf;
533 i->d_stream.avail_out = BSIZE;
534 err = deflate(&i->d_stream, Z_FINISH);
535 i->buf_pos = (int)(i->d_stream.next_out-i->readbuf);
536 if ( fwrite(i->readbuf, 1, (size_t)i->buf_pos, i->png) != (size_t)i->buf_pos) return(-1);
537 i->chunk_pos += i->buf_pos;
538 i->checksum = update_crc(i->checksum, i->readbuf, i->buf_pos);
539 } while (i->d_stream.avail_out==0);
540 err = deflateEnd(&i->d_stream);
541
542 i->checksum ^= 0xffffffffL;
543 CorrectLong1(&i->checksum, LongBuf);
544 if ( fwrite(LongBuf, 1, 4, i->png) !=4) return(-1);
545 fseek(i->png, -(long)(i->chunk_pos+12), SEEK_CUR);
546 length = i->chunk_pos;
547 CorrectLong1(&length, LongBuf);
548 if ( fwrite(LongBuf, 1, 4, i->png) !=4) return(-1);
549 fseek(i->png, (long)i->chunk_pos+8, SEEK_CUR);
550 i->position = 0;
551
552 return(0);
553 }
554
PosOverIEND(struct png_internal_struct * i)555 int PosOverIEND(struct png_internal_struct *i)
556 {
557 struct png_internal_struct last;
558
559 while (strncmp(i->chunk_type, "IEND", 4)!=0)
560 {
561 last = *i;
562 GetNextChunk(i);
563 }
564 fseek(i->png, -8, SEEK_CUR);
565 *i = last;
566 return(0);
567 }
568
PosOverIHDR(struct png_internal_struct * i)569 int PosOverIHDR(struct png_internal_struct *i)
570 {
571 unsigned char LongBuf[4];
572
573 fseek(i->png, 8, SEEK_SET);
574 fread(LongBuf, 1, 4, i->png);
575 CorrectLong2(LongBuf, &i->length);
576 fread(i->chunk_type, 1, 4, i->png);
577 i->position = 1;
578 return(0);
579 }
580
EndPNG(struct png_internal_struct * i)581 int EndPNG(struct png_internal_struct *i)
582 {
583 if (i->readbuf_initialized!=0) free(i->readbuf);
584 return(0);
585 }
586
587