This looks like a lot but its a few small changes.
[blender.git] / source / blender / imbuf / intern / png.c
1 /**
2  *
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  * $Id$
31  */
32
33
34 #include "png.h"
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #ifdef WIN32
41 #include "BLI_winstuff.h"
42 #endif
43 #include "BLI_blenlib.h"
44
45 #include "imbuf.h"
46 #include "imbuf_patch.h"
47
48 #include "IMB_imbuf_types.h"
49 #include "IMB_imbuf.h"
50
51 #include "IMB_allocimbuf.h"
52 #include "IMB_cmap.h"
53 #include "IMB_png.h"
54
55 typedef struct PNGReadStruct {
56         unsigned char *data;
57         unsigned int size;
58         unsigned int seek;
59 }PNGReadStruct;
60
61 static void ReadData( png_structp png_ptr, png_bytep data, png_size_t length);
62 static void WriteData( png_structp png_ptr, png_bytep data, png_size_t length);
63 static void Flush( png_structp png_ptr);
64
65 int imb_is_a_png(void *mem)
66 {
67         int ret_val = 0;
68
69         if (mem) {
70                 ret_val = !png_sig_cmp(mem, 0, 8);
71         }
72
73         return(ret_val);
74 }
75
76 static void Flush(png_structp png_ptr) 
77
78 }
79
80 static void WriteData( png_structp png_ptr, png_bytep data, png_size_t length)
81 {
82         ImBuf *ibuf = (ImBuf *) png_get_io_ptr(png_ptr);
83
84         // if buffer is to small increase it.
85         while (ibuf->encodedsize + length > ibuf->encodedbuffersize) {
86                 imb_enlargeencodedbufferImBuf(ibuf);
87         }
88
89         memcpy(ibuf->encodedbuffer + ibuf->encodedsize, data, length);
90         ibuf->encodedsize += length;
91 }
92
93 static void ReadData( png_structp png_ptr, png_bytep data, png_size_t length)
94 {
95         PNGReadStruct *rs= (PNGReadStruct *) png_get_io_ptr(png_ptr);
96
97         if (rs) {
98                 if (length <= rs->size - rs->seek) {
99                         memcpy(data, rs->data + rs->seek, length);
100                         rs->seek += length;
101                         return;
102                 }
103         }
104
105         printf("Reached EOF while decoding PNG\n");
106         longjmp(png_jmpbuf(png_ptr), 1);
107 }
108
109 short imb_savepng(struct ImBuf *ibuf, int file, int flags)
110 {
111         png_structp png_ptr;
112         png_infop info_ptr;
113         unsigned char *pixels = 0;
114         unsigned char *from, *to;
115         png_bytepp row_pointers = 0;
116         int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY;
117         FILE *fp = 0;
118
119         bytesperpixel = (ibuf->depth + 7) >> 3;
120         if ((bytesperpixel > 4) || (bytesperpixel == 2)) {
121                 printf("imb_savepng: unsupported bytes per pixel: %d\n", bytesperpixel);
122                 return (0);
123         }
124
125         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
126                 NULL, NULL, NULL);
127         if (png_ptr == NULL) {
128                 printf("Cannot png_create_write_struct\n");
129                 return 0;
130         }
131
132         info_ptr = png_create_info_struct(png_ptr);
133         if (info_ptr == NULL) {
134                 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
135                 printf("Cannot png_create_info_struct\n");
136                 return 0;
137         }
138
139         if (setjmp(png_jmpbuf(png_ptr))) {
140                 png_destroy_write_struct(&png_ptr, &info_ptr);
141                 if (pixels) MEM_freeN(pixels);
142                 if (row_pointers) MEM_freeN(row_pointers);
143                 // printf("Aborting\n");
144                 if (fp) {
145                         fflush(fp);
146                         fclose(fp);
147                 }
148                 return 0;
149         }
150
151         // copy image data
152
153         pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
154         if (pixels == NULL) {
155                 printf("Cannot allocate pixels array\n");
156                 return 0;
157         }
158
159         from = (unsigned char *) ibuf->rect;
160         to = pixels;
161
162         switch (bytesperpixel) {
163         case 4:
164                 color_type = PNG_COLOR_TYPE_RGBA;
165                 for (i = ibuf->x * ibuf->y; i > 0; i--) {
166                         to[0] = from[0];
167                         to[1] = from[1];
168                         to[2] = from[2];
169                         to[3] = from[3];
170                         to += 4; from += 4;
171                 }
172                 break;
173         case 3:
174                 color_type = PNG_COLOR_TYPE_RGB;
175                 for (i = ibuf->x * ibuf->y; i > 0; i--) {
176                         to[0] = from[0];
177                         to[1] = from[1];
178                         to[2] = from[2];
179                         to += 3; from += 4;
180                 }
181                 break;
182         case 1:
183                 color_type = PNG_COLOR_TYPE_GRAY;
184                 for (i = ibuf->x * ibuf->y; i > 0; i--) {
185                         to[0] = from[0];
186                         to++; from += 4;
187                 }
188                 break;
189         }
190
191         if (flags & IB_mem) {
192                 // create image in memory
193                 imb_addencodedbufferImBuf(ibuf);
194                 ibuf->encodedsize = 0;
195
196                 png_set_write_fn(png_ptr,
197                          (png_voidp) ibuf,
198                          WriteData,
199                          Flush);
200         } else {
201                 fp = fdopen(file, "wb");
202                 png_init_io(png_ptr, fp);
203         }
204
205         /*
206         png_set_filter(png_ptr, 0,
207                 PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE |
208                 PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB  |
209                 PNG_FILTER_UP    | PNG_FILTER_VALUE_UP   |
210                 PNG_FILTER_AVG   | PNG_FILTER_VALUE_AVG  |
211                 PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
212                 PNG_ALL_FILTERS);
213
214         png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
215         */
216
217         // png image settings
218         png_set_IHDR(png_ptr,
219                  info_ptr,
220                  ibuf->x,
221                  ibuf->y,
222                  8,
223                  color_type,
224                  PNG_INTERLACE_NONE,
225                  PNG_COMPRESSION_TYPE_DEFAULT,
226                  PNG_FILTER_TYPE_DEFAULT);
227
228         // write the file header information
229         png_write_info(png_ptr, info_ptr);
230
231         // allocate memory for an array of row-pointers
232         row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
233         if (row_pointers == NULL) {
234                         printf("Cannot allocate row-pointers array\n");
235                         return 0;
236         }
237
238         // set the individual row-pointers to point at the correct offsets
239         for (i = 0; i < ibuf->y; i++) {
240                 row_pointers[ibuf->y-1-i] = (png_bytep)
241                         ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
242         }
243
244         // write out the entire image data in one call
245         png_write_image(png_ptr, row_pointers);
246
247         // write the additional chunks to the PNG file (not really needed)
248         png_write_end(png_ptr, info_ptr);
249
250         // clean up
251         MEM_freeN(pixels);
252         MEM_freeN(row_pointers);
253         png_destroy_write_struct(&png_ptr, &info_ptr);
254
255         if (fp) {
256                 fflush(fp);
257                 fclose(fp);
258         }
259
260         return(1);
261 }
262
263 struct ImBuf *imb_loadpng(unsigned char *mem, int size, int flags)
264 {
265         struct ImBuf *ibuf = 0;
266         png_structp png_ptr;
267         png_infop info_ptr;
268         unsigned char *pixels = 0;
269         png_bytepp row_pointers = 0;
270         png_uint_32 width, height;
271         int bit_depth, color_type;
272         PNGReadStruct ps;
273
274         unsigned char *from, *to;
275         int i, bytesperpixel;
276
277         if (imb_is_a_png(mem) == 0) return(0);
278
279         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
280                 NULL, NULL, NULL);
281         if (png_ptr == NULL) {
282                 printf("Cannot png_create_read_struct\n");
283                 return 0;
284         }
285
286         info_ptr = png_create_info_struct(png_ptr);
287         if (info_ptr == NULL) {
288                 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, 
289                         (png_infopp)NULL);
290                 printf("Cannot png_create_info_struct\n");
291                 return 0;
292         }
293
294         ps.size = size;
295         ps.data = mem;
296         ps.seek = 0;
297
298         png_set_read_fn(png_ptr, (void *) &ps, ReadData);
299
300         if (setjmp(png_jmpbuf(png_ptr))) {
301                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
302                 if (pixels) MEM_freeN(pixels);
303                 if (row_pointers) MEM_freeN(row_pointers);
304                 if (ibuf) IMB_freeImBuf(ibuf);
305                 return 0;
306         }
307
308         // png_set_sig_bytes(png_ptr, 8);
309
310         png_read_info(png_ptr, info_ptr);
311         png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, 
312                 &color_type, NULL, NULL, NULL);
313
314         if (bit_depth == 16) {
315                 png_set_strip_16(png_ptr);
316                 bit_depth = 8;
317         }
318
319         bytesperpixel = png_get_channels(png_ptr, info_ptr);
320
321         switch(color_type) {
322         case PNG_COLOR_TYPE_RGB:
323         case PNG_COLOR_TYPE_RGB_ALPHA:
324                 break;
325         case PNG_COLOR_TYPE_PALETTE:
326                 png_set_palette_to_rgb(png_ptr);
327                 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
328                         bytesperpixel = 4;
329                 } else {
330                         bytesperpixel = 3;
331                 }
332                 break;
333         case PNG_COLOR_TYPE_GRAY:
334         case PNG_COLOR_TYPE_GRAY_ALPHA:
335                 if (bit_depth < 8) {
336                         png_set_expand(png_ptr);
337                         bit_depth = 8;
338                 }
339                 break;
340         default:
341                 printf("PNG format not supported\n");
342                 longjmp(png_jmpbuf(png_ptr), 1);
343         }
344         
345         ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0, 0);
346
347         if (ibuf) {
348                 ibuf->ftype = PNG;
349         } else {
350                 printf("Couldn't allocate memory for PNG image\n");
351         }
352
353         if (ibuf && ((flags & IB_test) == 0)) {
354                 imb_addrectImBuf(ibuf);
355
356                 pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
357                 if (pixels == NULL) {
358                         printf("Cannot allocate pixels array\n");
359                         longjmp(png_jmpbuf(png_ptr), 1);
360                 }
361
362                 // allocate memory for an array of row-pointers
363                 row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
364                 if (row_pointers == NULL) {
365                         printf("Cannot allocate row-pointers array\n");
366                         longjmp(png_jmpbuf(png_ptr), 1);
367                 }
368
369                 // set the individual row-pointers to point at the correct offsets
370                 for (i = 0; i < ibuf->y; i++) {
371                         row_pointers[ibuf->y-1-i] = (png_bytep)
372                         ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
373                 }
374
375                 png_read_image(png_ptr, row_pointers);
376
377                 // copy image data
378
379                 to = (unsigned char *) ibuf->rect;
380                 from = pixels;
381
382                 switch (bytesperpixel) {
383                 case 4:
384                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
385                                 to[0] = from[0];
386                                 to[1] = from[1];
387                                 to[2] = from[2];
388                                 to[3] = from[3];
389                                 to += 4; from += 4;
390                         }
391                         break;
392                 case 3:
393                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
394                                 to[0] = from[0];
395                                 to[1] = from[1];
396                                 to[2] = from[2];
397                                 to[3] = 0xff;
398                                 to += 4; from += 3;
399                         }
400                         break;
401                 case 2:
402                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
403                                 to[0] = to[1] = to[2] = from[0];
404                                 to[3] = from[1];
405                                 to += 4; from += 2;
406                         }
407                         break;
408                 case 1:
409                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
410                                 to[0] = to[1] = to[2] = from[0];
411                                 to[3] = 0xff;
412                                 to += 4; from++;
413                         }
414                         break;
415                 }
416
417                 png_read_end(png_ptr, info_ptr);
418         }
419
420         // clean up
421         MEM_freeN(pixels);
422         MEM_freeN(row_pointers);
423         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
424
425         return(ibuf);
426 }
427