Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00034 #include "png.h" 00035 00036 #include "BLI_blenlib.h" 00037 #include "MEM_guardedalloc.h" 00038 00039 #include "imbuf.h" 00040 00041 #include "IMB_imbuf_types.h" 00042 #include "IMB_imbuf.h" 00043 00044 #include "IMB_allocimbuf.h" 00045 #include "IMB_metadata.h" 00046 #include "IMB_filetype.h" 00047 00048 typedef struct PNGReadStruct { 00049 unsigned char *data; 00050 unsigned int size; 00051 unsigned int seek; 00052 }PNGReadStruct; 00053 00054 static void ReadData( png_structp png_ptr, png_bytep data, png_size_t length); 00055 static void WriteData( png_structp png_ptr, png_bytep data, png_size_t length); 00056 static void Flush( png_structp png_ptr); 00057 00058 int imb_is_a_png(unsigned char *mem) 00059 { 00060 int ret_val = 0; 00061 00062 if (mem) ret_val = !png_sig_cmp(mem, 0, 8); 00063 return(ret_val); 00064 } 00065 00066 static void Flush(png_structp png_ptr) 00067 { 00068 (void)png_ptr; 00069 } 00070 00071 static void WriteData( png_structp png_ptr, png_bytep data, png_size_t length) 00072 { 00073 ImBuf *ibuf = (ImBuf *) png_get_io_ptr(png_ptr); 00074 00075 // if buffer is to small increase it. 00076 while (ibuf->encodedsize + length > ibuf->encodedbuffersize) { 00077 imb_enlargeencodedbufferImBuf(ibuf); 00078 } 00079 00080 memcpy(ibuf->encodedbuffer + ibuf->encodedsize, data, length); 00081 ibuf->encodedsize += length; 00082 } 00083 00084 static void ReadData( png_structp png_ptr, png_bytep data, png_size_t length) 00085 { 00086 PNGReadStruct *rs= (PNGReadStruct *) png_get_io_ptr(png_ptr); 00087 00088 if (rs) { 00089 if (length <= rs->size - rs->seek) { 00090 memcpy(data, rs->data + rs->seek, length); 00091 rs->seek += length; 00092 return; 00093 } 00094 } 00095 00096 printf("Reached EOF while decoding PNG\n"); 00097 longjmp(png_jmpbuf(png_ptr), 1); 00098 } 00099 00100 int imb_savepng(struct ImBuf *ibuf, const char *name, int flags) 00101 { 00102 png_structp png_ptr; 00103 png_infop info_ptr; 00104 00105 unsigned char *pixels = NULL; 00106 unsigned char *from, *to; 00107 png_bytepp row_pointers = NULL; 00108 int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY; 00109 FILE *fp = NULL; 00110 00111 /* use the jpeg quality setting for compression */ 00112 int compression; 00113 compression= (int)(((float)(ibuf->ftype & 0xff) / 11.1111f)); 00114 compression= compression < 0 ? 0 : (compression > 9 ? 9 : compression); 00115 00116 /* for prints */ 00117 if(flags & IB_mem) 00118 name= "<memory>"; 00119 00120 bytesperpixel = (ibuf->planes + 7) >> 3; 00121 if ((bytesperpixel > 4) || (bytesperpixel == 2)) { 00122 printf("imb_savepng: Cunsupported bytes per pixel: %d for file: '%s'\n", bytesperpixel, name); 00123 return (0); 00124 } 00125 00126 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 00127 NULL, NULL, NULL); 00128 if (png_ptr == NULL) { 00129 printf("imb_savepng: Cannot png_create_write_struct for file: '%s'\n", name); 00130 return 0; 00131 } 00132 00133 info_ptr = png_create_info_struct(png_ptr); 00134 if (info_ptr == NULL) { 00135 png_destroy_write_struct(&png_ptr, (png_infopp)NULL); 00136 printf("imb_savepng: Cannot png_create_info_struct for file: '%s'\n", name); 00137 return 0; 00138 } 00139 00140 if (setjmp(png_jmpbuf(png_ptr))) { 00141 png_destroy_write_struct(&png_ptr, &info_ptr); 00142 printf("imb_savepng: Cannot setjmp for file: '%s'\n", name); 00143 return 0; 00144 } 00145 00146 // copy image data 00147 00148 pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); 00149 if (pixels == NULL) { 00150 png_destroy_write_struct(&png_ptr, &info_ptr); 00151 printf("imb_savepng: Cannot allocate pixels array of %dx%d, %d bytes per pixel for file: '%s'\n", ibuf->x, ibuf->y, bytesperpixel, name); 00152 return 0; 00153 } 00154 00155 from = (unsigned char *) ibuf->rect; 00156 to = pixels; 00157 00158 switch (bytesperpixel) { 00159 case 4: 00160 color_type = PNG_COLOR_TYPE_RGBA; 00161 for (i = ibuf->x * ibuf->y; i > 0; i--) { 00162 to[0] = from[0]; 00163 to[1] = from[1]; 00164 to[2] = from[2]; 00165 to[3] = from[3]; 00166 to += 4; from += 4; 00167 } 00168 break; 00169 case 3: 00170 color_type = PNG_COLOR_TYPE_RGB; 00171 for (i = ibuf->x * ibuf->y; i > 0; i--) { 00172 to[0] = from[0]; 00173 to[1] = from[1]; 00174 to[2] = from[2]; 00175 to += 3; from += 4; 00176 } 00177 break; 00178 case 1: 00179 color_type = PNG_COLOR_TYPE_GRAY; 00180 for (i = ibuf->x * ibuf->y; i > 0; i--) { 00181 to[0] = from[0]; 00182 to++; from += 4; 00183 } 00184 break; 00185 } 00186 00187 if (flags & IB_mem) { 00188 // create image in memory 00189 imb_addencodedbufferImBuf(ibuf); 00190 ibuf->encodedsize = 0; 00191 00192 png_set_write_fn(png_ptr, 00193 (png_voidp) ibuf, 00194 WriteData, 00195 Flush); 00196 } 00197 else { 00198 fp = fopen(name, "wb"); 00199 if (!fp) { 00200 png_destroy_write_struct(&png_ptr, &info_ptr); 00201 MEM_freeN(pixels); 00202 printf("imb_savepng: Cannot open file for writing: '%s'\n", name); 00203 return 0; 00204 } 00205 png_init_io(png_ptr, fp); 00206 } 00207 00208 /* 00209 png_set_filter(png_ptr, 0, 00210 PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE | 00211 PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB | 00212 PNG_FILTER_UP | PNG_FILTER_VALUE_UP | 00213 PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG | 00214 PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH| 00215 PNG_ALL_FILTERS); 00216 */ 00217 00218 png_set_compression_level(png_ptr, compression); 00219 00220 // png image settings 00221 png_set_IHDR(png_ptr, 00222 info_ptr, 00223 ibuf->x, 00224 ibuf->y, 00225 8, 00226 color_type, 00227 PNG_INTERLACE_NONE, 00228 PNG_COMPRESSION_TYPE_DEFAULT, 00229 PNG_FILTER_TYPE_DEFAULT); 00230 00231 /* image text info */ 00232 if (ibuf->metadata) { 00233 png_text* metadata; 00234 ImMetaData* iptr; 00235 int num_text = 0; 00236 iptr = ibuf->metadata; 00237 while (iptr) { 00238 num_text++; 00239 iptr = iptr->next; 00240 } 00241 00242 metadata = MEM_callocN(num_text*sizeof(png_text), "png_metadata"); 00243 iptr = ibuf->metadata; 00244 num_text = 0; 00245 while (iptr) { 00246 00247 metadata[num_text].compression = PNG_TEXT_COMPRESSION_NONE; 00248 metadata[num_text].key = iptr->key; 00249 metadata[num_text].text = iptr->value; 00250 num_text++; 00251 iptr = iptr->next; 00252 } 00253 00254 png_set_text(png_ptr, info_ptr, metadata, num_text); 00255 MEM_freeN(metadata); 00256 00257 } 00258 00259 if(ibuf->ppm[0] > 0.0 && ibuf->ppm[1] > 0.0) { 00260 png_set_pHYs(png_ptr, info_ptr, (unsigned int)(ibuf->ppm[0] + 0.5), (unsigned int)(ibuf->ppm[1] + 0.5), PNG_RESOLUTION_METER); 00261 } 00262 00263 // write the file header information 00264 png_write_info(png_ptr, info_ptr); 00265 00266 // allocate memory for an array of row-pointers 00267 row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); 00268 if (row_pointers == NULL) { 00269 printf("imb_savepng: Cannot allocate row-pointers array for file '%s'\n", name); 00270 png_destroy_write_struct(&png_ptr, &info_ptr); 00271 MEM_freeN(pixels); 00272 if (fp) { 00273 fclose(fp); 00274 } 00275 return 0; 00276 } 00277 00278 // set the individual row-pointers to point at the correct offsets 00279 for (i = 0; i < ibuf->y; i++) { 00280 row_pointers[ibuf->y-1-i] = (png_bytep) 00281 ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); 00282 } 00283 00284 // write out the entire image data in one call 00285 png_write_image(png_ptr, row_pointers); 00286 00287 // write the additional chunks to the PNG file (not really needed) 00288 png_write_end(png_ptr, info_ptr); 00289 00290 // clean up 00291 MEM_freeN(pixels); 00292 MEM_freeN(row_pointers); 00293 png_destroy_write_struct(&png_ptr, &info_ptr); 00294 00295 if (fp) { 00296 fflush(fp); 00297 fclose(fp); 00298 } 00299 00300 return(1); 00301 } 00302 00303 struct ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags) 00304 { 00305 struct ImBuf *ibuf = NULL; 00306 png_structp png_ptr; 00307 png_infop info_ptr; 00308 unsigned char *pixels = NULL; 00309 png_bytepp row_pointers = NULL; 00310 png_uint_32 width, height; 00311 int bit_depth, color_type; 00312 PNGReadStruct ps; 00313 00314 unsigned char *from, *to; 00315 int i, bytesperpixel; 00316 00317 if (imb_is_a_png(mem) == 0) return(NULL); 00318 00319 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 00320 NULL, NULL, NULL); 00321 if (png_ptr == NULL) { 00322 printf("Cannot png_create_read_struct\n"); 00323 return NULL; 00324 } 00325 00326 info_ptr = png_create_info_struct(png_ptr); 00327 if (info_ptr == NULL) { 00328 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, 00329 (png_infopp)NULL); 00330 printf("Cannot png_create_info_struct\n"); 00331 return NULL; 00332 } 00333 00334 ps.size = size; /* XXX, 4gig limit! */ 00335 ps.data = mem; 00336 ps.seek = 0; 00337 00338 png_set_read_fn(png_ptr, (void *) &ps, ReadData); 00339 00340 if (setjmp(png_jmpbuf(png_ptr))) { 00341 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); 00342 if (pixels) MEM_freeN(pixels); 00343 if (row_pointers) MEM_freeN(row_pointers); 00344 if (ibuf) IMB_freeImBuf(ibuf); 00345 return NULL; 00346 } 00347 00348 // png_set_sig_bytes(png_ptr, 8); 00349 00350 png_read_info(png_ptr, info_ptr); 00351 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, 00352 &color_type, NULL, NULL, NULL); 00353 00354 if (bit_depth == 16) { 00355 png_set_strip_16(png_ptr); 00356 bit_depth = 8; 00357 } 00358 00359 bytesperpixel = png_get_channels(png_ptr, info_ptr); 00360 00361 switch(color_type) { 00362 case PNG_COLOR_TYPE_RGB: 00363 case PNG_COLOR_TYPE_RGB_ALPHA: 00364 break; 00365 case PNG_COLOR_TYPE_PALETTE: 00366 png_set_palette_to_rgb(png_ptr); 00367 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 00368 bytesperpixel = 4; 00369 } else { 00370 bytesperpixel = 3; 00371 } 00372 break; 00373 case PNG_COLOR_TYPE_GRAY: 00374 case PNG_COLOR_TYPE_GRAY_ALPHA: 00375 if (bit_depth < 8) { 00376 png_set_expand(png_ptr); 00377 bit_depth = 8; 00378 } 00379 break; 00380 default: 00381 printf("PNG format not supported\n"); 00382 longjmp(png_jmpbuf(png_ptr), 1); 00383 } 00384 00385 ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0); 00386 00387 if (ibuf) { 00388 ibuf->ftype = PNG; 00389 ibuf->profile = IB_PROFILE_SRGB; 00390 00391 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_pHYs)) { 00392 int unit_type; 00393 png_uint_32 xres, yres; 00394 00395 if(png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type)) 00396 if(unit_type == PNG_RESOLUTION_METER) { 00397 ibuf->ppm[0]= xres; 00398 ibuf->ppm[1]= yres; 00399 } 00400 } 00401 } 00402 else { 00403 printf("Couldn't allocate memory for PNG image\n"); 00404 } 00405 00406 if (ibuf && ((flags & IB_test) == 0)) { 00407 imb_addrectImBuf(ibuf); 00408 00409 pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels"); 00410 if (pixels == NULL) { 00411 printf("Cannot allocate pixels array\n"); 00412 longjmp(png_jmpbuf(png_ptr), 1); 00413 } 00414 00415 // allocate memory for an array of row-pointers 00416 row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers"); 00417 if (row_pointers == NULL) { 00418 printf("Cannot allocate row-pointers array\n"); 00419 longjmp(png_jmpbuf(png_ptr), 1); 00420 } 00421 00422 // set the individual row-pointers to point at the correct offsets 00423 for (i = 0; i < ibuf->y; i++) { 00424 row_pointers[ibuf->y-1-i] = (png_bytep) 00425 ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char)); 00426 } 00427 00428 png_read_image(png_ptr, row_pointers); 00429 00430 // copy image data 00431 00432 to = (unsigned char *) ibuf->rect; 00433 from = pixels; 00434 00435 switch (bytesperpixel) { 00436 case 4: 00437 for (i = ibuf->x * ibuf->y; i > 0; i--) { 00438 to[0] = from[0]; 00439 to[1] = from[1]; 00440 to[2] = from[2]; 00441 to[3] = from[3]; 00442 to += 4; from += 4; 00443 } 00444 break; 00445 case 3: 00446 for (i = ibuf->x * ibuf->y; i > 0; i--) { 00447 to[0] = from[0]; 00448 to[1] = from[1]; 00449 to[2] = from[2]; 00450 to[3] = 0xff; 00451 to += 4; from += 3; 00452 } 00453 break; 00454 case 2: 00455 for (i = ibuf->x * ibuf->y; i > 0; i--) { 00456 to[0] = to[1] = to[2] = from[0]; 00457 to[3] = from[1]; 00458 to += 4; from += 2; 00459 } 00460 break; 00461 case 1: 00462 for (i = ibuf->x * ibuf->y; i > 0; i--) { 00463 to[0] = to[1] = to[2] = from[0]; 00464 to[3] = 0xff; 00465 to += 4; from++; 00466 } 00467 break; 00468 } 00469 00470 if (flags & IB_metadata) { 00471 png_text* text_chunks; 00472 int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL); 00473 for(i = 0; i < count; i++) { 00474 IMB_metadata_add_field(ibuf, text_chunks[i].key, text_chunks[i].text); 00475 ibuf->flags |= IB_metadata; 00476 } 00477 } 00478 00479 png_read_end(png_ptr, info_ptr); 00480 } 00481 00482 // clean up 00483 MEM_freeN(pixels); 00484 MEM_freeN(row_pointers); 00485 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); 00486 00487 return(ibuf); 00488 } 00489