1 /*
2     FLAM3 - cosmic recursive fractal flames
3     Copyright (C) 1992-2009 Spotworks LLC
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 3 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, see <http://www.gnu.org/licenses/>.
17 */
18 
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <png.h>
23 #include <setjmp.h>
24 
25 #include "config.h"
26 #include "img.h"
27 #include "flam3.h"
28 #include "private.h"
29 
30 #ifdef _WIN32
31 #include <winsock.h> /* for htons */
32 #else
33 #include <arpa/inet.h>
34 #endif
35 
write_png(FILE * file,void * image,int width,int height,flam3_img_comments * fpc,int bpc)36 void write_png(FILE *file, void *image, int width, int height, flam3_img_comments *fpc, int bpc) {
37   png_structp  png_ptr;
38   png_infop    info_ptr;
39   png_text     text[FLAM3_PNG_COM];
40   size_t i;
41   unsigned short testbe = 1;
42   void **rows = malloc(sizeof(void *) * height);
43   char *nick = getenv("nick");
44   char *url = getenv("url");
45   char *id = getenv("id");
46   char *ai; /* For argi */
47   int pngcom_enable = argi("enable_png_comments", 1);
48 
49   text[0].compression = PNG_TEXT_COMPRESSION_NONE;
50   text[0].key = "flam3_version";
51   text[0].text = flam3_version();
52 
53   text[1].compression = PNG_TEXT_COMPRESSION_NONE;
54   text[1].key = "flam3_nickname";
55   text[1].text = nick;
56 
57   text[2].compression = PNG_TEXT_COMPRESSION_NONE;
58   text[2].key = "flam3_url";
59   text[2].text = url;
60 
61   text[3].compression = PNG_TEXT_COMPRESSION_NONE;
62   text[3].key = "flam3_id";
63   text[3].text = id;
64 
65   text[4].compression = PNG_TEXT_COMPRESSION_NONE;
66   text[4].key = "flam3_error_rate";
67   text[4].text = fpc->badvals;
68 
69   text[5].compression = PNG_TEXT_COMPRESSION_NONE;
70   text[5].key = "flam3_samples";
71   text[5].text = fpc->numiters;
72 
73   text[6].compression = PNG_TEXT_COMPRESSION_NONE;
74   text[6].key = "flam3_time";
75   text[6].text = fpc->rtime;
76 
77   text[7].compression = PNG_TEXT_COMPRESSION_zTXt;
78   text[7].key = "flam3_genome";
79   text[7].text = fpc->genome;
80 
81   for (i = 0; i < height; i++)
82     rows[i] = (unsigned char *)image + i * width * 4 * bpc;
83 
84   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
85 				    NULL, NULL, NULL);
86   info_ptr = png_create_info_struct(png_ptr);
87 
88   if (setjmp(png_jmpbuf(png_ptr))) {
89      fclose(file);
90      png_destroy_write_struct(&png_ptr, &info_ptr);
91      perror("writing file");
92      return;
93   }
94   png_init_io(png_ptr, file);
95 
96   png_set_IHDR(png_ptr, info_ptr, width, height, 8*bpc,
97 	       PNG_COLOR_TYPE_RGBA,
98 	       PNG_INTERLACE_NONE,
99 	       PNG_COMPRESSION_TYPE_BASE,
100 	       PNG_FILTER_TYPE_BASE);
101 
102   if (pngcom_enable==1)
103 	  png_set_text(png_ptr, info_ptr, text, FLAM3_PNG_COM);
104 
105   png_write_info(png_ptr, info_ptr);
106 
107   /* Must set this after the write_info */
108   if (2==bpc && testbe != htons(testbe)) {
109      png_set_swap(png_ptr);
110   }
111 
112   png_write_image(png_ptr, (png_bytepp) rows);
113   png_write_end(png_ptr, info_ptr);
114   png_destroy_write_struct(&png_ptr, &info_ptr);
115   free(rows);
116 
117 }
118 
119 #define SIG_CHECK_SIZE 8
120 
read_png(FILE * ifp,int * width,int * height)121 unsigned char *read_png(FILE *ifp, int *width, int *height) {
122   unsigned char sig_buf [SIG_CHECK_SIZE];
123   png_struct *png_ptr;
124   png_info *info_ptr;
125   png_byte **png_image = NULL;
126   unsigned int linesize, x, y;
127   unsigned char *p, *q;
128 
129   if (fread (sig_buf, 1, SIG_CHECK_SIZE, ifp) != SIG_CHECK_SIZE) {
130     fprintf (stderr, "input file empty or too short\n");
131     return 0;
132   }
133   if (png_sig_cmp (sig_buf, (png_size_t) 0, (png_size_t) SIG_CHECK_SIZE) != 0) {
134     fprintf (stderr, "input file not a PNG file\n");
135     return 0;
136   }
137 
138   png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
139   if (png_ptr == NULL) {
140     fprintf (stderr, "cannot allocate LIBPNG structure\n");
141     return 0;
142   }
143   if (setjmp(png_jmpbuf(png_ptr))) {
144      if (png_image) {
145 	 for (y = 0 ; y < png_get_image_height(png_ptr, info_ptr) ; y++)
146 	     free (png_image[y]);
147 	 free (png_image);
148      }
149      png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
150      perror("reading file");
151      return 0;
152   }
153   info_ptr = png_create_info_struct (png_ptr);
154   if (info_ptr == NULL) {
155     png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
156     fprintf (stderr, "cannot allocate LIBPNG structures\n");
157     return 0;
158   }
159 
160   png_init_io (png_ptr, ifp);
161   png_set_sig_bytes (png_ptr, SIG_CHECK_SIZE);
162   png_read_info (png_ptr, info_ptr);
163 
164   if (8 != png_get_bit_depth(png_ptr, info_ptr)) {
165     fprintf(stderr, "bit depth type must be 8, not %d.\n",
166 	    png_get_bit_depth(png_ptr, info_ptr));
167     return 0;
168   }
169 
170   *width = png_get_image_width(png_ptr, info_ptr);
171   *height = png_get_image_height(png_ptr, info_ptr);
172   p = q = malloc(4 * *width * *height);
173   png_image = (png_byte **)malloc (*height * sizeof (png_byte*));
174 
175   linesize = *width;
176   switch (png_get_color_type(png_ptr, info_ptr)) {
177     case PNG_COLOR_TYPE_RGB:
178       linesize *= 3;
179       break;
180     case PNG_COLOR_TYPE_RGBA:
181       linesize *= 4;
182       break;
183   default:
184     fprintf(stderr, "color type must be RGB or RGBA not %d.\n",
185 	    png_get_color_type(png_ptr, info_ptr));
186     return 0;
187   }
188 
189   for (y = 0 ; y < *height ; y++) {
190     png_image[y] = malloc (linesize);
191   }
192   png_read_image (png_ptr, png_image);
193   png_read_end (png_ptr, info_ptr);
194 
195   for (y = 0 ; y < *height ; y++) {
196     unsigned char *s = png_image[y];
197     for (x = 0 ; x < *width ; x++) {
198 
199       switch (png_get_color_type(png_ptr, info_ptr)) {
200       case PNG_COLOR_TYPE_RGB:
201 	p[0] = s[0];
202 	p[1] = s[1];
203 	p[2] = s[2];
204 	p[3] = 255;
205 	s += 3;
206 	p += 4;
207 	break;
208       case PNG_COLOR_TYPE_RGBA:
209 	p[0] = s[0];
210 	p[1] = s[1];
211 	p[2] = s[2];
212 	p[3] = s[3];
213 	s += 4;
214 	p += 4;
215 	break;
216       }
217     }
218   }
219 
220   for (y = 0 ; y < *height ; y++)
221     free (png_image[y]);
222   free (png_image);
223   png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
224 
225   return q;
226 }
227