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