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