Initial revision
[blender.git] / source / blender / imbuf / intern / png_decode.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 #include "png.h"
34
35 #ifdef _WIN32
36 #include "BLI_winstuff.h"
37 #endif
38 #include "BLI_blenlib.h"
39
40 #include "imbuf.h"
41 #include "imbuf_patch.h"
42
43 #include "IMB_imbuf_types.h"
44 #include "IMB_imbuf.h"
45
46 #include "IMB_allocimbuf.h"
47 #include "IMB_cmap.h"
48 #include "IMB_png.h"
49
50
51
52 static int checkpng(unsigned char *mem)
53 {
54         int ret_val = 0;
55
56         if (mem) {
57                 ret_val = !png_sig_cmp(mem, 0, 8);
58         }
59
60         return(ret_val);        
61 }
62
63 int imb_is_a_png(void *buf) {
64         
65         return checkpng(buf);
66 }
67
68 typedef struct PNGReadStruct {
69         unsigned char *data;
70         unsigned int size;
71         unsigned int seek;
72 }PNGReadStruct;
73
74 static void
75 ReadData(
76     png_structp png_ptr,
77     png_bytep data,
78     png_size_t length);
79
80 static void
81 ReadData(
82     png_structp png_ptr,
83     png_bytep data,
84     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
101 struct ImBuf *imb_png_decode(unsigned char *mem, int size, int flags)
102 {
103         struct ImBuf *ibuf = 0;
104         png_structp png_ptr;
105         png_infop info_ptr;
106         unsigned char *pixels = 0;
107         png_bytepp row_pointers = 0;
108         png_uint_32 width, height;
109         int bit_depth, color_type;
110         PNGReadStruct ps;
111
112         unsigned char *from, *to;
113         int i, bytesperpixel;
114
115         if (checkpng(mem) == 0) return(0);
116
117         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
118                 NULL, NULL, NULL);
119         if (png_ptr == NULL) {
120                 printf("Cannot png_create_read_struct\n");
121                 return 0;
122         }
123
124         info_ptr = png_create_info_struct(png_ptr);
125         if (info_ptr == NULL) {
126                 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
127                 printf("Cannot png_create_info_struct\n");
128                 return 0;
129         }
130
131         ps.size = size;
132         ps.data = mem;
133         ps.seek = 0;
134
135         png_set_read_fn(png_ptr, (void *) &ps, ReadData);
136
137         if (setjmp(png_jmpbuf(png_ptr))) {
138                 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
139                 if (pixels) MEM_freeN(pixels);
140                 if (row_pointers) MEM_freeN(row_pointers);
141                 if (ibuf) IMB_freeImBuf(ibuf);
142                 return 0;
143         }
144
145         // png_set_sig_bytes(png_ptr, 8);
146
147         png_read_info(png_ptr, info_ptr);
148         png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
149
150         if (bit_depth == 16) {
151                 png_set_strip_16(png_ptr);
152                 bit_depth = 8;
153         }
154
155         bytesperpixel = png_get_channels(png_ptr, info_ptr);
156
157         switch(color_type) {
158         case PNG_COLOR_TYPE_RGB:
159         case PNG_COLOR_TYPE_RGB_ALPHA:
160                 break;
161         case PNG_COLOR_TYPE_PALETTE:
162                 png_set_palette_to_rgb(png_ptr);
163                 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
164                         bytesperpixel = 4;
165                 } else {
166                         bytesperpixel = 3;
167                 }
168                 break;
169         case PNG_COLOR_TYPE_GRAY:
170         case PNG_COLOR_TYPE_GRAY_ALPHA:
171                 if (bit_depth < 8) {
172                         png_set_expand(png_ptr);
173                         bit_depth = 8;
174                 }
175                 break;
176         default:
177                 printf("PNG format not supported\n");
178                 longjmp(png_jmpbuf(png_ptr), 1);
179         }
180         
181         ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0, 0);
182
183         if (ibuf) {
184                 ibuf->ftype = PNG;
185         } else {
186                 printf("Couldn't allocate memory for PNG image\n");
187         }
188
189         if (ibuf && ((flags & IB_test) == 0)) {
190                 imb_addrectImBuf(ibuf);
191
192                 pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
193                 if (pixels == NULL) {
194                         printf("Cannot allocate pixels array\n");
195                         longjmp(png_jmpbuf(png_ptr), 1);
196                 }
197
198                 // allocate memory for an array of row-pointers
199                 row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
200                 if (row_pointers == NULL) {
201                         printf("Cannot allocate row-pointers array\n");
202                         longjmp(png_jmpbuf(png_ptr), 1);
203                 }
204
205                 // set the individual row-pointers to point at the correct offsets
206                 for (i = 0; i < ibuf->y; i++) {
207                         row_pointers[ibuf->y-1-i] = (png_bytep)
208                         ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
209                 }
210
211                 png_read_image(png_ptr, row_pointers);
212
213                 // copy image data
214
215                 to = (unsigned char *) ibuf->rect;
216                 from = pixels;
217
218                 switch (bytesperpixel) {
219                 case 4:
220                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
221                                 to[0] = from[0];
222                                 to[1] = from[1];
223                                 to[2] = from[2];
224                                 to[3] = from[3];
225                                 to += 4; from += 4;
226                         }
227                         break;
228                 case 3:
229                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
230                                 to[0] = from[0];
231                                 to[1] = from[1];
232                                 to[2] = from[2];
233                                 to[3] = 0xff;
234                                 to += 4; from += 3;
235                         }
236                         break;
237                 case 2:
238                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
239                                 to[0] = to[1] = to[2] = from[0];
240                                 to[3] = from[1];
241                                 to += 4; from += 2;
242                         }
243                         break;
244                 case 1:
245                         for (i = ibuf->x * ibuf->y; i > 0; i--) {
246                                 to[0] = to[1] = to[2] = from[0];
247                                 to[3] = 0xff;
248                                 to += 4; from++;
249                         }
250                         break;
251                 }
252
253                 png_read_end(png_ptr, info_ptr);
254         }
255
256         // clean up
257         MEM_freeN(pixels);
258         MEM_freeN(row_pointers);
259         png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
260
261         return(ibuf);
262 }
263