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