|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 00002 /* pngwrite.c - general routines to write a PNG file 00003 * 00004 * Last changed in libpng 1.2.37 [June 4, 2009] 00005 * Copyright (c) 1998-2009 Glenn Randers-Pehrson 00006 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) 00007 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) 00008 * 00009 * This code is released under the libpng license. 00010 * For conditions of distribution and use, see the disclaimer 00011 * and license in png.h 00012 */ 00013 00014 /* Get internal access to png.h */ 00015 #define PNG_INTERNAL 00016 #include "png.h" 00017 #ifdef PNG_WRITE_SUPPORTED 00018 00019 /* Writes all the PNG information. This is the suggested way to use the 00020 * library. If you have a new chunk to add, make a function to write it, 00021 * and put it in the correct location here. If you want the chunk written 00022 * after the image data, put it in png_write_end(). I strongly encourage 00023 * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing 00024 * the chunk, as that will keep the code from breaking if you want to just 00025 * write a plain PNG file. If you have long comments, I suggest writing 00026 * them in png_write_end(), and compressing them. 00027 */ 00028 void PNGAPI 00029 png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) 00030 { 00031 png_debug(1, "in png_write_info_before_PLTE"); 00032 if (png_ptr == NULL || info_ptr == NULL) 00033 return; 00034 if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) 00035 { 00036 png_write_sig(png_ptr); /* Write PNG signature */ 00037 #if defined(PNG_MNG_FEATURES_SUPPORTED) 00038 if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted)) 00039 { 00040 png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); 00041 png_ptr->mng_features_permitted=0; 00042 } 00043 #endif 00044 /* Write IHDR information. */ 00045 png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, 00046 info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, 00047 info_ptr->filter_type, 00048 #if defined(PNG_WRITE_INTERLACING_SUPPORTED) 00049 info_ptr->interlace_type); 00050 #else 00051 0); 00052 #endif 00053 /* The rest of these check to see if the valid field has the appropriate 00054 * flag set, and if it does, writes the chunk. 00055 */ 00056 #if defined(PNG_WRITE_gAMA_SUPPORTED) 00057 if (info_ptr->valid & PNG_INFO_gAMA) 00058 { 00059 # ifdef PNG_FLOATING_POINT_SUPPORTED 00060 png_write_gAMA(png_ptr, info_ptr->gamma); 00061 #else 00062 #ifdef PNG_FIXED_POINT_SUPPORTED 00063 png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma); 00064 # endif 00065 #endif 00066 } 00067 #endif 00068 #if defined(PNG_WRITE_sRGB_SUPPORTED) 00069 if (info_ptr->valid & PNG_INFO_sRGB) 00070 png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); 00071 #endif 00072 #if defined(PNG_WRITE_iCCP_SUPPORTED) 00073 if (info_ptr->valid & PNG_INFO_iCCP) 00074 png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, 00075 info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); 00076 #endif 00077 #if defined(PNG_WRITE_sBIT_SUPPORTED) 00078 if (info_ptr->valid & PNG_INFO_sBIT) 00079 png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); 00080 #endif 00081 #if defined(PNG_WRITE_cHRM_SUPPORTED) 00082 if (info_ptr->valid & PNG_INFO_cHRM) 00083 { 00084 #ifdef PNG_FLOATING_POINT_SUPPORTED 00085 png_write_cHRM(png_ptr, 00086 info_ptr->x_white, info_ptr->y_white, 00087 info_ptr->x_red, info_ptr->y_red, 00088 info_ptr->x_green, info_ptr->y_green, 00089 info_ptr->x_blue, info_ptr->y_blue); 00090 #else 00091 # ifdef PNG_FIXED_POINT_SUPPORTED 00092 png_write_cHRM_fixed(png_ptr, 00093 info_ptr->int_x_white, info_ptr->int_y_white, 00094 info_ptr->int_x_red, info_ptr->int_y_red, 00095 info_ptr->int_x_green, info_ptr->int_y_green, 00096 info_ptr->int_x_blue, info_ptr->int_y_blue); 00097 # endif 00098 #endif 00099 } 00100 #endif 00101 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) 00102 if (info_ptr->unknown_chunks_num) 00103 { 00104 png_unknown_chunk *up; 00105 00106 png_debug(5, "writing extra chunks"); 00107 00108 for (up = info_ptr->unknown_chunks; 00109 up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; 00110 up++) 00111 { 00112 int keep=png_handle_as_unknown(png_ptr, up->name); 00113 if (keep != PNG_HANDLE_CHUNK_NEVER && 00114 up->location && !(up->location & PNG_HAVE_PLTE) && 00115 !(up->location & PNG_HAVE_IDAT) && 00116 ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || 00117 (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) 00118 { 00119 if (up->size == 0) 00120 png_warning(png_ptr, "Writing zero-length unknown chunk"); 00121 png_write_chunk(png_ptr, up->name, up->data, up->size); 00122 } 00123 } 00124 } 00125 #endif 00126 png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; 00127 } 00128 } 00129 00130 void PNGAPI 00131 png_write_info(png_structp png_ptr, png_infop info_ptr) 00132 { 00133 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) 00134 int i; 00135 #endif 00136 00137 png_debug(1, "in png_write_info"); 00138 00139 if (png_ptr == NULL || info_ptr == NULL) 00140 return; 00141 00142 png_write_info_before_PLTE(png_ptr, info_ptr); 00143 00144 if (info_ptr->valid & PNG_INFO_PLTE) 00145 png_write_PLTE(png_ptr, info_ptr->palette, 00146 (png_uint_32)info_ptr->num_palette); 00147 else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 00148 png_error(png_ptr, "Valid palette required for paletted images"); 00149 00150 #if defined(PNG_WRITE_tRNS_SUPPORTED) 00151 if (info_ptr->valid & PNG_INFO_tRNS) 00152 { 00153 #if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) 00154 /* Invert the alpha channel (in tRNS) */ 00155 if ((png_ptr->transformations & PNG_INVERT_ALPHA) && 00156 info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 00157 { 00158 int j; 00159 for (j=0; j<(int)info_ptr->num_trans; j++) 00160 info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]); 00161 } 00162 #endif 00163 png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values), 00164 info_ptr->num_trans, info_ptr->color_type); 00165 } 00166 #endif 00167 #if defined(PNG_WRITE_bKGD_SUPPORTED) 00168 if (info_ptr->valid & PNG_INFO_bKGD) 00169 png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); 00170 #endif 00171 #if defined(PNG_WRITE_hIST_SUPPORTED) 00172 if (info_ptr->valid & PNG_INFO_hIST) 00173 png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); 00174 #endif 00175 #if defined(PNG_WRITE_oFFs_SUPPORTED) 00176 if (info_ptr->valid & PNG_INFO_oFFs) 00177 png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, 00178 info_ptr->offset_unit_type); 00179 #endif 00180 #if defined(PNG_WRITE_pCAL_SUPPORTED) 00181 if (info_ptr->valid & PNG_INFO_pCAL) 00182 png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, 00183 info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, 00184 info_ptr->pcal_units, info_ptr->pcal_params); 00185 #endif 00186 00187 #if defined(PNG_sCAL_SUPPORTED) 00188 if (info_ptr->valid & PNG_INFO_sCAL) 00189 #if defined(PNG_WRITE_sCAL_SUPPORTED) 00190 #if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) 00191 png_write_sCAL(png_ptr, (int)info_ptr->scal_unit, 00192 info_ptr->scal_pixel_width, info_ptr->scal_pixel_height); 00193 #else /* !FLOATING_POINT */ 00194 #ifdef PNG_FIXED_POINT_SUPPORTED 00195 png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, 00196 info_ptr->scal_s_width, info_ptr->scal_s_height); 00197 #endif /* FIXED_POINT */ 00198 #endif /* FLOATING_POINT */ 00199 #else /* !WRITE_sCAL */ 00200 png_warning(png_ptr, 00201 "png_write_sCAL not supported; sCAL chunk not written."); 00202 #endif /* WRITE_sCAL */ 00203 #endif /* sCAL */ 00204 00205 #if defined(PNG_WRITE_pHYs_SUPPORTED) 00206 if (info_ptr->valid & PNG_INFO_pHYs) 00207 png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, 00208 info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); 00209 #endif /* pHYs */ 00210 00211 #if defined(PNG_WRITE_tIME_SUPPORTED) 00212 if (info_ptr->valid & PNG_INFO_tIME) 00213 { 00214 png_write_tIME(png_ptr, &(info_ptr->mod_time)); 00215 png_ptr->mode |= PNG_WROTE_tIME; 00216 } 00217 #endif /* tIME */ 00218 00219 #if defined(PNG_WRITE_sPLT_SUPPORTED) 00220 if (info_ptr->valid & PNG_INFO_sPLT) 00221 for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) 00222 png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); 00223 #endif /* sPLT */ 00224 00225 #if defined(PNG_WRITE_TEXT_SUPPORTED) 00226 /* Check to see if we need to write text chunks */ 00227 for (i = 0; i < info_ptr->num_text; i++) 00228 { 00229 png_debug2(2, "Writing header text chunk %d, type %d", i, 00230 info_ptr->text[i].compression); 00231 /* An internationalized chunk? */ 00232 if (info_ptr->text[i].compression > 0) 00233 { 00234 #if defined(PNG_WRITE_iTXt_SUPPORTED) 00235 /* Write international chunk */ 00236 png_write_iTXt(png_ptr, 00237 info_ptr->text[i].compression, 00238 info_ptr->text[i].key, 00239 info_ptr->text[i].lang, 00240 info_ptr->text[i].lang_key, 00241 info_ptr->text[i].text); 00242 #else 00243 png_warning(png_ptr, "Unable to write international text"); 00244 #endif 00245 /* Mark this chunk as written */ 00246 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 00247 } 00248 /* If we want a compressed text chunk */ 00249 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) 00250 { 00251 #if defined(PNG_WRITE_zTXt_SUPPORTED) 00252 /* Write compressed chunk */ 00253 png_write_zTXt(png_ptr, info_ptr->text[i].key, 00254 info_ptr->text[i].text, 0, 00255 info_ptr->text[i].compression); 00256 #else 00257 png_warning(png_ptr, "Unable to write compressed text"); 00258 #endif 00259 /* Mark this chunk as written */ 00260 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; 00261 } 00262 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) 00263 { 00264 #if defined(PNG_WRITE_tEXt_SUPPORTED) 00265 /* Write uncompressed chunk */ 00266 png_write_tEXt(png_ptr, info_ptr->text[i].key, 00267 info_ptr->text[i].text, 00268 0); 00269 /* Mark this chunk as written */ 00270 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 00271 #else 00272 /* Can't get here */ 00273 png_warning(png_ptr, "Unable to write uncompressed text"); 00274 #endif 00275 } 00276 } 00277 #endif /* tEXt */ 00278 00279 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) 00280 if (info_ptr->unknown_chunks_num) 00281 { 00282 png_unknown_chunk *up; 00283 00284 png_debug(5, "writing extra chunks"); 00285 00286 for (up = info_ptr->unknown_chunks; 00287 up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; 00288 up++) 00289 { 00290 int keep=png_handle_as_unknown(png_ptr, up->name); 00291 if (keep != PNG_HANDLE_CHUNK_NEVER && 00292 up->location && (up->location & PNG_HAVE_PLTE) && 00293 !(up->location & PNG_HAVE_IDAT) && 00294 ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || 00295 (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) 00296 { 00297 png_write_chunk(png_ptr, up->name, up->data, up->size); 00298 } 00299 } 00300 } 00301 #endif 00302 } 00303 00304 /* Writes the end of the PNG file. If you don't want to write comments or 00305 * time information, you can pass NULL for info. If you already wrote these 00306 * in png_write_info(), do not write them again here. If you have long 00307 * comments, I suggest writing them here, and compressing them. 00308 */ 00309 void PNGAPI 00310 png_write_end(png_structp png_ptr, png_infop info_ptr) 00311 { 00312 png_debug(1, "in png_write_end"); 00313 if (png_ptr == NULL) 00314 return; 00315 if (!(png_ptr->mode & PNG_HAVE_IDAT)) 00316 png_error(png_ptr, "No IDATs written into file"); 00317 00318 /* See if user wants us to write information chunks */ 00319 if (info_ptr != NULL) 00320 { 00321 #if defined(PNG_WRITE_TEXT_SUPPORTED) 00322 int i; /* Local index variable */ 00323 #endif 00324 #if defined(PNG_WRITE_tIME_SUPPORTED) 00325 /* Check to see if user has supplied a time chunk */ 00326 if ((info_ptr->valid & PNG_INFO_tIME) && 00327 !(png_ptr->mode & PNG_WROTE_tIME)) 00328 png_write_tIME(png_ptr, &(info_ptr->mod_time)); 00329 #endif 00330 #if defined(PNG_WRITE_TEXT_SUPPORTED) 00331 /* Loop through comment chunks */ 00332 for (i = 0; i < info_ptr->num_text; i++) 00333 { 00334 png_debug2(2, "Writing trailer text chunk %d, type %d", i, 00335 info_ptr->text[i].compression); 00336 /* An internationalized chunk? */ 00337 if (info_ptr->text[i].compression > 0) 00338 { 00339 #if defined(PNG_WRITE_iTXt_SUPPORTED) 00340 /* Write international chunk */ 00341 png_write_iTXt(png_ptr, 00342 info_ptr->text[i].compression, 00343 info_ptr->text[i].key, 00344 info_ptr->text[i].lang, 00345 info_ptr->text[i].lang_key, 00346 info_ptr->text[i].text); 00347 #else 00348 png_warning(png_ptr, "Unable to write international text"); 00349 #endif 00350 /* Mark this chunk as written */ 00351 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 00352 } 00353 else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) 00354 { 00355 #if defined(PNG_WRITE_zTXt_SUPPORTED) 00356 /* Write compressed chunk */ 00357 png_write_zTXt(png_ptr, info_ptr->text[i].key, 00358 info_ptr->text[i].text, 0, 00359 info_ptr->text[i].compression); 00360 #else 00361 png_warning(png_ptr, "Unable to write compressed text"); 00362 #endif 00363 /* Mark this chunk as written */ 00364 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; 00365 } 00366 else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) 00367 { 00368 #if defined(PNG_WRITE_tEXt_SUPPORTED) 00369 /* Write uncompressed chunk */ 00370 png_write_tEXt(png_ptr, info_ptr->text[i].key, 00371 info_ptr->text[i].text, 0); 00372 #else 00373 png_warning(png_ptr, "Unable to write uncompressed text"); 00374 #endif 00375 00376 /* Mark this chunk as written */ 00377 info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; 00378 } 00379 } 00380 #endif 00381 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) 00382 if (info_ptr->unknown_chunks_num) 00383 { 00384 png_unknown_chunk *up; 00385 00386 png_debug(5, "writing extra chunks"); 00387 00388 for (up = info_ptr->unknown_chunks; 00389 up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; 00390 up++) 00391 { 00392 int keep=png_handle_as_unknown(png_ptr, up->name); 00393 if (keep != PNG_HANDLE_CHUNK_NEVER && 00394 up->location && (up->location & PNG_AFTER_IDAT) && 00395 ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || 00396 (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) 00397 { 00398 png_write_chunk(png_ptr, up->name, up->data, up->size); 00399 } 00400 } 00401 } 00402 #endif 00403 } 00404 00405 png_ptr->mode |= PNG_AFTER_IDAT; 00406 00407 /* Write end of PNG file */ 00408 png_write_IEND(png_ptr); 00409 /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, 00410 * and restored again in libpng-1.2.30, may cause some applications that 00411 * do not set png_ptr->output_flush_fn to crash. If your application 00412 * experiences a problem, please try building libpng with 00413 * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to 00414 * png-mng-implement at lists.sf.net . This kludge will be removed 00415 * from libpng-1.4.0. 00416 */ 00417 #if defined(PNG_WRITE_FLUSH_SUPPORTED) && \ 00418 defined(PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED) 00419 png_flush(png_ptr); 00420 #endif 00421 } 00422 00423 #if defined(PNG_WRITE_tIME_SUPPORTED) 00424 #if !defined(_WIN32_WCE) 00425 /* "time.h" functions are not supported on WindowsCE */ 00426 void PNGAPI 00427 png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime) 00428 { 00429 png_debug(1, "in png_convert_from_struct_tm"); 00430 ptime->year = (png_uint_16)(1900 + ttime->tm_year); 00431 ptime->month = (png_byte)(ttime->tm_mon + 1); 00432 ptime->day = (png_byte)ttime->tm_mday; 00433 ptime->hour = (png_byte)ttime->tm_hour; 00434 ptime->minute = (png_byte)ttime->tm_min; 00435 ptime->second = (png_byte)ttime->tm_sec; 00436 } 00437 00438 void PNGAPI 00439 png_convert_from_time_t(png_timep ptime, time_t ttime) 00440 { 00441 struct tm *tbuf; 00442 00443 png_debug(1, "in png_convert_from_time_t"); 00444 tbuf = gmtime(&ttime); 00445 png_convert_from_struct_tm(ptime, tbuf); 00446 } 00447 #endif 00448 #endif 00449 00450 /* Initialize png_ptr structure, and allocate any memory needed */ 00451 png_structp PNGAPI 00452 png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr, 00453 png_error_ptr error_fn, png_error_ptr warn_fn) 00454 { 00455 #ifdef PNG_USER_MEM_SUPPORTED 00456 return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, 00457 warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL)); 00458 } 00459 00460 /* Alternate initialize png_ptr structure, and allocate any memory needed */ 00461 png_structp PNGAPI 00462 png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr, 00463 png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, 00464 png_malloc_ptr malloc_fn, png_free_ptr free_fn) 00465 { 00466 #endif /* PNG_USER_MEM_SUPPORTED */ 00467 #ifdef PNG_SETJMP_SUPPORTED 00468 volatile 00469 #endif 00470 png_structp png_ptr; 00471 #ifdef PNG_SETJMP_SUPPORTED 00472 #ifdef USE_FAR_KEYWORD 00473 jmp_buf jmpbuf; 00474 #endif 00475 #endif 00476 int i; 00477 png_debug(1, "in png_create_write_struct"); 00478 #ifdef PNG_USER_MEM_SUPPORTED 00479 png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, 00480 (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); 00481 #else 00482 png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); 00483 #endif /* PNG_USER_MEM_SUPPORTED */ 00484 if (png_ptr == NULL) 00485 return (NULL); 00486 00487 /* Added at libpng-1.2.6 */ 00488 #ifdef PNG_SET_USER_LIMITS_SUPPORTED 00489 png_ptr->user_width_max=PNG_USER_WIDTH_MAX; 00490 png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; 00491 #endif 00492 00493 #ifdef PNG_SETJMP_SUPPORTED 00494 #ifdef USE_FAR_KEYWORD 00495 if (setjmp(jmpbuf)) 00496 #else 00497 if (setjmp(png_ptr->jmpbuf)) 00498 #endif 00499 { 00500 png_free(png_ptr, png_ptr->zbuf); 00501 png_ptr->zbuf=NULL; 00502 png_destroy_struct(png_ptr); 00503 return (NULL); 00504 } 00505 #ifdef USE_FAR_KEYWORD 00506 png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); 00507 #endif 00508 #endif 00509 00510 #ifdef PNG_USER_MEM_SUPPORTED 00511 png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); 00512 #endif /* PNG_USER_MEM_SUPPORTED */ 00513 png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); 00514 00515 if (user_png_ver) 00516 { 00517 i=0; 00518 do 00519 { 00520 if (user_png_ver[i] != png_libpng_ver[i]) 00521 png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; 00522 } while (png_libpng_ver[i++]); 00523 } 00524 00525 if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) 00526 { 00527 /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so 00528 * we must recompile any applications that use any older library version. 00529 * For versions after libpng 1.0, we will be compatible, so we need 00530 * only check the first digit. 00531 */ 00532 if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || 00533 (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || 00534 (user_png_ver[0] == '0' && user_png_ver[2] < '9')) 00535 { 00536 #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) 00537 char msg[80]; 00538 if (user_png_ver) 00539 { 00540 png_snprintf(msg, 80, 00541 "Application was compiled with png.h from libpng-%.20s", 00542 user_png_ver); 00543 png_warning(png_ptr, msg); 00544 } 00545 png_snprintf(msg, 80, 00546 "Application is running with png.c from libpng-%.20s", 00547 png_libpng_ver); 00548 png_warning(png_ptr, msg); 00549 #endif 00550 #ifdef PNG_ERROR_NUMBERS_SUPPORTED 00551 png_ptr->flags=0; 00552 #endif 00553 png_error(png_ptr, 00554 "Incompatible libpng version in application and library"); 00555 } 00556 } 00557 00558 /* Initialize zbuf - compression buffer */ 00559 png_ptr->zbuf_size = PNG_ZBUF_SIZE; 00560 png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, 00561 (png_uint_32)png_ptr->zbuf_size); 00562 00563 png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL, 00564 png_flush_ptr_NULL); 00565 00566 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 00567 png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, 00568 1, png_doublep_NULL, png_doublep_NULL); 00569 #endif 00570 00571 #ifdef PNG_SETJMP_SUPPORTED 00572 /* Applications that neglect to set up their own setjmp() and then encounter 00573 a png_error() will longjmp here. Since the jmpbuf is then meaningless we 00574 abort instead of returning. */ 00575 #ifdef USE_FAR_KEYWORD 00576 if (setjmp(jmpbuf)) 00577 PNG_ABORT(); 00578 png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf)); 00579 #else 00580 if (setjmp(png_ptr->jmpbuf)) 00581 PNG_ABORT(); 00582 #endif 00583 #endif 00584 return (png_ptr); 00585 } 00586 00587 /* Initialize png_ptr structure, and allocate any memory needed */ 00588 #if defined(PNG_1_0_X) || defined(PNG_1_2_X) 00589 /* Deprecated. */ 00590 #undef png_write_init 00591 void PNGAPI 00592 png_write_init(png_structp png_ptr) 00593 { 00594 /* We only come here via pre-1.0.7-compiled applications */ 00595 png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0); 00596 } 00597 00598 void PNGAPI 00599 png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver, 00600 png_size_t png_struct_size, png_size_t png_info_size) 00601 { 00602 /* We only come here via pre-1.0.12-compiled applications */ 00603 if (png_ptr == NULL) return; 00604 #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) 00605 if (png_sizeof(png_struct) > png_struct_size || 00606 png_sizeof(png_info) > png_info_size) 00607 { 00608 char msg[80]; 00609 png_ptr->warning_fn=NULL; 00610 if (user_png_ver) 00611 { 00612 png_snprintf(msg, 80, 00613 "Application was compiled with png.h from libpng-%.20s", 00614 user_png_ver); 00615 png_warning(png_ptr, msg); 00616 } 00617 png_snprintf(msg, 80, 00618 "Application is running with png.c from libpng-%.20s", 00619 png_libpng_ver); 00620 png_warning(png_ptr, msg); 00621 } 00622 #endif 00623 if (png_sizeof(png_struct) > png_struct_size) 00624 { 00625 png_ptr->error_fn=NULL; 00626 #ifdef PNG_ERROR_NUMBERS_SUPPORTED 00627 png_ptr->flags=0; 00628 #endif 00629 png_error(png_ptr, 00630 "The png struct allocated by the application for writing is too small."); 00631 } 00632 if (png_sizeof(png_info) > png_info_size) 00633 { 00634 png_ptr->error_fn=NULL; 00635 #ifdef PNG_ERROR_NUMBERS_SUPPORTED 00636 png_ptr->flags=0; 00637 #endif 00638 png_error(png_ptr, 00639 "The info struct allocated by the application for writing is too small."); 00640 } 00641 png_write_init_3(&png_ptr, user_png_ver, png_struct_size); 00642 } 00643 #endif /* PNG_1_0_X || PNG_1_2_X */ 00644 00645 00646 void PNGAPI 00647 png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, 00648 png_size_t png_struct_size) 00649 { 00650 png_structp png_ptr=*ptr_ptr; 00651 #ifdef PNG_SETJMP_SUPPORTED 00652 jmp_buf tmp_jmp; /* To save current jump buffer */ 00653 #endif 00654 00655 int i = 0; 00656 00657 if (png_ptr == NULL) 00658 return; 00659 00660 do 00661 { 00662 if (user_png_ver[i] != png_libpng_ver[i]) 00663 { 00664 #ifdef PNG_LEGACY_SUPPORTED 00665 png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; 00666 #else 00667 png_ptr->warning_fn=NULL; 00668 png_warning(png_ptr, 00669 "Application uses deprecated png_write_init() and should be recompiled."); 00670 break; 00671 #endif 00672 } 00673 } while (png_libpng_ver[i++]); 00674 00675 png_debug(1, "in png_write_init_3"); 00676 00677 #ifdef PNG_SETJMP_SUPPORTED 00678 /* Save jump buffer and error functions */ 00679 png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); 00680 #endif 00681 00682 if (png_sizeof(png_struct) > png_struct_size) 00683 { 00684 png_destroy_struct(png_ptr); 00685 png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); 00686 *ptr_ptr = png_ptr; 00687 } 00688 00689 /* Reset all variables to 0 */ 00690 png_memset(png_ptr, 0, png_sizeof(png_struct)); 00691 00692 /* Added at libpng-1.2.6 */ 00693 #ifdef PNG_SET_USER_LIMITS_SUPPORTED 00694 png_ptr->user_width_max=PNG_USER_WIDTH_MAX; 00695 png_ptr->user_height_max=PNG_USER_HEIGHT_MAX; 00696 #endif 00697 00698 #ifdef PNG_SETJMP_SUPPORTED 00699 /* Restore jump buffer */ 00700 png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); 00701 #endif 00702 00703 png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL, 00704 png_flush_ptr_NULL); 00705 00706 /* Initialize zbuf - compression buffer */ 00707 png_ptr->zbuf_size = PNG_ZBUF_SIZE; 00708 png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, 00709 (png_uint_32)png_ptr->zbuf_size); 00710 00711 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 00712 png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT, 00713 1, png_doublep_NULL, png_doublep_NULL); 00714 #endif 00715 } 00716 00717 /* Write a few rows of image data. If the image is interlaced, 00718 * either you will have to write the 7 sub images, or, if you 00719 * have called png_set_interlace_handling(), you will have to 00720 * "write" the image seven times. 00721 */ 00722 void PNGAPI 00723 png_write_rows(png_structp png_ptr, png_bytepp row, 00724 png_uint_32 num_rows) 00725 { 00726 png_uint_32 i; /* Row counter */ 00727 png_bytepp rp; /* Row pointer */ 00728 00729 png_debug(1, "in png_write_rows"); 00730 00731 if (png_ptr == NULL) 00732 return; 00733 00734 /* Loop through the rows */ 00735 for (i = 0, rp = row; i < num_rows; i++, rp++) 00736 { 00737 png_write_row(png_ptr, *rp); 00738 } 00739 } 00740 00741 /* Write the image. You only need to call this function once, even 00742 * if you are writing an interlaced image. 00743 */ 00744 void PNGAPI 00745 png_write_image(png_structp png_ptr, png_bytepp image) 00746 { 00747 png_uint_32 i; /* Row index */ 00748 int pass, num_pass; /* Pass variables */ 00749 png_bytepp rp; /* Points to current row */ 00750 00751 if (png_ptr == NULL) 00752 return; 00753 00754 png_debug(1, "in png_write_image"); 00755 #if defined(PNG_WRITE_INTERLACING_SUPPORTED) 00756 /* Initialize interlace handling. If image is not interlaced, 00757 * this will set pass to 1 00758 */ 00759 num_pass = png_set_interlace_handling(png_ptr); 00760 #else 00761 num_pass = 1; 00762 #endif 00763 /* Loop through passes */ 00764 for (pass = 0; pass < num_pass; pass++) 00765 { 00766 /* Loop through image */ 00767 for (i = 0, rp = image; i < png_ptr->height; i++, rp++) 00768 { 00769 png_write_row(png_ptr, *rp); 00770 } 00771 } 00772 } 00773 00774 /* Called by user to write a row of image data */ 00775 void PNGAPI 00776 png_write_row(png_structp png_ptr, png_bytep row) 00777 { 00778 if (png_ptr == NULL) 00779 return; 00780 png_debug2(1, "in png_write_row (row %ld, pass %d)", 00781 png_ptr->row_number, png_ptr->pass); 00782 00783 /* Initialize transformations and other stuff if first time */ 00784 if (png_ptr->row_number == 0 && png_ptr->pass == 0) 00785 { 00786 /* Make sure we wrote the header info */ 00787 if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) 00788 png_error(png_ptr, 00789 "png_write_info was never called before png_write_row."); 00790 00791 /* Check for transforms that have been set but were defined out */ 00792 #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) 00793 if (png_ptr->transformations & PNG_INVERT_MONO) 00794 png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined."); 00795 #endif 00796 #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) 00797 if (png_ptr->transformations & PNG_FILLER) 00798 png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined."); 00799 #endif 00800 #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED) 00801 if (png_ptr->transformations & PNG_PACKSWAP) 00802 png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined."); 00803 #endif 00804 #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) 00805 if (png_ptr->transformations & PNG_PACK) 00806 png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined."); 00807 #endif 00808 #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) 00809 if (png_ptr->transformations & PNG_SHIFT) 00810 png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined."); 00811 #endif 00812 #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) 00813 if (png_ptr->transformations & PNG_BGR) 00814 png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined."); 00815 #endif 00816 #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) 00817 if (png_ptr->transformations & PNG_SWAP_BYTES) 00818 png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined."); 00819 #endif 00820 00821 png_write_start_row(png_ptr); 00822 } 00823 00824 #if defined(PNG_WRITE_INTERLACING_SUPPORTED) 00825 /* If interlaced and not interested in row, return */ 00826 if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) 00827 { 00828 switch (png_ptr->pass) 00829 { 00830 case 0: 00831 if (png_ptr->row_number & 0x07) 00832 { 00833 png_write_finish_row(png_ptr); 00834 return; 00835 } 00836 break; 00837 case 1: 00838 if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) 00839 { 00840 png_write_finish_row(png_ptr); 00841 return; 00842 } 00843 break; 00844 case 2: 00845 if ((png_ptr->row_number & 0x07) != 4) 00846 { 00847 png_write_finish_row(png_ptr); 00848 return; 00849 } 00850 break; 00851 case 3: 00852 if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) 00853 { 00854 png_write_finish_row(png_ptr); 00855 return; 00856 } 00857 break; 00858 case 4: 00859 if ((png_ptr->row_number & 0x03) != 2) 00860 { 00861 png_write_finish_row(png_ptr); 00862 return; 00863 } 00864 break; 00865 case 5: 00866 if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) 00867 { 00868 png_write_finish_row(png_ptr); 00869 return; 00870 } 00871 break; 00872 case 6: 00873 if (!(png_ptr->row_number & 0x01)) 00874 { 00875 png_write_finish_row(png_ptr); 00876 return; 00877 } 00878 break; 00879 } 00880 } 00881 #endif 00882 00883 /* Set up row info for transformations */ 00884 png_ptr->row_info.color_type = png_ptr->color_type; 00885 png_ptr->row_info.width = png_ptr->usr_width; 00886 png_ptr->row_info.channels = png_ptr->usr_channels; 00887 png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth; 00888 png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * 00889 png_ptr->row_info.channels); 00890 00891 png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, 00892 png_ptr->row_info.width); 00893 00894 png_debug1(3, "row_info->color_type = %d", png_ptr->row_info.color_type); 00895 png_debug1(3, "row_info->width = %lu", png_ptr->row_info.width); 00896 png_debug1(3, "row_info->channels = %d", png_ptr->row_info.channels); 00897 png_debug1(3, "row_info->bit_depth = %d", png_ptr->row_info.bit_depth); 00898 png_debug1(3, "row_info->pixel_depth = %d", png_ptr->row_info.pixel_depth); 00899 png_debug1(3, "row_info->rowbytes = %lu", png_ptr->row_info.rowbytes); 00900 00901 /* Copy user's row into buffer, leaving room for filter byte. */ 00902 png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row, 00903 png_ptr->row_info.rowbytes); 00904 00905 #if defined(PNG_WRITE_INTERLACING_SUPPORTED) 00906 /* Handle interlacing */ 00907 if (png_ptr->interlaced && png_ptr->pass < 6 && 00908 (png_ptr->transformations & PNG_INTERLACE)) 00909 { 00910 png_do_write_interlace(&(png_ptr->row_info), 00911 png_ptr->row_buf + 1, png_ptr->pass); 00912 /* This should always get caught above, but still ... */ 00913 if (!(png_ptr->row_info.width)) 00914 { 00915 png_write_finish_row(png_ptr); 00916 return; 00917 } 00918 } 00919 #endif 00920 00921 /* Handle other transformations */ 00922 if (png_ptr->transformations) 00923 png_do_write_transformations(png_ptr); 00924 00925 #if defined(PNG_MNG_FEATURES_SUPPORTED) 00926 /* Write filter_method 64 (intrapixel differencing) only if 00927 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and 00928 * 2. Libpng did not write a PNG signature (this filter_method is only 00929 * used in PNG datastreams that are embedded in MNG datastreams) and 00930 * 3. The application called png_permit_mng_features with a mask that 00931 * included PNG_FLAG_MNG_FILTER_64 and 00932 * 4. The filter_method is 64 and 00933 * 5. The color_type is RGB or RGBA 00934 */ 00935 if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && 00936 (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) 00937 { 00938 /* Intrapixel differencing */ 00939 png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); 00940 } 00941 #endif 00942 00943 /* Find a filter if necessary, filter the row and write it out. */ 00944 png_write_find_filter(png_ptr, &(png_ptr->row_info)); 00945 00946 if (png_ptr->write_row_fn != NULL) 00947 (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); 00948 } 00949 00950 #if defined(PNG_WRITE_FLUSH_SUPPORTED) 00951 /* Set the automatic flush interval or 0 to turn flushing off */ 00952 void PNGAPI 00953 png_set_flush(png_structp png_ptr, int nrows) 00954 { 00955 png_debug(1, "in png_set_flush"); 00956 if (png_ptr == NULL) 00957 return; 00958 png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); 00959 } 00960 00961 /* Flush the current output buffers now */ 00962 void PNGAPI 00963 png_write_flush(png_structp png_ptr) 00964 { 00965 int wrote_IDAT; 00966 00967 png_debug(1, "in png_write_flush"); 00968 if (png_ptr == NULL) 00969 return; 00970 /* We have already written out all of the data */ 00971 if (png_ptr->row_number >= png_ptr->num_rows) 00972 return; 00973 00974 do 00975 { 00976 int ret; 00977 00978 /* Compress the data */ 00979 ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH); 00980 wrote_IDAT = 0; 00981 00982 /* Check for compression errors */ 00983 if (ret != Z_OK) 00984 { 00985 if (png_ptr->zstream.msg != NULL) 00986 png_error(png_ptr, png_ptr->zstream.msg); 00987 else 00988 png_error(png_ptr, "zlib error"); 00989 } 00990 00991 if (!(png_ptr->zstream.avail_out)) 00992 { 00993 /* Write the IDAT and reset the zlib output buffer */ 00994 png_write_IDAT(png_ptr, png_ptr->zbuf, 00995 png_ptr->zbuf_size); 00996 png_ptr->zstream.next_out = png_ptr->zbuf; 00997 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 00998 wrote_IDAT = 1; 00999 } 01000 } while(wrote_IDAT == 1); 01001 01002 /* If there is any data left to be output, write it into a new IDAT */ 01003 if (png_ptr->zbuf_size != png_ptr->zstream.avail_out) 01004 { 01005 /* Write the IDAT and reset the zlib output buffer */ 01006 png_write_IDAT(png_ptr, png_ptr->zbuf, 01007 png_ptr->zbuf_size - png_ptr->zstream.avail_out); 01008 png_ptr->zstream.next_out = png_ptr->zbuf; 01009 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; 01010 } 01011 png_ptr->flush_rows = 0; 01012 png_flush(png_ptr); 01013 } 01014 #endif /* PNG_WRITE_FLUSH_SUPPORTED */ 01015 01016 /* Free all memory used by the write */ 01017 void PNGAPI 01018 png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) 01019 { 01020 png_structp png_ptr = NULL; 01021 png_infop info_ptr = NULL; 01022 #ifdef PNG_USER_MEM_SUPPORTED 01023 png_free_ptr free_fn = NULL; 01024 png_voidp mem_ptr = NULL; 01025 #endif 01026 01027 png_debug(1, "in png_destroy_write_struct"); 01028 if (png_ptr_ptr != NULL) 01029 { 01030 png_ptr = *png_ptr_ptr; 01031 #ifdef PNG_USER_MEM_SUPPORTED 01032 free_fn = png_ptr->free_fn; 01033 mem_ptr = png_ptr->mem_ptr; 01034 #endif 01035 } 01036 01037 #ifdef PNG_USER_MEM_SUPPORTED 01038 if (png_ptr != NULL) 01039 { 01040 free_fn = png_ptr->free_fn; 01041 mem_ptr = png_ptr->mem_ptr; 01042 } 01043 #endif 01044 01045 if (info_ptr_ptr != NULL) 01046 info_ptr = *info_ptr_ptr; 01047 01048 if (info_ptr != NULL) 01049 { 01050 if (png_ptr != NULL) 01051 { 01052 png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); 01053 01054 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) 01055 if (png_ptr->num_chunk_list) 01056 { 01057 png_free(png_ptr, png_ptr->chunk_list); 01058 png_ptr->chunk_list=NULL; 01059 png_ptr->num_chunk_list = 0; 01060 } 01061 #endif 01062 } 01063 01064 #ifdef PNG_USER_MEM_SUPPORTED 01065 png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, 01066 (png_voidp)mem_ptr); 01067 #else 01068 png_destroy_struct((png_voidp)info_ptr); 01069 #endif 01070 *info_ptr_ptr = NULL; 01071 } 01072 01073 if (png_ptr != NULL) 01074 { 01075 png_write_destroy(png_ptr); 01076 #ifdef PNG_USER_MEM_SUPPORTED 01077 png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, 01078 (png_voidp)mem_ptr); 01079 #else 01080 png_destroy_struct((png_voidp)png_ptr); 01081 #endif 01082 *png_ptr_ptr = NULL; 01083 } 01084 } 01085 01086 01087 /* Free any memory used in png_ptr struct (old method) */ 01088 void /* PRIVATE */ 01089 png_write_destroy(png_structp png_ptr) 01090 { 01091 #ifdef PNG_SETJMP_SUPPORTED 01092 jmp_buf tmp_jmp; /* Save jump buffer */ 01093 #endif 01094 png_error_ptr error_fn; 01095 png_error_ptr warning_fn; 01096 png_voidp error_ptr; 01097 #ifdef PNG_USER_MEM_SUPPORTED 01098 png_free_ptr free_fn; 01099 #endif 01100 01101 png_debug(1, "in png_write_destroy"); 01102 /* Free any memory zlib uses */ 01103 deflateEnd(&png_ptr->zstream); 01104 01105 /* Free our memory. png_free checks NULL for us. */ 01106 png_free(png_ptr, png_ptr->zbuf); 01107 png_free(png_ptr, png_ptr->row_buf); 01108 #ifndef PNG_NO_WRITE_FILTER 01109 png_free(png_ptr, png_ptr->prev_row); 01110 png_free(png_ptr, png_ptr->sub_row); 01111 png_free(png_ptr, png_ptr->up_row); 01112 png_free(png_ptr, png_ptr->avg_row); 01113 png_free(png_ptr, png_ptr->paeth_row); 01114 #endif 01115 01116 #if defined(PNG_TIME_RFC1123_SUPPORTED) 01117 png_free(png_ptr, png_ptr->time_buffer); 01118 #endif 01119 01120 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) 01121 png_free(png_ptr, png_ptr->prev_filters); 01122 png_free(png_ptr, png_ptr->filter_weights); 01123 png_free(png_ptr, png_ptr->inv_filter_weights); 01124 png_free(png_ptr, png_ptr->filter_costs); 01125 png_free(png_ptr, png_ptr->inv_filter_costs); 01126 #endif 01127 01128 #ifdef PNG_SETJMP_SUPPORTED 01129 /* Reset structure */ 01130 png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf)); 01131 #endif 01132 01133 error_fn = png_ptr->error_fn; 01134 warning_fn = png_ptr->warning_fn; 01135 error_ptr = png_ptr->error_ptr; 01136 #ifdef PNG_USER_MEM_SUPPORTED 01137 free_fn = png_ptr->free_fn; 01138 #endif 01139 01140 png_memset(png_ptr, 0, png_sizeof(png_struct)); 01141 01142 png_ptr->error_fn = error_fn; 01143 png_ptr->warning_fn = warning_fn; 01144 png_ptr->error_ptr = error_ptr; 01145 #ifdef PNG_USER_MEM_SUPPORTED 01146 png_ptr->free_fn = free_fn; 01147 #endif 01148 01149 #ifdef PNG_SETJMP_SUPPORTED 01150 png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); 01151 #endif 01152 } 01153 01154 /* Allow the application to select one or more row filters to use. */ 01155 void PNGAPI 01156 png_set_filter(png_structp png_ptr, int method, int filters) 01157 { 01158 png_debug(1, "in png_set_filter"); 01159 if (png_ptr == NULL) 01160 return; 01161 #if defined(PNG_MNG_FEATURES_SUPPORTED) 01162 if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && 01163 (method == PNG_INTRAPIXEL_DIFFERENCING)) 01164 method = PNG_FILTER_TYPE_BASE; 01165 #endif 01166 if (method == PNG_FILTER_TYPE_BASE) 01167 { 01168 switch (filters & (PNG_ALL_FILTERS | 0x07)) 01169 { 01170 #ifndef PNG_NO_WRITE_FILTER 01171 case 5: 01172 case 6: 01173 case 7: png_warning(png_ptr, "Unknown row filter for method 0"); 01174 #endif /* PNG_NO_WRITE_FILTER */ 01175 case PNG_FILTER_VALUE_NONE: 01176 png_ptr->do_filter=PNG_FILTER_NONE; break; 01177 #ifndef PNG_NO_WRITE_FILTER 01178 case PNG_FILTER_VALUE_SUB: 01179 png_ptr->do_filter=PNG_FILTER_SUB; break; 01180 case PNG_FILTER_VALUE_UP: 01181 png_ptr->do_filter=PNG_FILTER_UP; break; 01182 case PNG_FILTER_VALUE_AVG: 01183 png_ptr->do_filter=PNG_FILTER_AVG; break; 01184 case PNG_FILTER_VALUE_PAETH: 01185 png_ptr->do_filter=PNG_FILTER_PAETH; break; 01186 default: png_ptr->do_filter = (png_byte)filters; break; 01187 #else 01188 default: png_warning(png_ptr, "Unknown row filter for method 0"); 01189 #endif /* PNG_NO_WRITE_FILTER */ 01190 } 01191 01192 /* If we have allocated the row_buf, this means we have already started 01193 * with the image and we should have allocated all of the filter buffers 01194 * that have been selected. If prev_row isn't already allocated, then 01195 * it is too late to start using the filters that need it, since we 01196 * will be missing the data in the previous row. If an application 01197 * wants to start and stop using particular filters during compression, 01198 * it should start out with all of the filters, and then add and 01199 * remove them after the start of compression. 01200 */ 01201 if (png_ptr->row_buf != NULL) 01202 { 01203 #ifndef PNG_NO_WRITE_FILTER 01204 if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) 01205 { 01206 png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, 01207 (png_ptr->rowbytes + 1)); 01208 png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; 01209 } 01210 01211 if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) 01212 { 01213 if (png_ptr->prev_row == NULL) 01214 { 01215 png_warning(png_ptr, "Can't add Up filter after starting"); 01216 png_ptr->do_filter &= ~PNG_FILTER_UP; 01217 } 01218 else 01219 { 01220 png_ptr->up_row = (png_bytep)png_malloc(png_ptr, 01221 (png_ptr->rowbytes + 1)); 01222 png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; 01223 } 01224 } 01225 01226 if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) 01227 { 01228 if (png_ptr->prev_row == NULL) 01229 { 01230 png_warning(png_ptr, "Can't add Average filter after starting"); 01231 png_ptr->do_filter &= ~PNG_FILTER_AVG; 01232 } 01233 else 01234 { 01235 png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, 01236 (png_ptr->rowbytes + 1)); 01237 png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; 01238 } 01239 } 01240 01241 if ((png_ptr->do_filter & PNG_FILTER_PAETH) && 01242 png_ptr->paeth_row == NULL) 01243 { 01244 if (png_ptr->prev_row == NULL) 01245 { 01246 png_warning(png_ptr, "Can't add Paeth filter after starting"); 01247 png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); 01248 } 01249 else 01250 { 01251 png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, 01252 (png_ptr->rowbytes + 1)); 01253 png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; 01254 } 01255 } 01256 01257 if (png_ptr->do_filter == PNG_NO_FILTERS) 01258 #endif /* PNG_NO_WRITE_FILTER */ 01259 png_ptr->do_filter = PNG_FILTER_NONE; 01260 } 01261 } 01262 else 01263 png_error(png_ptr, "Unknown custom filter method"); 01264 } 01265 01266 /* This allows us to influence the way in which libpng chooses the "best" 01267 * filter for the current scanline. While the "minimum-sum-of-absolute- 01268 * differences metric is relatively fast and effective, there is some 01269 * question as to whether it can be improved upon by trying to keep the 01270 * filtered data going to zlib more consistent, hopefully resulting in 01271 * better compression. 01272 */ 01273 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */ 01274 void PNGAPI 01275 png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, 01276 int num_weights, png_doublep filter_weights, 01277 png_doublep filter_costs) 01278 { 01279 int i; 01280 01281 png_debug(1, "in png_set_filter_heuristics"); 01282 if (png_ptr == NULL) 01283 return; 01284 if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST) 01285 { 01286 png_warning(png_ptr, "Unknown filter heuristic method"); 01287 return; 01288 } 01289 01290 if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT) 01291 { 01292 heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; 01293 } 01294 01295 if (num_weights < 0 || filter_weights == NULL || 01296 heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) 01297 { 01298 num_weights = 0; 01299 } 01300 01301 png_ptr->num_prev_filters = (png_byte)num_weights; 01302 png_ptr->heuristic_method = (png_byte)heuristic_method; 01303 01304 if (num_weights > 0) 01305 { 01306 if (png_ptr->prev_filters == NULL) 01307 { 01308 png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, 01309 (png_uint_32)(png_sizeof(png_byte) * num_weights)); 01310 01311 /* To make sure that the weighting starts out fairly */ 01312 for (i = 0; i < num_weights; i++) 01313 { 01314 png_ptr->prev_filters[i] = 255; 01315 } 01316 } 01317 01318 if (png_ptr->filter_weights == NULL) 01319 { 01320 png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, 01321 (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); 01322 01323 png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, 01324 (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); 01325 for (i = 0; i < num_weights; i++) 01326 { 01327 png_ptr->inv_filter_weights[i] = 01328 png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; 01329 } 01330 } 01331 01332 for (i = 0; i < num_weights; i++) 01333 { 01334 if (filter_weights[i] < 0.0) 01335 { 01336 png_ptr->inv_filter_weights[i] = 01337 png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; 01338 } 01339 else 01340 { 01341 png_ptr->inv_filter_weights[i] = 01342 (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5); 01343 png_ptr->filter_weights[i] = 01344 (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5); 01345 } 01346 } 01347 } 01348 01349 /* If, in the future, there are other filter methods, this would 01350 * need to be based on png_ptr->filter. 01351 */ 01352 if (png_ptr->filter_costs == NULL) 01353 { 01354 png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, 01355 (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); 01356 01357 png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, 01358 (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); 01359 01360 for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) 01361 { 01362 png_ptr->inv_filter_costs[i] = 01363 png_ptr->filter_costs[i] = PNG_COST_FACTOR; 01364 } 01365 } 01366 01367 /* Here is where we set the relative costs of the different filters. We 01368 * should take the desired compression level into account when setting 01369 * the costs, so that Paeth, for instance, has a high relative cost at low 01370 * compression levels, while it has a lower relative cost at higher 01371 * compression settings. The filter types are in order of increasing 01372 * relative cost, so it would be possible to do this with an algorithm. 01373 */ 01374 for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) 01375 { 01376 if (filter_costs == NULL || filter_costs[i] < 0.0) 01377 { 01378 png_ptr->inv_filter_costs[i] = 01379 png_ptr->filter_costs[i] = PNG_COST_FACTOR; 01380 } 01381 else if (filter_costs[i] >= 1.0) 01382 { 01383 png_ptr->inv_filter_costs[i] = 01384 (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5); 01385 png_ptr->filter_costs[i] = 01386 (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5); 01387 } 01388 } 01389 } 01390 #endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ 01391 01392 void PNGAPI 01393 png_set_compression_level(png_structp png_ptr, int level) 01394 { 01395 png_debug(1, "in png_set_compression_level"); 01396 if (png_ptr == NULL) 01397 return; 01398 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; 01399 png_ptr->zlib_level = level; 01400 } 01401 01402 void PNGAPI 01403 png_set_compression_mem_level(png_structp png_ptr, int mem_level) 01404 { 01405 png_debug(1, "in png_set_compression_mem_level"); 01406 if (png_ptr == NULL) 01407 return; 01408 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; 01409 png_ptr->zlib_mem_level = mem_level; 01410 } 01411 01412 void PNGAPI 01413 png_set_compression_strategy(png_structp png_ptr, int strategy) 01414 { 01415 png_debug(1, "in png_set_compression_strategy"); 01416 if (png_ptr == NULL) 01417 return; 01418 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; 01419 png_ptr->zlib_strategy = strategy; 01420 } 01421 01422 void PNGAPI 01423 png_set_compression_window_bits(png_structp png_ptr, int window_bits) 01424 { 01425 if (png_ptr == NULL) 01426 return; 01427 if (window_bits > 15) 01428 png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); 01429 else if (window_bits < 8) 01430 png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); 01431 #ifndef WBITS_8_OK 01432 /* Avoid libpng bug with 256-byte windows */ 01433 if (window_bits == 8) 01434 { 01435 png_warning(png_ptr, "Compression window is being reset to 512"); 01436 window_bits=9; 01437 } 01438 #endif 01439 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; 01440 png_ptr->zlib_window_bits = window_bits; 01441 } 01442 01443 void PNGAPI 01444 png_set_compression_method(png_structp png_ptr, int method) 01445 { 01446 png_debug(1, "in png_set_compression_method"); 01447 if (png_ptr == NULL) 01448 return; 01449 if (method != 8) 01450 png_warning(png_ptr, "Only compression method 8 is supported by PNG"); 01451 png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; 01452 png_ptr->zlib_method = method; 01453 } 01454 01455 void PNGAPI 01456 png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) 01457 { 01458 if (png_ptr == NULL) 01459 return; 01460 png_ptr->write_row_fn = write_row_fn; 01461 } 01462 01463 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) 01464 void PNGAPI 01465 png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr 01466 write_user_transform_fn) 01467 { 01468 png_debug(1, "in png_set_write_user_transform_fn"); 01469 if (png_ptr == NULL) 01470 return; 01471 png_ptr->transformations |= PNG_USER_TRANSFORM; 01472 png_ptr->write_user_transform_fn = write_user_transform_fn; 01473 } 01474 #endif 01475 01476 01477 #if defined(PNG_INFO_IMAGE_SUPPORTED) 01478 void PNGAPI 01479 png_write_png(png_structp png_ptr, png_infop info_ptr, 01480 int transforms, voidp params) 01481 { 01482 if (png_ptr == NULL || info_ptr == NULL) 01483 return; 01484 #if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) 01485 /* Invert the alpha channel from opacity to transparency */ 01486 if (transforms & PNG_TRANSFORM_INVERT_ALPHA) 01487 png_set_invert_alpha(png_ptr); 01488 #endif 01489 01490 /* Write the file header information. */ 01491 png_write_info(png_ptr, info_ptr); 01492 01493 /* ------ these transformations don't touch the info structure ------- */ 01494 01495 #if defined(PNG_WRITE_INVERT_SUPPORTED) 01496 /* Invert monochrome pixels */ 01497 if (transforms & PNG_TRANSFORM_INVERT_MONO) 01498 png_set_invert_mono(png_ptr); 01499 #endif 01500 01501 #if defined(PNG_WRITE_SHIFT_SUPPORTED) 01502 /* Shift the pixels up to a legal bit depth and fill in 01503 * as appropriate to correctly scale the image. 01504 */ 01505 if ((transforms & PNG_TRANSFORM_SHIFT) 01506 && (info_ptr->valid & PNG_INFO_sBIT)) 01507 png_set_shift(png_ptr, &info_ptr->sig_bit); 01508 #endif 01509 01510 #if defined(PNG_WRITE_PACK_SUPPORTED) 01511 /* Pack pixels into bytes */ 01512 if (transforms & PNG_TRANSFORM_PACKING) 01513 png_set_packing(png_ptr); 01514 #endif 01515 01516 #if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) 01517 /* Swap location of alpha bytes from ARGB to RGBA */ 01518 if (transforms & PNG_TRANSFORM_SWAP_ALPHA) 01519 png_set_swap_alpha(png_ptr); 01520 #endif 01521 01522 #if defined(PNG_WRITE_FILLER_SUPPORTED) 01523 /* Pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels) */ 01524 if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) 01525 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); 01526 else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) 01527 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); 01528 #endif 01529 01530 #if defined(PNG_WRITE_BGR_SUPPORTED) 01531 /* Flip BGR pixels to RGB */ 01532 if (transforms & PNG_TRANSFORM_BGR) 01533 png_set_bgr(png_ptr); 01534 #endif 01535 01536 #if defined(PNG_WRITE_SWAP_SUPPORTED) 01537 /* Swap bytes of 16-bit files to most significant byte first */ 01538 if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) 01539 png_set_swap(png_ptr); 01540 #endif 01541 01542 #if defined(PNG_WRITE_PACKSWAP_SUPPORTED) 01543 /* Swap bits of 1, 2, 4 bit packed pixel formats */ 01544 if (transforms & PNG_TRANSFORM_PACKSWAP) 01545 png_set_packswap(png_ptr); 01546 #endif 01547 01548 /* ----------------------- end of transformations ------------------- */ 01549 01550 /* Write the bits */ 01551 if (info_ptr->valid & PNG_INFO_IDAT) 01552 png_write_image(png_ptr, info_ptr->row_pointers); 01553 01554 /* It is REQUIRED to call this to finish writing the rest of the file */ 01555 png_write_end(png_ptr, info_ptr); 01556 01557 transforms = transforms; /* Quiet compiler warnings */ 01558 params = params; 01559 } 01560 #endif 01561 #endif /* PNG_WRITE_SUPPORTED */