doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / imbuf / intern / png.c
1 /*
2  *
3  * ***** BEGIN GPL 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.
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 Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  * $Id$
28  */
29
30
31 #include "png.h"
32
33 #include "BLI_blenlib.h"
34 #include "MEM_guardedalloc.h"
35
36 #include "imbuf.h"
37
38 #include "IMB_imbuf_types.h"
39 #include "IMB_imbuf.h"
40
41 #include "IMB_allocimbuf.h"
42 #include "IMB_metadata.h"
43 #include "IMB_filetype.h"
44
45 typedef struct PNGReadStruct {
46         unsigned char *data;
47         unsigned int size;
48         unsigned int seek;
49 }PNGReadStruct;
50
51 static void ReadData( png_structp png_ptr, png_bytep data, png_size_t length);
52 static void WriteData( png_structp png_ptr, png_bytep data, png_size_t length);
53 static void Flush( png_structp png_ptr);
54
55 int imb_is_a_png(unsigned char *mem)
56 {
57         int ret_val = 0;
58
59         if (mem) ret_val = !png_sig_cmp(mem, 0, 8);
60         return(ret_val);
61 }
62
63 static void Flush(png_structp png_ptr) 
64 {
65         (void)png_ptr;
66 }
67
68 static void WriteData( png_structp png_ptr, png_bytep data, png_size_t length)
69 {
70         ImBuf *ibuf = (ImBuf *) png_get_io_ptr(png_ptr);
71
72         // if buffer is to small increase it.
73         while (ibuf->encodedsize + length > ibuf->encodedbuffersize) {
74                 imb_enlargeencodedbufferImBuf(ibuf);
75         }
76
77         memcpy(ibuf->encodedbuffer + ibuf->encodedsize, data, length);
78         ibuf->encodedsize += length;
79 }
80
81 static void ReadData( png_structp png_ptr, png_bytep data, png_size_t length)
82 {
83         PNGReadStruct *rs= (PNGReadStruct *) png_get_io_ptr(png_ptr);
84
85         if (rs) {
86                 if (length <= rs->size - rs->seek) {
87                         memcpy(data, rs->data + rs->seek, length);
88                         rs->seek += length;
89                         return;
90                 }
91         }
92
93         printf("Reached EOF while decoding PNG\n");
94         longjmp(png_jmpbuf(png_ptr), 1);
95 }
96
97 int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
98 {
99         png_structp png_ptr;
100         png_infop info_ptr;
101
102         unsigned char *pixels = 0;
103         unsigned char *from, *to;
104         png_bytepp row_pointers = 0;
105         int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY;
106         FILE *fp = 0;
107
108         /* use the jpeg quality setting for compression */
109         int compression;
110         compression= (int)(((float)(ibuf->ftype & 0xff) / 11.1111f));
111         compression= compression < 0 ? 0 : (compression > 9 ? 9 : compression);
112
113         /* for prints */
114         if(flags & IB_mem)
115                 name= "<memory>";
116
117         bytesperpixel = (ibuf->depth + 7) >> 3;
118         if ((bytesperpixel > 4) || (bytesperpixel == 2)) {
119                 printf("imb_savepng: Cunsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, name);
120                 return (0);
121         }
122
123         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
124                 NULL, NULL, NULL);
125         if (png_ptr == NULL) {
126                 printf("imb_savepng: Cannot png_create_write_struct for file: '%s'\n", name);
127                 return 0;
128         }
129
130         info_ptr = png_create_info_struct(png_ptr);
131         if (info_ptr == NULL) {
132                 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
133                 printf("imb_savepng: Cannot png_create_info_struct for file: '%s'\n", name);
134                 return 0;
135         }
136
137         if (setjmp(png_jmpbuf(png_ptr))) {
138                 png_destroy_write_struct(&png_ptr, &info_ptr);
139                 printf("imb_savepng: Cannot setjmp for file: '%s'\n", name);
140                 return 0;
141         }
142
143         // copy image data
144
145         pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
146         if (pixels == NULL) {
147                 png_destroy_write_struct(&png_ptr, &info_ptr);
148                 printf("imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n", ibuf->x, ibuf->y, bytesperpixel, name);
149                 return 0;
150         }
151
152         from = (unsigned char *) ibuf->rect;
153         to = pixels;
154
155         switch (bytesperpixel) {
156         case 4:
157                 color_type = PNG_COLOR_TYPE_RGBA;
158                 for (i = ibuf->x * ibuf->y; i > 0; i--) {
159                         to[0] = from[0];
160                         to[1] = from[1];
161                         to[2] = from[2];
162                         to[3] = from[3];
163                         to += 4; from += 4;
164                 }
165                 break;
166         case 3:
167                 color_type = PNG_COLOR_TYPE_RGB;
168                 for (i = ibuf->x * ibuf->y; i > 0; i--) {
169                         to[0] = from[0];
170                         to[1] = from[1];
171                         to[2] = from[2];
172                         to += 3; from += 4;
173                 }
174                 break;
175         case 1:
176                 color_type = PNG_COLOR_TYPE_GRAY;
177                 for (i = ibuf->x * ibuf->y; i > 0; i--) {
178                         to[0] = from[0];
179                         to++; from += 4;
180                 }
181                 break;
182         }
183
184         if (flags & IB_mem) {
185                 // create image in memory
186                 imb_addencodedbufferImBuf(ibuf);
187                 ibuf->encodedsize = 0;
188
189                 png_set_write_fn(png_ptr,
190                          (png_voidp) ibuf,
191                          WriteData,
192                          Flush);
193         } else {
194                 fp = fopen(name, "wb");
195                 if (!fp) {
196                         png_destroy_write_struct(&png_ptr, &info_ptr);
197                         MEM_freeN(pixels);
198                         printf("imb_savepng: Cannot open file for writing: '%s'\n", name);
199                         return 0;
200                 }
201                 png_init_io(png_ptr, fp);
202         }
203
204         /*
205         png_set_filter(png_ptr, 0,
206                 PNG_FILTER_NONE  | PNG_FILTER_VALUE_NONE |
207                 PNG_FILTER_SUB   | PNG_FILTER_VALUE_SUB  |
208                 PNG_FILTER_UP    | PNG_FILTER_VALUE_UP   |
209                 PNG_FILTER_AVG   | PNG_FILTER_VALUE_AVG  |
210                 PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
211                 PNG_ALL_FILTERS);
212         */
213
214         png_set_compression_level(png_ptr, compression);
215
216         // png image settings
217         png_set_IHDR(png_ptr,
218                  info_ptr,
219                  ibuf->x,
220                  ibuf->y,
221                  8,
222                  color_type,
223                  PNG_INTERLACE_NONE,
224                  PNG_COMPRESSION_TYPE_DEFAULT,
225                  PNG_FILTER_TYPE_DEFAULT);
226
227         /* image text info */
228         if (ibuf->metadata) {
229                 png_text*  metadata;
230                 ImMetaData* iptr;
231                 int  num_text = 0;
232                 iptr = ibuf->metadata;
233                 while (iptr) {
234                         num_text++;
235                         iptr = iptr->next;
236                 }
237                 
238                 metadata = MEM_callocN(num_text*sizeof(png_text), "png_metadata");
239                 iptr = ibuf->metadata;
240                 num_text = 0;
241                 while (iptr) {
242                         
243                         metadata[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
244                         metadata[num_text].key = iptr->key;
245                         metadata[num_text].text = iptr->value;
246                         num_text++;
247                         iptr = iptr->next;
248                 }
249                 
250                 png_set_text(png_ptr, info_ptr, metadata, num_text);
251                 MEM_freeN(metadata);
252
253         }
254
255         // write the file header information
256         png_write_info(png_ptr, info_ptr);
257
258         // allocate memory for an array of row-pointers
259         row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
260         if (row_pointers == NULL) {
261                 printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name);
262                 png_destroy_write_struct(&png_ptr, &info_ptr);
263                 MEM_freeN(pixels);
264                 if (fp) {
265                         fclose(fp);
266                 }
267                 return 0;
268         }
269
270         // set the individual row-pointers to point at the correct offsets
271         for (i = 0; i < ibuf->y; i++) {
272                 row_pointers[ibuf->y-1-i] = (png_bytep)
273                         ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
274         }
275
276         // write out the entire image data in one call
277         png_write_image(png_ptr, row_pointers);
278
279         // write the additional chunks to the PNG file (not really needed)
280         png_write_end(png_ptr, info_ptr);
281
282         // clean up
283         MEM_freeN(pixels);
284         MEM_freeN(row_pointers);
285         png_destroy_write_struct(&png_ptr, &info_ptr);
286
287         if (fp) {
288                 fflush(fp);
289                 fclose(fp);
290         }
291
292         return(1);
293 }
294
295 struct ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags)
296 {
297         struct ImBuf *ibuf = 0;
298         png_structp png_ptr;
299         png_infop info_ptr;
300         unsigned char *pixels = 0;
301         png_bytepp row_pointers = 0;
302         png_uint_32 width, height;
303         int bit_depth, color_type;
304         PNGReadStruct ps;
305
306         unsigned char *from, *to;
307         int i, bytesperpixel;
308
309         if (imb_is_a_png(mem) == 0) return(0);
310
311         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
312                 NULL, NULL, NULL);
313         if (png_ptr == NULL) {
314                 printf("Cannot png_create_read_struct\n");
315                 return 0;
316         }
317
318         info_ptr = png_create_info_struct(png_ptr);
319         if (info_ptr == NULL) {
320                 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, 
321                         (png_infopp)NULL);
322                 printf("Cannot png_create_info_struct\n");
323                 return 0;
324         }
325
326         ps.size = size; /* XXX, 4gig limit! */
327         ps.data = mem;
328         ps.seek = 0;
329
330         png_set_read_fn(png_ptr, (void *) &ps, ReadData);
331
332         if (setjmp(png_jmpbuf(png_ptr))) {
333                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
334                 if (pixels) MEM_freeN(pixels);
335                 if (row_pointers) MEM_freeN(row_pointers);
336                 if (ibuf) IMB_freeImBuf(ibuf);
337                 return 0;
338         }
339
340         // png_set_sig_bytes(png_ptr, 8);
341
342         png_read_info(png_ptr, info_ptr);
343         png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, 
344                 &color_type, NULL, NULL, NULL);
345
346         if (bit_depth == 16) {
347                 png_set_strip_16(png_ptr);
348                 bit_depth = 8;
349         }
350
351         bytesperpixel = png_get_channels(png_ptr, info_ptr);
352
353         switch(color_type) {
354         case PNG_COLOR_TYPE_RGB:
355         case PNG_COLOR_TYPE_RGB_ALPHA:
356                 break;
357         case PNG_COLOR_TYPE_PALETTE:
358                 png_set_palette_to_rgb(png_ptr);
359                 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
360                         bytesperpixel = 4;
361                 } else {
362                         bytesperpixel = 3;
363                 }
364                 break;
365         case PNG_COLOR_TYPE_GRAY:
366         case PNG_COLOR_TYPE_GRAY_ALPHA:
367                 if (bit_depth < 8) {
368                         png_set_expand(png_ptr);
369                         bit_depth = 8;
370                 }
371                 break;
372         default:
373                 printf("PNG format not supported\n");
374                 longjmp(png_jmpbuf(png_ptr), 1);
375         }
376         
377         ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0);
378
379         if (ibuf) {
380                 ibuf->ftype = PNG;
381                 ibuf->profile = IB_PROFILE_SRGB;
382         } else {
383                 printf("Couldn't allocate memory for PNG image\n");
384         }
385
386         if (ibuf && ((flags & IB_test) == 0)) {
387                 imb_addrectImBuf(ibuf);
388
389                 pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
390                 if (pixels == NULL) {
391                         printf("Cannot allocate pixels array\n");
392                         longjmp(png_jmpbuf(png_ptr), 1);
393                 }
394
395                 // allocate memory for an array of row-pointers
396                 row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
397                 if (row_pointers == NULL) {
398                         printf("Cannot allocate row-pointers array\n");
399                         longjmp(png_jmpbuf(png_ptr), 1);
400                 }
401
402                 // set the individual row-pointers to point at the correct offsets
403                 for (i = 0; i < ibuf->y; i++) {
404                         row_pointers[ibuf->y-1-i] = (png_bytep)
405                         ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
406                 }
407
408                 png_read_image(png_ptr, row_pointers);
409
410                 // copy image data
411
412                 to = (unsigned char *) ibuf->rect;
413                 from = pixels;
414
415                 switch (bytesperpixel) {
416                 case 4:
417                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
418                                 to[0] = from[0];
419                                 to[1] = from[1];
420                                 to[2] = from[2];
421                                 to[3] = from[3];
422                                 to += 4; from += 4;
423                         }
424                         break;
425                 case 3:
426                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
427                                 to[0] = from[0];
428                                 to[1] = from[1];
429                                 to[2] = from[2];
430                                 to[3] = 0xff;
431                                 to += 4; from += 3;
432                         }
433                         break;
434                 case 2:
435                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
436                                 to[0] = to[1] = to[2] = from[0];
437                                 to[3] = from[1];
438                                 to += 4; from += 2;
439                         }
440                         break;
441                 case 1:
442                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
443                                 to[0] = to[1] = to[2] = from[0];
444                                 to[3] = 0xff;
445                                 to += 4; from++;
446                         }
447                         break;
448                 }
449
450                 if (flags & IB_metadata) {
451                         png_text* text_chunks;
452                         int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL);
453                         for(i = 0; i < count; i++) {
454                                 IMB_metadata_add_field(ibuf, text_chunks[i].key, text_chunks[i].text);
455                                 ibuf->flags |= IB_metadata;                             
456                          }
457                 }
458
459                 png_read_end(png_ptr, info_ptr);
460         }
461
462         // clean up
463         MEM_freeN(pixels);
464         MEM_freeN(row_pointers);
465         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
466
467         return(ibuf);
468 }
469