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