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