00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #define PNG_INTERNAL
00012 #include "png.h"
00013 #ifdef PNG_WRITE_SUPPORTED
00014
00015
00016
00017
00018
00019 void
00020 png_save_uint_32(png_bytep buf, png_uint_32 i)
00021 {
00022 buf[0] = (png_byte)((i >> 24) & 0xff);
00023 buf[1] = (png_byte)((i >> 16) & 0xff);
00024 buf[2] = (png_byte)((i >> 8) & 0xff);
00025 buf[3] = (png_byte)(i & 0xff);
00026 }
00027
00028 #if defined(PNG_WRITE_pCAL_SUPPORTED) || defined(PNG_WRITE_oFFs_SUPPORTED)
00029
00030
00031
00032
00033 void
00034 png_save_int_32(png_bytep buf, png_int_32 i)
00035 {
00036 buf[0] = (png_byte)((i >> 24) & 0xff);
00037 buf[1] = (png_byte)((i >> 16) & 0xff);
00038 buf[2] = (png_byte)((i >> 8) & 0xff);
00039 buf[3] = (png_byte)(i & 0xff);
00040 }
00041 #endif
00042
00043
00044
00045
00046
00047 void
00048 png_save_uint_16(png_bytep buf, unsigned int i)
00049 {
00050 buf[0] = (png_byte)((i >> 8) & 0xff);
00051 buf[1] = (png_byte)(i & 0xff);
00052 }
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 void PNGAPI
00064 png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
00065 png_bytep data, png_size_t length)
00066 {
00067 png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
00068 png_write_chunk_data(png_ptr, data, length);
00069 png_write_chunk_end(png_ptr);
00070 }
00071
00072
00073
00074
00075
00076 void PNGAPI
00077 png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
00078 png_uint_32 length)
00079 {
00080 png_byte buf[4];
00081 png_debug2(0, "Writing %s chunk (%lu bytes)\n", chunk_name, length);
00082
00083
00084 png_save_uint_32(buf, length);
00085 png_write_data(png_ptr, buf, (png_size_t)4);
00086
00087
00088 png_write_data(png_ptr, chunk_name, (png_size_t)4);
00089
00090 png_reset_crc(png_ptr);
00091 png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
00092 }
00093
00094
00095
00096
00097
00098
00099 void PNGAPI
00100 png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
00101 {
00102
00103 if (data != NULL && length > 0)
00104 {
00105 png_calculate_crc(png_ptr, data, length);
00106 png_write_data(png_ptr, data, length);
00107 }
00108 }
00109
00110
00111 void PNGAPI
00112 png_write_chunk_end(png_structp png_ptr)
00113 {
00114 png_byte buf[4];
00115
00116
00117 png_save_uint_32(buf, png_ptr->crc);
00118
00119 png_write_data(png_ptr, buf, (png_size_t)4);
00120 }
00121
00122
00123
00124
00125
00126
00127
00128 void
00129 png_write_sig(png_structp png_ptr)
00130 {
00131 png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
00132
00133 png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
00134 (png_size_t)8 - png_ptr->sig_bytes);
00135 if(png_ptr->sig_bytes < 3)
00136 png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
00137 }
00138
00139 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
00140
00141
00142
00143
00144
00145
00146
00147 typedef struct
00148 {
00149 char *input;
00150 int input_len;
00151 int num_output_ptr;
00152 int max_output_ptr;
00153 png_charpp output_ptr;
00154 } compression_state;
00155
00156
00157 static int
00158 png_text_compress(png_structp png_ptr,
00159 png_charp text, png_size_t text_len, int compression,
00160 compression_state *comp)
00161 {
00162 int ret;
00163
00164 comp->num_output_ptr = comp->max_output_ptr = 0;
00165 comp->output_ptr = NULL;
00166 comp->input = NULL;
00167
00168
00169 if (compression == PNG_TEXT_COMPRESSION_NONE)
00170 {
00171 comp->input = text;
00172 comp->input_len = text_len;
00173 return((int)text_len);
00174 }
00175
00176 if (compression >= PNG_TEXT_COMPRESSION_LAST)
00177 {
00178 #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
00179 char msg[50];
00180 sprintf(msg, "Unknown compression type %d", compression);
00181 png_warning(png_ptr, msg);
00182 #else
00183 png_warning(png_ptr, "Unknown compression type");
00184 #endif
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 png_ptr->zstream.avail_in = (uInt)text_len;
00204 png_ptr->zstream.next_in = (Bytef *)text;
00205 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
00206 png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
00207
00208
00209 do
00210 {
00211
00212 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
00213 if (ret != Z_OK)
00214 {
00215
00216 if (png_ptr->zstream.msg != NULL)
00217 png_error(png_ptr, png_ptr->zstream.msg);
00218 else
00219 png_error(png_ptr, "zlib error");
00220 }
00221
00222 if (!(png_ptr->zstream.avail_out))
00223 {
00224
00225 if (comp->num_output_ptr >= comp->max_output_ptr)
00226 {
00227 int old_max;
00228
00229 old_max = comp->max_output_ptr;
00230 comp->max_output_ptr = comp->num_output_ptr + 4;
00231 if (comp->output_ptr != NULL)
00232 {
00233 png_charpp old_ptr;
00234
00235 old_ptr = comp->output_ptr;
00236 comp->output_ptr = (png_charpp)png_malloc(png_ptr,
00237 (png_uint_32)(comp->max_output_ptr *
00238 png_sizeof (png_charpp)));
00239 png_memcpy(comp->output_ptr, old_ptr, old_max
00240 * png_sizeof (png_charp));
00241 png_free(png_ptr, old_ptr);
00242 }
00243 else
00244 comp->output_ptr = (png_charpp)png_malloc(png_ptr,
00245 (png_uint_32)(comp->max_output_ptr *
00246 png_sizeof (png_charp)));
00247 }
00248
00249
00250 comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr,
00251 (png_uint_32)png_ptr->zbuf_size);
00252 png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
00253 png_ptr->zbuf_size);
00254 comp->num_output_ptr++;
00255
00256
00257 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
00258 png_ptr->zstream.next_out = png_ptr->zbuf;
00259 }
00260
00261 } while (png_ptr->zstream.avail_in);
00262
00263
00264 do
00265 {
00266
00267 ret = deflate(&png_ptr->zstream, Z_FINISH);
00268
00269 if (ret == Z_OK)
00270 {
00271
00272 if (!(png_ptr->zstream.avail_out))
00273 {
00274
00275 if (comp->num_output_ptr >= comp->max_output_ptr)
00276 {
00277 int old_max;
00278
00279 old_max = comp->max_output_ptr;
00280 comp->max_output_ptr = comp->num_output_ptr + 4;
00281 if (comp->output_ptr != NULL)
00282 {
00283 png_charpp old_ptr;
00284
00285 old_ptr = comp->output_ptr;
00286
00287 comp->output_ptr = (png_charpp)png_malloc(png_ptr,
00288 (png_uint_32)(comp->max_output_ptr *
00289 png_sizeof (png_charpp)));
00290 png_memcpy(comp->output_ptr, old_ptr,
00291 old_max * png_sizeof (png_charp));
00292 png_free(png_ptr, old_ptr);
00293 }
00294 else
00295 comp->output_ptr = (png_charpp)png_malloc(png_ptr,
00296 (png_uint_32)(comp->max_output_ptr *
00297 png_sizeof (png_charp)));
00298 }
00299
00300
00301 comp->output_ptr[comp->num_output_ptr] =
00302 (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size);
00303 png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
00304 png_ptr->zbuf_size);
00305 comp->num_output_ptr++;
00306
00307
00308 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
00309 png_ptr->zstream.next_out = png_ptr->zbuf;
00310 }
00311 }
00312 else if (ret != Z_STREAM_END)
00313 {
00314
00315 if (png_ptr->zstream.msg != NULL)
00316 png_error(png_ptr, png_ptr->zstream.msg);
00317 else
00318 png_error(png_ptr, "zlib error");
00319 }
00320 } while (ret != Z_STREAM_END);
00321
00322
00323 text_len = png_ptr->zbuf_size * comp->num_output_ptr;
00324 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
00325 text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
00326
00327 return((int)text_len);
00328 }
00329
00330
00331 static void
00332 png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
00333 {
00334 int i;
00335
00336
00337 if (comp->input)
00338 {
00339 png_write_chunk_data(png_ptr, (png_bytep)comp->input,
00340 (png_size_t)comp->input_len);
00341 return;
00342 }
00343
00344
00345 for (i = 0; i < comp->num_output_ptr; i++)
00346 {
00347 png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
00348 png_ptr->zbuf_size);
00349 png_free(png_ptr, comp->output_ptr[i]);
00350 comp->output_ptr[i]=NULL;
00351 }
00352 if (comp->max_output_ptr != 0)
00353 png_free(png_ptr, comp->output_ptr);
00354 comp->output_ptr=NULL;
00355
00356 if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
00357 png_write_chunk_data(png_ptr, png_ptr->zbuf,
00358 png_ptr->zbuf_size - png_ptr->zstream.avail_out);
00359
00360
00361 deflateReset(&png_ptr->zstream);
00362 png_ptr->zstream.data_type = Z_BINARY;
00363 }
00364 #endif
00365
00366
00367
00368
00369
00370 void
00371 png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
00372 int bit_depth, int color_type, int compression_type, int filter_type,
00373 int interlace_type)
00374 {
00375 #ifdef PNG_USE_LOCAL_ARRAYS
00376 PNG_IHDR;
00377 #endif
00378 png_byte buf[13];
00379
00380 png_debug(1, "in png_write_IHDR\n");
00381
00382 switch (color_type)
00383 {
00384 case PNG_COLOR_TYPE_GRAY:
00385 switch (bit_depth)
00386 {
00387 case 1:
00388 case 2:
00389 case 4:
00390 case 8:
00391 case 16: png_ptr->channels = 1; break;
00392 default: png_error(png_ptr,"Invalid bit depth for grayscale image");
00393 }
00394 break;
00395 case PNG_COLOR_TYPE_RGB:
00396 if (bit_depth != 8 && bit_depth != 16)
00397 png_error(png_ptr, "Invalid bit depth for RGB image");
00398 png_ptr->channels = 3;
00399 break;
00400 case PNG_COLOR_TYPE_PALETTE:
00401 switch (bit_depth)
00402 {
00403 case 1:
00404 case 2:
00405 case 4:
00406 case 8: png_ptr->channels = 1; break;
00407 default: png_error(png_ptr, "Invalid bit depth for paletted image");
00408 }
00409 break;
00410 case PNG_COLOR_TYPE_GRAY_ALPHA:
00411 if (bit_depth != 8 && bit_depth != 16)
00412 png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
00413 png_ptr->channels = 2;
00414 break;
00415 case PNG_COLOR_TYPE_RGB_ALPHA:
00416 if (bit_depth != 8 && bit_depth != 16)
00417 png_error(png_ptr, "Invalid bit depth for RGBA image");
00418 png_ptr->channels = 4;
00419 break;
00420 default:
00421 png_error(png_ptr, "Invalid image color type specified");
00422 }
00423
00424 if (compression_type != PNG_COMPRESSION_TYPE_BASE)
00425 {
00426 png_warning(png_ptr, "Invalid compression type specified");
00427 compression_type = PNG_COMPRESSION_TYPE_BASE;
00428 }
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 if (
00440 #if defined(PNG_MNG_FEATURES_SUPPORTED)
00441 !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
00442 ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
00443 (color_type == PNG_COLOR_TYPE_RGB ||
00444 color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
00445 (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
00446 #endif
00447 filter_type != PNG_FILTER_TYPE_BASE)
00448 {
00449 png_warning(png_ptr, "Invalid filter type specified");
00450 filter_type = PNG_FILTER_TYPE_BASE;
00451 }
00452
00453 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
00454 if (interlace_type != PNG_INTERLACE_NONE &&
00455 interlace_type != PNG_INTERLACE_ADAM7)
00456 {
00457 png_warning(png_ptr, "Invalid interlace type specified");
00458 interlace_type = PNG_INTERLACE_ADAM7;
00459 }
00460 #else
00461 interlace_type=PNG_INTERLACE_NONE;
00462 #endif
00463
00464
00465 png_ptr->bit_depth = (png_byte)bit_depth;
00466 png_ptr->color_type = (png_byte)color_type;
00467 png_ptr->interlaced = (png_byte)interlace_type;
00468 #if defined(PNG_MNG_FEATURES_SUPPORTED)
00469 png_ptr->filter_type = (png_byte)filter_type;
00470 #endif
00471 png_ptr->compression_type = (png_byte)compression_type;
00472 png_ptr->width = width;
00473 png_ptr->height = height;
00474
00475 png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
00476 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
00477
00478 png_ptr->usr_width = png_ptr->width;
00479 png_ptr->usr_bit_depth = png_ptr->bit_depth;
00480 png_ptr->usr_channels = png_ptr->channels;
00481
00482
00483 png_save_uint_32(buf, width);
00484 png_save_uint_32(buf + 4, height);
00485 buf[8] = (png_byte)bit_depth;
00486 buf[9] = (png_byte)color_type;
00487 buf[10] = (png_byte)compression_type;
00488 buf[11] = (png_byte)filter_type;
00489 buf[12] = (png_byte)interlace_type;
00490
00491
00492 png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13);
00493
00494
00495 png_ptr->zstream.zalloc = png_zalloc;
00496 png_ptr->zstream.zfree = png_zfree;
00497 png_ptr->zstream.opaque = (voidpf)png_ptr;
00498 if (!(png_ptr->do_filter))
00499 {
00500 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
00501 png_ptr->bit_depth < 8)
00502 png_ptr->do_filter = PNG_FILTER_NONE;
00503 else
00504 png_ptr->do_filter = PNG_ALL_FILTERS;
00505 }
00506 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
00507 {
00508 if (png_ptr->do_filter != PNG_FILTER_NONE)
00509 png_ptr->zlib_strategy = Z_FILTERED;
00510 else
00511 png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
00512 }
00513 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
00514 png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
00515 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
00516 png_ptr->zlib_mem_level = 8;
00517 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
00518 png_ptr->zlib_window_bits = 15;
00519 if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
00520 png_ptr->zlib_method = 8;
00521 deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
00522 png_ptr->zlib_method, png_ptr->zlib_window_bits,
00523 png_ptr->zlib_mem_level, png_ptr->zlib_strategy);
00524 png_ptr->zstream.next_out = png_ptr->zbuf;
00525 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
00526
00527
00528 png_ptr->zstream.data_type = Z_BINARY;
00529
00530 png_ptr->mode = PNG_HAVE_IHDR;
00531 }
00532
00533
00534
00535
00536
00537 void
00538 png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
00539 {
00540 #ifdef PNG_USE_LOCAL_ARRAYS
00541 PNG_PLTE;
00542 #endif
00543 png_uint_32 i;
00544 png_colorp pal_ptr;
00545 png_byte buf[3];
00546
00547 png_debug(1, "in png_write_PLTE\n");
00548 if ((
00549 #if defined(PNG_MNG_FEATURES_SUPPORTED)
00550 !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
00551 #endif
00552 num_pal == 0) || num_pal > 256)
00553 {
00554 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
00555 {
00556 png_error(png_ptr, "Invalid number of colors in palette");
00557 }
00558 else
00559 {
00560 png_warning(png_ptr, "Invalid number of colors in palette");
00561 return;
00562 }
00563 }
00564
00565 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
00566 {
00567 png_warning(png_ptr,
00568 "Ignoring request to write a PLTE chunk in grayscale PNG");
00569 return;
00570 }
00571
00572 png_ptr->num_palette = (png_uint_16)num_pal;
00573 png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
00574
00575 png_write_chunk_start(png_ptr, (png_bytep)png_PLTE, num_pal * 3);
00576 #ifndef PNG_NO_POINTER_INDEXING
00577 for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
00578 {
00579 buf[0] = pal_ptr->red;
00580 buf[1] = pal_ptr->green;
00581 buf[2] = pal_ptr->blue;
00582 png_write_chunk_data(png_ptr, buf, (png_size_t)3);
00583 }
00584 #else
00585
00586 pal_ptr=palette;
00587 for (i = 0; i < num_pal; i++)
00588 {
00589 buf[0] = pal_ptr[i].red;
00590 buf[1] = pal_ptr[i].green;
00591 buf[2] = pal_ptr[i].blue;
00592 png_write_chunk_data(png_ptr, buf, (png_size_t)3);
00593 }
00594 #endif
00595 png_write_chunk_end(png_ptr);
00596 png_ptr->mode |= PNG_HAVE_PLTE;
00597 }
00598
00599
00600 void
00601 png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
00602 {
00603 #ifdef PNG_USE_LOCAL_ARRAYS
00604 PNG_IDAT;
00605 #endif
00606 png_debug(1, "in png_write_IDAT\n");
00607
00608
00609
00610 if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
00611 png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
00612 {
00613 unsigned int z_cmf = data[0];
00614 if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
00615 {
00616
00617
00618
00619 if (length >= 2 &&
00620 png_ptr->height < 16384 && png_ptr->width < 16384)
00621 {
00622 png_uint_32 uncompressed_idat_size = png_ptr->height *
00623 ((png_ptr->width *
00624 png_ptr->channels * png_ptr->bit_depth + 15) >> 3);
00625 unsigned int z_cinfo = z_cmf >> 4;
00626 unsigned int half_z_window_size = 1 << (z_cinfo + 7);
00627 while (uncompressed_idat_size <= half_z_window_size &&
00628 half_z_window_size >= 256)
00629 {
00630 z_cinfo--;
00631 half_z_window_size >>= 1;
00632 }
00633 z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
00634 if (data[0] != (png_byte)z_cmf)
00635 {
00636 data[0] = (png_byte)z_cmf;
00637 data[1] &= 0xe0;
00638 data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f);
00639 }
00640 }
00641 }
00642 else
00643 png_error(png_ptr,
00644 "Invalid zlib compression method or flags in IDAT");
00645 }
00646
00647 png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
00648 png_ptr->mode |= PNG_HAVE_IDAT;
00649 }
00650
00651
00652 void
00653 png_write_IEND(png_structp png_ptr)
00654 {
00655 #ifdef PNG_USE_LOCAL_ARRAYS
00656 PNG_IEND;
00657 #endif
00658 png_debug(1, "in png_write_IEND\n");
00659 png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL,
00660 (png_size_t)0);
00661 png_ptr->mode |= PNG_HAVE_IEND;
00662 }
00663
00664 #if defined(PNG_WRITE_gAMA_SUPPORTED)
00665
00666 #ifdef PNG_FLOATING_POINT_SUPPORTED
00667 void
00668 png_write_gAMA(png_structp png_ptr, double file_gamma)
00669 {
00670 #ifdef PNG_USE_LOCAL_ARRAYS
00671 PNG_gAMA;
00672 #endif
00673 png_uint_32 igamma;
00674 png_byte buf[4];
00675
00676 png_debug(1, "in png_write_gAMA\n");
00677
00678 igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
00679 png_save_uint_32(buf, igamma);
00680 png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
00681 }
00682 #endif
00683 #ifdef PNG_FIXED_POINT_SUPPORTED
00684 void
00685 png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
00686 {
00687 #ifdef PNG_USE_LOCAL_ARRAYS
00688 PNG_gAMA;
00689 #endif
00690 png_byte buf[4];
00691
00692 png_debug(1, "in png_write_gAMA\n");
00693
00694 png_save_uint_32(buf, (png_uint_32)file_gamma);
00695 png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
00696 }
00697 #endif
00698 #endif
00699
00700 #if defined(PNG_WRITE_sRGB_SUPPORTED)
00701
00702 void
00703 png_write_sRGB(png_structp png_ptr, int srgb_intent)
00704 {
00705 #ifdef PNG_USE_LOCAL_ARRAYS
00706 PNG_sRGB;
00707 #endif
00708 png_byte buf[1];
00709
00710 png_debug(1, "in png_write_sRGB\n");
00711 if(srgb_intent >= PNG_sRGB_INTENT_LAST)
00712 png_warning(png_ptr,
00713 "Invalid sRGB rendering intent specified");
00714 buf[0]=(png_byte)srgb_intent;
00715 png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
00716 }
00717 #endif
00718
00719 #if defined(PNG_WRITE_iCCP_SUPPORTED)
00720
00721 void
00722 png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type,
00723 png_charp profile, int profile_len)
00724 {
00725 #ifdef PNG_USE_LOCAL_ARRAYS
00726 PNG_iCCP;
00727 #endif
00728 png_size_t name_len;
00729 png_charp new_name;
00730 compression_state comp;
00731
00732 png_debug(1, "in png_write_iCCP\n");
00733 if (name == NULL || (name_len = png_check_keyword(png_ptr, name,
00734 &new_name)) == 0)
00735 {
00736 png_warning(png_ptr, "Empty keyword in iCCP chunk");
00737 return;
00738 }
00739
00740 if (compression_type != PNG_COMPRESSION_TYPE_BASE)
00741 png_warning(png_ptr, "Unknown compression type in iCCP chunk");
00742
00743 if (profile == NULL)
00744 profile_len = 0;
00745
00746 if (profile_len)
00747 profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
00748 PNG_COMPRESSION_TYPE_BASE, &comp);
00749
00750
00751 png_write_chunk_start(png_ptr, (png_bytep)png_iCCP,
00752 (png_uint_32)name_len+profile_len+2);
00753 new_name[name_len+1]=0x00;
00754 png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 2);
00755
00756 if (profile_len)
00757 png_write_compressed_data_out(png_ptr, &comp);
00758
00759 png_write_chunk_end(png_ptr);
00760 png_free(png_ptr, new_name);
00761 }
00762 #endif
00763
00764 #if defined(PNG_WRITE_sPLT_SUPPORTED)
00765
00766 void
00767 png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
00768 {
00769 #ifdef PNG_USE_LOCAL_ARRAYS
00770 PNG_sPLT;
00771 #endif
00772 png_size_t name_len;
00773 png_charp new_name;
00774 png_byte entrybuf[10];
00775 int entry_size = (spalette->depth == 8 ? 6 : 10);
00776 int palette_size = entry_size * spalette->nentries;
00777 png_sPLT_entryp ep;
00778 #ifdef PNG_NO_POINTER_INDEXING
00779 int i;
00780 #endif
00781
00782 png_debug(1, "in png_write_sPLT\n");
00783 if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
00784 spalette->name, &new_name))==0)
00785 {
00786 png_warning(png_ptr, "Empty keyword in sPLT chunk");
00787 return;
00788 }
00789
00790
00791 png_write_chunk_start(png_ptr, (png_bytep)png_sPLT,
00792 (png_uint_32)(name_len + 2 + palette_size));
00793 png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
00794 png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
00795
00796
00797 #ifndef PNG_NO_POINTER_INDEXING
00798 for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++)
00799 {
00800 if (spalette->depth == 8)
00801 {
00802 entrybuf[0] = (png_byte)ep->red;
00803 entrybuf[1] = (png_byte)ep->green;
00804 entrybuf[2] = (png_byte)ep->blue;
00805 entrybuf[3] = (png_byte)ep->alpha;
00806 png_save_uint_16(entrybuf + 4, ep->frequency);
00807 }
00808 else
00809 {
00810 png_save_uint_16(entrybuf + 0, ep->red);
00811 png_save_uint_16(entrybuf + 2, ep->green);
00812 png_save_uint_16(entrybuf + 4, ep->blue);
00813 png_save_uint_16(entrybuf + 6, ep->alpha);
00814 png_save_uint_16(entrybuf + 8, ep->frequency);
00815 }
00816 png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
00817 }
00818 #else
00819 ep=spalette->entries;
00820 for (i=0; i>spalette->nentries; i++)
00821 {
00822 if (spalette->depth == 8)
00823 {
00824 entrybuf[0] = (png_byte)ep[i].red;
00825 entrybuf[1] = (png_byte)ep[i].green;
00826 entrybuf[2] = (png_byte)ep[i].blue;
00827 entrybuf[3] = (png_byte)ep[i].alpha;
00828 png_save_uint_16(entrybuf + 4, ep[i].frequency);
00829 }
00830 else
00831 {
00832 png_save_uint_16(entrybuf + 0, ep[i].red);
00833 png_save_uint_16(entrybuf + 2, ep[i].green);
00834 png_save_uint_16(entrybuf + 4, ep[i].blue);
00835 png_save_uint_16(entrybuf + 6, ep[i].alpha);
00836 png_save_uint_16(entrybuf + 8, ep[i].frequency);
00837 }
00838 png_write_chunk_data(png_ptr, entrybuf, entry_size);
00839 }
00840 #endif
00841
00842 png_write_chunk_end(png_ptr);
00843 png_free(png_ptr, new_name);
00844 }
00845 #endif
00846
00847 #if defined(PNG_WRITE_sBIT_SUPPORTED)
00848
00849 void
00850 png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
00851 {
00852 #ifdef PNG_USE_LOCAL_ARRAYS
00853 PNG_sBIT;
00854 #endif
00855 png_byte buf[4];
00856 png_size_t size;
00857
00858 png_debug(1, "in png_write_sBIT\n");
00859
00860 if (color_type & PNG_COLOR_MASK_COLOR)
00861 {
00862 png_byte maxbits;
00863
00864 maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
00865 png_ptr->usr_bit_depth);
00866 if (sbit->red == 0 || sbit->red > maxbits ||
00867 sbit->green == 0 || sbit->green > maxbits ||
00868 sbit->blue == 0 || sbit->blue > maxbits)
00869 {
00870 png_warning(png_ptr, "Invalid sBIT depth specified");
00871 return;
00872 }
00873 buf[0] = sbit->red;
00874 buf[1] = sbit->green;
00875 buf[2] = sbit->blue;
00876 size = 3;
00877 }
00878 else
00879 {
00880 if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
00881 {
00882 png_warning(png_ptr, "Invalid sBIT depth specified");
00883 return;
00884 }
00885 buf[0] = sbit->gray;
00886 size = 1;
00887 }
00888
00889 if (color_type & PNG_COLOR_MASK_ALPHA)
00890 {
00891 if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
00892 {
00893 png_warning(png_ptr, "Invalid sBIT depth specified");
00894 return;
00895 }
00896 buf[size++] = sbit->alpha;
00897 }
00898
00899 png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
00900 }
00901 #endif
00902
00903 #if defined(PNG_WRITE_cHRM_SUPPORTED)
00904
00905 #ifdef PNG_FLOATING_POINT_SUPPORTED
00906 void
00907 png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
00908 double red_x, double red_y, double green_x, double green_y,
00909 double blue_x, double blue_y)
00910 {
00911 #ifdef PNG_USE_LOCAL_ARRAYS
00912 PNG_cHRM;
00913 #endif
00914 png_byte buf[32];
00915 png_uint_32 itemp;
00916
00917 png_debug(1, "in png_write_cHRM\n");
00918
00919 if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
00920 white_x + white_y > 1.0)
00921 {
00922 png_warning(png_ptr, "Invalid cHRM white point specified");
00923 #if !defined(PNG_NO_CONSOLE_IO)
00924 fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
00925 #endif
00926 return;
00927 }
00928 itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
00929 png_save_uint_32(buf, itemp);
00930 itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
00931 png_save_uint_32(buf + 4, itemp);
00932
00933 if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
00934 red_x + red_y > 1.0)
00935 {
00936 png_warning(png_ptr, "Invalid cHRM red point specified");
00937 return;
00938 }
00939 itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
00940 png_save_uint_32(buf + 8, itemp);
00941 itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
00942 png_save_uint_32(buf + 12, itemp);
00943
00944 if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
00945 green_x + green_y > 1.0)
00946 {
00947 png_warning(png_ptr, "Invalid cHRM green point specified");
00948 return;
00949 }
00950 itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
00951 png_save_uint_32(buf + 16, itemp);
00952 itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
00953 png_save_uint_32(buf + 20, itemp);
00954
00955 if (blue_x < 0 || blue_x > 0.8 || blue_y < 0 || blue_y > 0.8 ||
00956 blue_x + blue_y > 1.0)
00957 {
00958 png_warning(png_ptr, "Invalid cHRM blue point specified");
00959 return;
00960 }
00961 itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
00962 png_save_uint_32(buf + 24, itemp);
00963 itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
00964 png_save_uint_32(buf + 28, itemp);
00965
00966 png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
00967 }
00968 #endif
00969 #ifdef PNG_FIXED_POINT_SUPPORTED
00970 void
00971 png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x,
00972 png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y,
00973 png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x,
00974 png_fixed_point blue_y)
00975 {
00976 #ifdef PNG_USE_LOCAL_ARRAYS
00977 PNG_cHRM;
00978 #endif
00979 png_byte buf[32];
00980
00981 png_debug(1, "in png_write_cHRM\n");
00982
00983 if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
00984 {
00985 png_warning(png_ptr, "Invalid fixed cHRM white point specified");
00986 #if !defined(PNG_NO_CONSOLE_IO)
00987 fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y);
00988 #endif
00989 return;
00990 }
00991 png_save_uint_32(buf, (png_uint_32)white_x);
00992 png_save_uint_32(buf + 4, (png_uint_32)white_y);
00993
00994 if (red_x > 80000L || red_y > 80000L || red_x + red_y > 100000L)
00995 {
00996 png_warning(png_ptr, "Invalid cHRM fixed red point specified");
00997 return;
00998 }
00999 png_save_uint_32(buf + 8, (png_uint_32)red_x);
01000 png_save_uint_32(buf + 12, (png_uint_32)red_y);
01001
01002 if (green_x > 80000L || green_y > 80000L || green_x + green_y > 100000L)
01003 {
01004 png_warning(png_ptr, "Invalid fixed cHRM green point specified");
01005 return;
01006 }
01007 png_save_uint_32(buf + 16, (png_uint_32)green_x);
01008 png_save_uint_32(buf + 20, (png_uint_32)green_y);
01009
01010 if (blue_x > 80000L || blue_y > 80000L || blue_x + blue_y > 100000L)
01011 {
01012 png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
01013 return;
01014 }
01015 png_save_uint_32(buf + 24, (png_uint_32)blue_x);
01016 png_save_uint_32(buf + 28, (png_uint_32)blue_y);
01017
01018 png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
01019 }
01020 #endif
01021 #endif
01022
01023 #if defined(PNG_WRITE_tRNS_SUPPORTED)
01024
01025 void
01026 png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
01027 int num_trans, int color_type)
01028 {
01029 #ifdef PNG_USE_LOCAL_ARRAYS
01030 PNG_tRNS;
01031 #endif
01032 png_byte buf[6];
01033
01034 png_debug(1, "in png_write_tRNS\n");
01035 if (color_type == PNG_COLOR_TYPE_PALETTE)
01036 {
01037 if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
01038 {
01039 png_warning(png_ptr,"Invalid number of transparent colors specified");
01040 return;
01041 }
01042
01043 png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans);
01044 }
01045 else if (color_type == PNG_COLOR_TYPE_GRAY)
01046 {
01047
01048 if(tran->gray >= (1 << png_ptr->bit_depth))
01049 {
01050 png_warning(png_ptr,
01051 "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
01052 return;
01053 }
01054 png_save_uint_16(buf, tran->gray);
01055 png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
01056 }
01057 else if (color_type == PNG_COLOR_TYPE_RGB)
01058 {
01059
01060 png_save_uint_16(buf, tran->red);
01061 png_save_uint_16(buf + 2, tran->green);
01062 png_save_uint_16(buf + 4, tran->blue);
01063 if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
01064 {
01065 png_warning(png_ptr,
01066 "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
01067 return;
01068 }
01069 png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
01070 }
01071 else
01072 {
01073 png_warning(png_ptr, "Can't write tRNS with an alpha channel");
01074 }
01075 }
01076 #endif
01077
01078 #if defined(PNG_WRITE_bKGD_SUPPORTED)
01079
01080 void
01081 png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
01082 {
01083 #ifdef PNG_USE_LOCAL_ARRAYS
01084 PNG_bKGD;
01085 #endif
01086 png_byte buf[6];
01087
01088 png_debug(1, "in png_write_bKGD\n");
01089 if (color_type == PNG_COLOR_TYPE_PALETTE)
01090 {
01091 if (
01092 #if defined(PNG_MNG_FEATURES_SUPPORTED)
01093 (png_ptr->num_palette ||
01094 (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
01095 #endif
01096 back->index > png_ptr->num_palette)
01097 {
01098 png_warning(png_ptr, "Invalid background palette index");
01099 return;
01100 }
01101 buf[0] = back->index;
01102 png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
01103 }
01104 else if (color_type & PNG_COLOR_MASK_COLOR)
01105 {
01106 png_save_uint_16(buf, back->red);
01107 png_save_uint_16(buf + 2, back->green);
01108 png_save_uint_16(buf + 4, back->blue);
01109 if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
01110 {
01111 png_warning(png_ptr,
01112 "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
01113 return;
01114 }
01115 png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
01116 }
01117 else
01118 {
01119 if(back->gray >= (1 << png_ptr->bit_depth))
01120 {
01121 png_warning(png_ptr,
01122 "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
01123 return;
01124 }
01125 png_save_uint_16(buf, back->gray);
01126 png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
01127 }
01128 }
01129 #endif
01130
01131 #if defined(PNG_WRITE_hIST_SUPPORTED)
01132
01133 void
01134 png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
01135 {
01136 #ifdef PNG_USE_LOCAL_ARRAYS
01137 PNG_hIST;
01138 #endif
01139 int i;
01140 png_byte buf[3];
01141
01142 png_debug(1, "in png_write_hIST\n");
01143 if (num_hist > (int)png_ptr->num_palette)
01144 {
01145 png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
01146 png_ptr->num_palette);
01147 png_warning(png_ptr, "Invalid number of histogram entries specified");
01148 return;
01149 }
01150
01151 png_write_chunk_start(png_ptr, (png_bytep)png_hIST, (png_uint_32)(num_hist * 2));
01152 for (i = 0; i < num_hist; i++)
01153 {
01154 png_save_uint_16(buf, hist[i]);
01155 png_write_chunk_data(png_ptr, buf, (png_size_t)2);
01156 }
01157 png_write_chunk_end(png_ptr);
01158 }
01159 #endif
01160
01161 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
01162 defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173 png_size_t
01174 png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
01175 {
01176 png_size_t key_len;
01177 png_charp kp, dp;
01178 int kflag;
01179 int kwarn=0;
01180
01181 png_debug(1, "in png_check_keyword\n");
01182 *new_key = NULL;
01183
01184 if (key == NULL || (key_len = png_strlen(key)) == 0)
01185 {
01186 png_warning(png_ptr, "zero length keyword");
01187 return ((png_size_t)0);
01188 }
01189
01190 png_debug1(2, "Keyword to be checked is '%s'\n", key);
01191
01192 *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
01193 if (*new_key == NULL)
01194 {
01195 png_warning(png_ptr, "Out of memory while procesing keyword");
01196 return ((png_size_t)0);
01197 }
01198
01199
01200 for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
01201 {
01202 if (*kp < 0x20 || (*kp > 0x7E && (png_byte)*kp < 0xA1))
01203 {
01204 #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
01205 char msg[40];
01206
01207 sprintf(msg, "invalid keyword character 0x%02X", *kp);
01208 png_warning(png_ptr, msg);
01209 #else
01210 png_warning(png_ptr, "invalid character in keyword");
01211 #endif
01212 *dp = ' ';
01213 }
01214 else
01215 {
01216 *dp = *kp;
01217 }
01218 }
01219 *dp = '\0';
01220
01221
01222 kp = *new_key + key_len - 1;
01223 if (*kp == ' ')
01224 {
01225 png_warning(png_ptr, "trailing spaces removed from keyword");
01226
01227 while (*kp == ' ')
01228 {
01229 *(kp--) = '\0';
01230 key_len--;
01231 }
01232 }
01233
01234
01235 kp = *new_key;
01236 if (*kp == ' ')
01237 {
01238 png_warning(png_ptr, "leading spaces removed from keyword");
01239
01240 while (*kp == ' ')
01241 {
01242 kp++;
01243 key_len--;
01244 }
01245 }
01246
01247 png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);
01248
01249
01250 for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
01251 {
01252 if (*kp == ' ' && kflag == 0)
01253 {
01254 *(dp++) = *kp;
01255 kflag = 1;
01256 }
01257 else if (*kp == ' ')
01258 {
01259 key_len--;
01260 kwarn=1;
01261 }
01262 else
01263 {
01264 *(dp++) = *kp;
01265 kflag = 0;
01266 }
01267 }
01268 *dp = '\0';
01269 if(kwarn)
01270 png_warning(png_ptr, "extra interior spaces removed from keyword");
01271
01272 if (key_len == 0)
01273 {
01274 png_free(png_ptr, *new_key);
01275 *new_key=NULL;
01276 png_warning(png_ptr, "Zero length keyword");
01277 }
01278
01279 if (key_len > 79)
01280 {
01281 png_warning(png_ptr, "keyword length must be 1 - 79 characters");
01282 new_key[79] = '\0';
01283 key_len = 79;
01284 }
01285
01286 return (key_len);
01287 }
01288 #endif
01289
01290 #if defined(PNG_WRITE_tEXt_SUPPORTED)
01291
01292 void
01293 png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
01294 png_size_t text_len)
01295 {
01296 #ifdef PNG_USE_LOCAL_ARRAYS
01297 PNG_tEXt;
01298 #endif
01299 png_size_t key_len;
01300 png_charp new_key;
01301
01302 png_debug(1, "in png_write_tEXt\n");
01303 if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
01304 {
01305 png_warning(png_ptr, "Empty keyword in tEXt chunk");
01306 return;
01307 }
01308
01309 if (text == NULL || *text == '\0')
01310 text_len = 0;
01311 else
01312 text_len = png_strlen(text);
01313
01314
01315 png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
01316
01317
01318
01319
01320
01321
01322 png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
01323 if (text_len)
01324 png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
01325
01326 png_write_chunk_end(png_ptr);
01327 png_free(png_ptr, new_key);
01328 }
01329 #endif
01330
01331 #if defined(PNG_WRITE_zTXt_SUPPORTED)
01332
01333 void
01334 png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
01335 png_size_t text_len, int compression)
01336 {
01337 #ifdef PNG_USE_LOCAL_ARRAYS
01338 PNG_zTXt;
01339 #endif
01340 png_size_t key_len;
01341 char buf[1];
01342 png_charp new_key;
01343 compression_state comp;
01344
01345 png_debug(1, "in png_write_zTXt\n");
01346
01347 if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
01348 {
01349 png_warning(png_ptr, "Empty keyword in zTXt chunk");
01350 return;
01351 }
01352
01353 if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
01354 {
01355 png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
01356 png_free(png_ptr, new_key);
01357 return;
01358 }
01359
01360 text_len = png_strlen(text);
01361
01362 png_free(png_ptr, new_key);
01363
01364
01365 text_len = png_text_compress(png_ptr, text, text_len, compression,
01366 &comp);
01367
01368
01369 png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, (png_uint_32)
01370 (key_len+text_len+2));
01371
01372 png_write_chunk_data(png_ptr, (png_bytep)key, key_len + 1);
01373 buf[0] = (png_byte)compression;
01374
01375 png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
01376
01377 png_write_compressed_data_out(png_ptr, &comp);
01378
01379
01380 png_write_chunk_end(png_ptr);
01381 }
01382 #endif
01383
01384 #if defined(PNG_WRITE_iTXt_SUPPORTED)
01385
01386 void
01387 png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
01388 png_charp lang, png_charp lang_key, png_charp text)
01389 {
01390 #ifdef PNG_USE_LOCAL_ARRAYS
01391 PNG_iTXt;
01392 #endif
01393 png_size_t lang_len, key_len, lang_key_len, text_len;
01394 png_charp new_lang, new_key;
01395 png_byte cbuf[2];
01396 compression_state comp;
01397
01398 png_debug(1, "in png_write_iTXt\n");
01399
01400 if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
01401 {
01402 png_warning(png_ptr, "Empty keyword in iTXt chunk");
01403 return;
01404 }
01405 if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
01406 {
01407 png_warning(png_ptr, "Empty language field in iTXt chunk");
01408 new_lang = NULL;
01409 lang_len = 0;
01410 }
01411
01412 if (lang_key == NULL)
01413 lang_key_len = 0;
01414 else
01415 lang_key_len = png_strlen(lang_key);
01416
01417 if (text == NULL)
01418 text_len = 0;
01419 else
01420 text_len = png_strlen(text);
01421
01422
01423 text_len = png_text_compress(png_ptr, text, text_len, compression-2,
01424 &comp);
01425
01426
01427
01428
01429
01430 png_write_chunk_start(png_ptr, (png_bytep)png_iTXt,
01431 (png_uint_32)(
01432 5
01433 + key_len
01434 + lang_len
01435 + lang_key_len
01436 + text_len));
01437
01438
01439
01440
01441
01442
01443
01444 png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
01445
01446
01447 if (compression == PNG_ITXT_COMPRESSION_NONE || \
01448 compression == PNG_TEXT_COMPRESSION_NONE)
01449 cbuf[0] = 0;
01450 else
01451 cbuf[0] = 1;
01452
01453 cbuf[1] = 0;
01454 png_write_chunk_data(png_ptr, cbuf, 2);
01455
01456 cbuf[0] = 0;
01457 png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), lang_len + 1);
01458 png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), lang_key_len + 1);
01459 png_write_compressed_data_out(png_ptr, &comp);
01460
01461 png_write_chunk_end(png_ptr);
01462 png_free(png_ptr, new_key);
01463 if (new_lang)
01464 png_free(png_ptr, new_lang);
01465 }
01466 #endif
01467
01468 #if defined(PNG_WRITE_oFFs_SUPPORTED)
01469
01470 void
01471 png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
01472 int unit_type)
01473 {
01474 #ifdef PNG_USE_LOCAL_ARRAYS
01475 PNG_oFFs;
01476 #endif
01477 png_byte buf[9];
01478
01479 png_debug(1, "in png_write_oFFs\n");
01480 if (unit_type >= PNG_OFFSET_LAST)
01481 png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
01482
01483 png_save_int_32(buf, x_offset);
01484 png_save_int_32(buf + 4, y_offset);
01485 buf[8] = (png_byte)unit_type;
01486
01487 png_write_chunk(png_ptr, (png_bytep)png_oFFs, buf, (png_size_t)9);
01488 }
01489 #endif
01490
01491 #if defined(PNG_WRITE_pCAL_SUPPORTED)
01492
01493 void
01494 png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
01495 png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
01496 {
01497 #ifdef PNG_USE_LOCAL_ARRAYS
01498 PNG_pCAL;
01499 #endif
01500 png_size_t purpose_len, units_len, total_len;
01501 png_uint_32p params_len;
01502 png_byte buf[10];
01503 png_charp new_purpose;
01504 int i;
01505
01506 png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
01507 if (type >= PNG_EQUATION_LAST)
01508 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
01509
01510 purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
01511 png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len);
01512 units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
01513 png_debug1(3, "pCAL units length = %d\n", (int)units_len);
01514 total_len = purpose_len + units_len + 10;
01515
01516 params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
01517 *png_sizeof(png_uint_32)));
01518
01519
01520
01521 for (i = 0; i < nparams; i++)
01522 {
01523 params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
01524 png_debug2(3, "pCAL parameter %d length = %lu\n", i, params_len[i]);
01525 total_len += (png_size_t)params_len[i];
01526 }
01527
01528 png_debug1(3, "pCAL total length = %d\n", (int)total_len);
01529 png_write_chunk_start(png_ptr, (png_bytep)png_pCAL, (png_uint_32)total_len);
01530 png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
01531 png_save_int_32(buf, X0);
01532 png_save_int_32(buf + 4, X1);
01533 buf[8] = (png_byte)type;
01534 buf[9] = (png_byte)nparams;
01535 png_write_chunk_data(png_ptr, buf, (png_size_t)10);
01536 png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
01537
01538 png_free(png_ptr, new_purpose);
01539
01540 for (i = 0; i < nparams; i++)
01541 {
01542 png_write_chunk_data(png_ptr, (png_bytep)params[i],
01543 (png_size_t)params_len[i]);
01544 }
01545
01546 png_free(png_ptr, params_len);
01547 png_write_chunk_end(png_ptr);
01548 }
01549 #endif
01550
01551 #if defined(PNG_WRITE_sCAL_SUPPORTED)
01552
01553 #if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
01554 void
01555 png_write_sCAL(png_structp png_ptr, int unit, double width,double height)
01556 {
01557 #ifdef PNG_USE_LOCAL_ARRAYS
01558 PNG_sCAL;
01559 #endif
01560 png_size_t total_len;
01561 char wbuf[32], hbuf[32];
01562 png_byte bunit = unit;
01563
01564 png_debug(1, "in png_write_sCAL\n");
01565
01566 #if defined(_WIN32_WCE)
01567
01568 {
01569 wchar_t wc_buf[32];
01570 swprintf(wc_buf, TEXT("%12.12e"), width);
01571 WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, wbuf, 32, NULL, NULL);
01572 swprintf(wc_buf, TEXT("%12.12e"), height);
01573 WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, hbuf, 32, NULL, NULL);
01574 }
01575 #else
01576 sprintf(wbuf, "%12.12e", width);
01577 sprintf(hbuf, "%12.12e", height);
01578 #endif
01579 total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
01580
01581 png_debug1(3, "sCAL total length = %d\n", (int)total_len);
01582 png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
01583 png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1);
01584 png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
01585 png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
01586
01587 png_write_chunk_end(png_ptr);
01588 }
01589 #else
01590 #ifdef PNG_FIXED_POINT_SUPPORTED
01591 void
01592 png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
01593 png_charp height)
01594 {
01595 #ifdef PNG_USE_LOCAL_ARRAYS
01596 PNG_sCAL;
01597 #endif
01598 png_size_t total_len;
01599 char wbuf[32], hbuf[32];
01600 png_byte bunit = unit;
01601
01602 png_debug(1, "in png_write_sCAL_s\n");
01603
01604 png_strcpy(wbuf,(const char *)width);
01605 png_strcpy(hbuf,(const char *)height);
01606 total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf);
01607
01608 png_debug1(3, "sCAL total length = %d\n", total_len);
01609 png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len);
01610 png_write_chunk_data(png_ptr, (png_bytep)&bunit, 1);
01611 png_write_chunk_data(png_ptr, (png_bytep)wbuf, png_strlen(wbuf)+1);
01612 png_write_chunk_data(png_ptr, (png_bytep)hbuf, png_strlen(hbuf));
01613
01614 png_write_chunk_end(png_ptr);
01615 }
01616 #endif
01617 #endif
01618 #endif
01619
01620 #if defined(PNG_WRITE_pHYs_SUPPORTED)
01621
01622 void
01623 png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
01624 png_uint_32 y_pixels_per_unit,
01625 int unit_type)
01626 {
01627 #ifdef PNG_USE_LOCAL_ARRAYS
01628 PNG_pHYs;
01629 #endif
01630 png_byte buf[9];
01631
01632 png_debug(1, "in png_write_pHYs\n");
01633 if (unit_type >= PNG_RESOLUTION_LAST)
01634 png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
01635
01636 png_save_uint_32(buf, x_pixels_per_unit);
01637 png_save_uint_32(buf + 4, y_pixels_per_unit);
01638 buf[8] = (png_byte)unit_type;
01639
01640 png_write_chunk(png_ptr, (png_bytep)png_pHYs, buf, (png_size_t)9);
01641 }
01642 #endif
01643
01644 #if defined(PNG_WRITE_tIME_SUPPORTED)
01645
01646
01647
01648 void
01649 png_write_tIME(png_structp png_ptr, png_timep mod_time)
01650 {
01651 #ifdef PNG_USE_LOCAL_ARRAYS
01652 PNG_tIME;
01653 #endif
01654 png_byte buf[7];
01655
01656 png_debug(1, "in png_write_tIME\n");
01657 if (mod_time->month > 12 || mod_time->month < 1 ||
01658 mod_time->day > 31 || mod_time->day < 1 ||
01659 mod_time->hour > 23 || mod_time->second > 60)
01660 {
01661 png_warning(png_ptr, "Invalid time specified for tIME chunk");
01662 return;
01663 }
01664
01665 png_save_uint_16(buf, mod_time->year);
01666 buf[2] = mod_time->month;
01667 buf[3] = mod_time->day;
01668 buf[4] = mod_time->hour;
01669 buf[5] = mod_time->minute;
01670 buf[6] = mod_time->second;
01671
01672 png_write_chunk(png_ptr, (png_bytep)png_tIME, buf, (png_size_t)7);
01673 }
01674 #endif
01675
01676
01677 void
01678 png_write_start_row(png_structp png_ptr)
01679 {
01680 #ifdef PNG_USE_LOCAL_ARRAYS
01681
01682
01683
01684 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
01685
01686
01687 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
01688
01689
01690 int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
01691
01692
01693 int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
01694 #endif
01695
01696 png_size_t buf_size;
01697
01698 png_debug(1, "in png_write_start_row\n");
01699 buf_size = (png_size_t)(PNG_ROWBYTES(
01700 png_ptr->usr_channels*png_ptr->usr_bit_depth,png_ptr->width)+1);
01701
01702
01703 png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
01704 png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
01705
01706
01707 if (png_ptr->do_filter & PNG_FILTER_SUB)
01708 {
01709 png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
01710 (png_ptr->rowbytes + 1));
01711 png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
01712 }
01713
01714
01715 if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
01716 {
01717
01718 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
01719 png_memset(png_ptr->prev_row, 0, buf_size);
01720
01721 if (png_ptr->do_filter & PNG_FILTER_UP)
01722 {
01723 png_ptr->up_row = (png_bytep )png_malloc(png_ptr,
01724 (png_ptr->rowbytes + 1));
01725 png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
01726 }
01727
01728 if (png_ptr->do_filter & PNG_FILTER_AVG)
01729 {
01730 png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
01731 (png_ptr->rowbytes + 1));
01732 png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
01733 }
01734
01735 if (png_ptr->do_filter & PNG_FILTER_PAETH)
01736 {
01737 png_ptr->paeth_row = (png_bytep )png_malloc(png_ptr,
01738 (png_ptr->rowbytes + 1));
01739 png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
01740 }
01741 }
01742
01743 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
01744
01745 if (png_ptr->interlaced)
01746 {
01747 if (!(png_ptr->transformations & PNG_INTERLACE))
01748 {
01749 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
01750 png_pass_ystart[0]) / png_pass_yinc[0];
01751 png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
01752 png_pass_start[0]) / png_pass_inc[0];
01753 }
01754 else
01755 {
01756 png_ptr->num_rows = png_ptr->height;
01757 png_ptr->usr_width = png_ptr->width;
01758 }
01759 }
01760 else
01761 #endif
01762 {
01763 png_ptr->num_rows = png_ptr->height;
01764 png_ptr->usr_width = png_ptr->width;
01765 }
01766 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
01767 png_ptr->zstream.next_out = png_ptr->zbuf;
01768 }
01769
01770
01771 void
01772 png_write_finish_row(png_structp png_ptr)
01773 {
01774 #ifdef PNG_USE_LOCAL_ARRAYS
01775
01776
01777
01778 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
01779
01780
01781 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
01782
01783
01784 int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
01785
01786
01787 int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
01788 #endif
01789
01790 int ret;
01791
01792 png_debug(1, "in png_write_finish_row\n");
01793
01794 png_ptr->row_number++;
01795
01796
01797 if (png_ptr->row_number < png_ptr->num_rows)
01798 return;
01799
01800 #ifdef PNG_WRITE_INTERLACING_SUPPORTED
01801
01802 if (png_ptr->interlaced)
01803 {
01804 png_ptr->row_number = 0;
01805 if (png_ptr->transformations & PNG_INTERLACE)
01806 {
01807 png_ptr->pass++;
01808 }
01809 else
01810 {
01811
01812 do
01813 {
01814 png_ptr->pass++;
01815 if (png_ptr->pass >= 7)
01816 break;
01817 png_ptr->usr_width = (png_ptr->width +
01818 png_pass_inc[png_ptr->pass] - 1 -
01819 png_pass_start[png_ptr->pass]) /
01820 png_pass_inc[png_ptr->pass];
01821 png_ptr->num_rows = (png_ptr->height +
01822 png_pass_yinc[png_ptr->pass] - 1 -
01823 png_pass_ystart[png_ptr->pass]) /
01824 png_pass_yinc[png_ptr->pass];
01825 if (png_ptr->transformations & PNG_INTERLACE)
01826 break;
01827 } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
01828
01829 }
01830
01831
01832 if (png_ptr->pass < 7)
01833 {
01834 if (png_ptr->prev_row != NULL)
01835 png_memset(png_ptr->prev_row, 0,
01836 (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*
01837 png_ptr->usr_bit_depth,png_ptr->width))+1);
01838 return;
01839 }
01840 }
01841 #endif
01842
01843
01844
01845 do
01846 {
01847
01848 ret = deflate(&png_ptr->zstream, Z_FINISH);
01849
01850 if (ret == Z_OK)
01851 {
01852
01853 if (!(png_ptr->zstream.avail_out))
01854 {
01855 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
01856 png_ptr->zstream.next_out = png_ptr->zbuf;
01857 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
01858 }
01859 }
01860 else if (ret != Z_STREAM_END)
01861 {
01862 if (png_ptr->zstream.msg != NULL)
01863 png_error(png_ptr, png_ptr->zstream.msg);
01864 else
01865 png_error(png_ptr, "zlib error");
01866 }
01867 } while (ret != Z_STREAM_END);
01868
01869
01870 if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
01871 {
01872 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
01873 png_ptr->zstream.avail_out);
01874 }
01875
01876 deflateReset(&png_ptr->zstream);
01877 png_ptr->zstream.data_type = Z_BINARY;
01878 }
01879
01880 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
01881
01882
01883
01884
01885
01886
01887
01888 void
01889 png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
01890 {
01891 #ifdef PNG_USE_LOCAL_ARRAYS
01892
01893
01894
01895 int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
01896
01897
01898 int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
01899 #endif
01900
01901 png_debug(1, "in png_do_write_interlace\n");
01902
01903 #if defined(PNG_USELESS_TESTS_SUPPORTED)
01904 if (row != NULL && row_info != NULL && pass < 6)
01905 #else
01906 if (pass < 6)
01907 #endif
01908 {
01909
01910 switch (row_info->pixel_depth)
01911 {
01912 case 1:
01913 {
01914 png_bytep sp;
01915 png_bytep dp;
01916 int shift;
01917 int d;
01918 int value;
01919 png_uint_32 i;
01920 png_uint_32 row_width = row_info->width;
01921
01922 dp = row;
01923 d = 0;
01924 shift = 7;
01925 for (i = png_pass_start[pass]; i < row_width;
01926 i += png_pass_inc[pass])
01927 {
01928 sp = row + (png_size_t)(i >> 3);
01929 value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
01930 d |= (value << shift);
01931
01932 if (shift == 0)
01933 {
01934 shift = 7;
01935 *dp++ = (png_byte)d;
01936 d = 0;
01937 }
01938 else
01939 shift--;
01940
01941 }
01942 if (shift != 7)
01943 *dp = (png_byte)d;
01944 break;
01945 }
01946 case 2:
01947 {
01948 png_bytep sp;
01949 png_bytep dp;
01950 int shift;
01951 int d;
01952 int value;
01953 png_uint_32 i;
01954 png_uint_32 row_width = row_info->width;
01955
01956 dp = row;
01957 shift = 6;
01958 d = 0;
01959 for (i = png_pass_start[pass]; i < row_width;
01960 i += png_pass_inc[pass])
01961 {
01962 sp = row + (png_size_t)(i >> 2);
01963 value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
01964 d |= (value << shift);
01965
01966 if (shift == 0)
01967 {
01968 shift = 6;
01969 *dp++ = (png_byte)d;
01970 d = 0;
01971 }
01972 else
01973 shift -= 2;
01974 }
01975 if (shift != 6)
01976 *dp = (png_byte)d;
01977 break;
01978 }
01979 case 4:
01980 {
01981 png_bytep sp;
01982 png_bytep dp;
01983 int shift;
01984 int d;
01985 int value;
01986 png_uint_32 i;
01987 png_uint_32 row_width = row_info->width;
01988
01989 dp = row;
01990 shift = 4;
01991 d = 0;
01992 for (i = png_pass_start[pass]; i < row_width;
01993 i += png_pass_inc[pass])
01994 {
01995 sp = row + (png_size_t)(i >> 1);
01996 value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
01997 d |= (value << shift);
01998
01999 if (shift == 0)
02000 {
02001 shift = 4;
02002 *dp++ = (png_byte)d;
02003 d = 0;
02004 }
02005 else
02006 shift -= 4;
02007 }
02008 if (shift != 4)
02009 *dp = (png_byte)d;
02010 break;
02011 }
02012 default:
02013 {
02014 png_bytep sp;
02015 png_bytep dp;
02016 png_uint_32 i;
02017 png_uint_32 row_width = row_info->width;
02018 png_size_t pixel_bytes;
02019
02020
02021 dp = row;
02022
02023 pixel_bytes = (row_info->pixel_depth >> 3);
02024
02025
02026 for (i = png_pass_start[pass]; i < row_width;
02027 i += png_pass_inc[pass])
02028 {
02029
02030 sp = row + (png_size_t)i * pixel_bytes;
02031
02032 if (dp != sp)
02033 png_memcpy(dp, sp, pixel_bytes);
02034
02035 dp += pixel_bytes;
02036 }
02037 break;
02038 }
02039 }
02040
02041 row_info->width = (row_info->width +
02042 png_pass_inc[pass] - 1 -
02043 png_pass_start[pass]) /
02044 png_pass_inc[pass];
02045 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
02046 row_info->width);
02047 }
02048 }
02049 #endif
02050
02051
02052
02053
02054
02055 #define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
02056 #define PNG_HISHIFT 10
02057 #define PNG_LOMASK ((png_uint_32)0xffffL)
02058 #define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
02059 void
02060 png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
02061 {
02062 png_bytep prev_row, best_row, row_buf;
02063 png_uint_32 mins, bpp;
02064 png_byte filter_to_do = png_ptr->do_filter;
02065 png_uint_32 row_bytes = row_info->rowbytes;
02066 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
02067 int num_p_filters = (int)png_ptr->num_prev_filters;
02068 #endif
02069
02070 png_debug(1, "in png_write_find_filter\n");
02071
02072 bpp = (row_info->pixel_depth + 7) >> 3;
02073
02074 prev_row = png_ptr->prev_row;
02075 best_row = row_buf = png_ptr->row_buf;
02076 mins = PNG_MAXSUM;
02077
02078
02079
02080
02081
02082
02083
02084
02085
02086
02087
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101
02102
02103 if ((filter_to_do & PNG_FILTER_NONE) &&
02104 filter_to_do != PNG_FILTER_NONE)
02105 {
02106 png_bytep rp;
02107 png_uint_32 sum = 0;
02108 png_uint_32 i;
02109 int v;
02110
02111 for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
02112 {
02113 v = *rp;
02114 sum += (v < 128) ? v : 256 - v;
02115 }
02116
02117 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
02118 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
02119 {
02120 png_uint_32 sumhi, sumlo;
02121 int j;
02122 sumlo = sum & PNG_LOMASK;
02123 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
02124
02125
02126 for (j = 0; j < num_p_filters; j++)
02127 {
02128 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
02129 {
02130 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
02131 PNG_WEIGHT_SHIFT;
02132 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
02133 PNG_WEIGHT_SHIFT;
02134 }
02135 }
02136
02137
02138
02139
02140
02141 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
02142 PNG_COST_SHIFT;
02143 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
02144 PNG_COST_SHIFT;
02145
02146 if (sumhi > PNG_HIMASK)
02147 sum = PNG_MAXSUM;
02148 else
02149 sum = (sumhi << PNG_HISHIFT) + sumlo;
02150 }
02151 #endif
02152 mins = sum;
02153 }
02154
02155
02156 if (filter_to_do == PNG_FILTER_SUB)
02157
02158 {
02159 png_bytep rp, lp, dp;
02160 png_uint_32 i;
02161 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
02162 i++, rp++, dp++)
02163 {
02164 *dp = *rp;
02165 }
02166 for (lp = row_buf + 1; i < row_bytes;
02167 i++, rp++, lp++, dp++)
02168 {
02169 *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
02170 }
02171 best_row = png_ptr->sub_row;
02172 }
02173
02174 else if (filter_to_do & PNG_FILTER_SUB)
02175 {
02176 png_bytep rp, dp, lp;
02177 png_uint_32 sum = 0, lmins = mins;
02178 png_uint_32 i;
02179 int v;
02180
02181 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
02182
02183
02184
02185
02186 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
02187 {
02188 int j;
02189 png_uint_32 lmhi, lmlo;
02190 lmlo = lmins & PNG_LOMASK;
02191 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
02192
02193 for (j = 0; j < num_p_filters; j++)
02194 {
02195 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
02196 {
02197 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
02198 PNG_WEIGHT_SHIFT;
02199 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
02200 PNG_WEIGHT_SHIFT;
02201 }
02202 }
02203
02204 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
02205 PNG_COST_SHIFT;
02206 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
02207 PNG_COST_SHIFT;
02208
02209 if (lmhi > PNG_HIMASK)
02210 lmins = PNG_MAXSUM;
02211 else
02212 lmins = (lmhi << PNG_HISHIFT) + lmlo;
02213 }
02214 #endif
02215
02216 for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
02217 i++, rp++, dp++)
02218 {
02219 v = *dp = *rp;
02220
02221 sum += (v < 128) ? v : 256 - v;
02222 }
02223 for (lp = row_buf + 1; i < row_bytes;
02224 i++, rp++, lp++, dp++)
02225 {
02226 v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
02227
02228 sum += (v < 128) ? v : 256 - v;
02229
02230 if (sum > lmins)
02231 break;
02232 }
02233
02234 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
02235 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
02236 {
02237 int j;
02238 png_uint_32 sumhi, sumlo;
02239 sumlo = sum & PNG_LOMASK;
02240 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
02241
02242 for (j = 0; j < num_p_filters; j++)
02243 {
02244 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
02245 {
02246 sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
02247 PNG_WEIGHT_SHIFT;
02248 sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
02249 PNG_WEIGHT_SHIFT;
02250 }
02251 }
02252
02253 sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
02254 PNG_COST_SHIFT;
02255 sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
02256 PNG_COST_SHIFT;
02257
02258 if (sumhi > PNG_HIMASK)
02259 sum = PNG_MAXSUM;
02260 else
02261 sum = (sumhi << PNG_HISHIFT) + sumlo;
02262 }
02263 #endif
02264
02265 if (sum < mins)
02266 {
02267 mins = sum;
02268 best_row = png_ptr->sub_row;
02269 }
02270 }
02271
02272
02273 if (filter_to_do == PNG_FILTER_UP)
02274 {
02275 png_bytep rp, dp, pp;
02276 png_uint_32 i;
02277
02278 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
02279 pp = prev_row + 1; i < row_bytes;
02280 i++, rp++, pp++, dp++)
02281 {
02282 *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
02283 }
02284 best_row = png_ptr->up_row;
02285 }
02286
02287 else if (filter_to_do & PNG_FILTER_UP)
02288 {
02289 png_bytep rp, dp, pp;
02290 png_uint_32 sum = 0, lmins = mins;
02291 png_uint_32 i;
02292 int v;
02293
02294
02295 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
02296 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
02297 {
02298 int j;
02299 png_uint_32 lmhi, lmlo;
02300 lmlo = lmins & PNG_LOMASK;
02301 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
02302
02303 for (j = 0; j < num_p_filters; j++)
02304 {
02305 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
02306 {
02307 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
02308 PNG_WEIGHT_SHIFT;
02309 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
02310 PNG_WEIGHT_SHIFT;
02311 }
02312 }
02313
02314 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
02315 PNG_COST_SHIFT;
02316 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
02317 PNG_COST_SHIFT;
02318
02319 if (lmhi > PNG_HIMASK)
02320 lmins = PNG_MAXSUM;
02321 else
02322 lmins = (lmhi << PNG_HISHIFT) + lmlo;
02323 }
02324 #endif
02325
02326 for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
02327 pp = prev_row + 1; i < row_bytes; i++)
02328 {
02329 v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
02330
02331 sum += (v < 128) ? v : 256 - v;
02332
02333 if (sum > lmins)
02334 break;
02335 }
02336
02337 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
02338 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
02339 {
02340 int j;
02341 png_uint_32 sumhi, sumlo;
02342 sumlo = sum & PNG_LOMASK;
02343 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
02344
02345 for (j = 0; j < num_p_filters; j++)
02346 {
02347 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
02348 {
02349 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
02350 PNG_WEIGHT_SHIFT;
02351 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
02352 PNG_WEIGHT_SHIFT;
02353 }
02354 }
02355
02356 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
02357 PNG_COST_SHIFT;
02358 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
02359 PNG_COST_SHIFT;
02360
02361 if (sumhi > PNG_HIMASK)
02362 sum = PNG_MAXSUM;
02363 else
02364 sum = (sumhi << PNG_HISHIFT) + sumlo;
02365 }
02366 #endif
02367
02368 if (sum < mins)
02369 {
02370 mins = sum;
02371 best_row = png_ptr->up_row;
02372 }
02373 }
02374
02375
02376 if (filter_to_do == PNG_FILTER_AVG)
02377 {
02378 png_bytep rp, dp, pp, lp;
02379 png_uint_32 i;
02380 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
02381 pp = prev_row + 1; i < bpp; i++)
02382 {
02383 *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
02384 }
02385 for (lp = row_buf + 1; i < row_bytes; i++)
02386 {
02387 *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
02388 & 0xff);
02389 }
02390 best_row = png_ptr->avg_row;
02391 }
02392
02393 else if (filter_to_do & PNG_FILTER_AVG)
02394 {
02395 png_bytep rp, dp, pp, lp;
02396 png_uint_32 sum = 0, lmins = mins;
02397 png_uint_32 i;
02398 int v;
02399
02400 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
02401 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
02402 {
02403 int j;
02404 png_uint_32 lmhi, lmlo;
02405 lmlo = lmins & PNG_LOMASK;
02406 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
02407
02408 for (j = 0; j < num_p_filters; j++)
02409 {
02410 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
02411 {
02412 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
02413 PNG_WEIGHT_SHIFT;
02414 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
02415 PNG_WEIGHT_SHIFT;
02416 }
02417 }
02418
02419 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
02420 PNG_COST_SHIFT;
02421 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
02422 PNG_COST_SHIFT;
02423
02424 if (lmhi > PNG_HIMASK)
02425 lmins = PNG_MAXSUM;
02426 else
02427 lmins = (lmhi << PNG_HISHIFT) + lmlo;
02428 }
02429 #endif
02430
02431 for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
02432 pp = prev_row + 1; i < bpp; i++)
02433 {
02434 v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
02435
02436 sum += (v < 128) ? v : 256 - v;
02437 }
02438 for (lp = row_buf + 1; i < row_bytes; i++)
02439 {
02440 v = *dp++ =
02441 (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
02442
02443 sum += (v < 128) ? v : 256 - v;
02444
02445 if (sum > lmins)
02446 break;
02447 }
02448
02449 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
02450 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
02451 {
02452 int j;
02453 png_uint_32 sumhi, sumlo;
02454 sumlo = sum & PNG_LOMASK;
02455 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
02456
02457 for (j = 0; j < num_p_filters; j++)
02458 {
02459 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
02460 {
02461 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
02462 PNG_WEIGHT_SHIFT;
02463 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
02464 PNG_WEIGHT_SHIFT;
02465 }
02466 }
02467
02468 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
02469 PNG_COST_SHIFT;
02470 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
02471 PNG_COST_SHIFT;
02472
02473 if (sumhi > PNG_HIMASK)
02474 sum = PNG_MAXSUM;
02475 else
02476 sum = (sumhi << PNG_HISHIFT) + sumlo;
02477 }
02478 #endif
02479
02480 if (sum < mins)
02481 {
02482 mins = sum;
02483 best_row = png_ptr->avg_row;
02484 }
02485 }
02486
02487
02488 if (filter_to_do == PNG_FILTER_PAETH)
02489 {
02490 png_bytep rp, dp, pp, cp, lp;
02491 png_uint_32 i;
02492 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
02493 pp = prev_row + 1; i < bpp; i++)
02494 {
02495 *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
02496 }
02497
02498 for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
02499 {
02500 int a, b, c, pa, pb, pc, p;
02501
02502 b = *pp++;
02503 c = *cp++;
02504 a = *lp++;
02505
02506 p = b - c;
02507 pc = a - c;
02508
02509 #ifdef PNG_USE_ABS
02510 pa = abs(p);
02511 pb = abs(pc);
02512 pc = abs(p + pc);
02513 #else
02514 pa = p < 0 ? -p : p;
02515 pb = pc < 0 ? -pc : pc;
02516 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
02517 #endif
02518
02519 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
02520
02521 *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
02522 }
02523 best_row = png_ptr->paeth_row;
02524 }
02525
02526 else if (filter_to_do & PNG_FILTER_PAETH)
02527 {
02528 png_bytep rp, dp, pp, cp, lp;
02529 png_uint_32 sum = 0, lmins = mins;
02530 png_uint_32 i;
02531 int v;
02532
02533 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
02534 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
02535 {
02536 int j;
02537 png_uint_32 lmhi, lmlo;
02538 lmlo = lmins & PNG_LOMASK;
02539 lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
02540
02541 for (j = 0; j < num_p_filters; j++)
02542 {
02543 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
02544 {
02545 lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
02546 PNG_WEIGHT_SHIFT;
02547 lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
02548 PNG_WEIGHT_SHIFT;
02549 }
02550 }
02551
02552 lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
02553 PNG_COST_SHIFT;
02554 lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
02555 PNG_COST_SHIFT;
02556
02557 if (lmhi > PNG_HIMASK)
02558 lmins = PNG_MAXSUM;
02559 else
02560 lmins = (lmhi << PNG_HISHIFT) + lmlo;
02561 }
02562 #endif
02563
02564 for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
02565 pp = prev_row + 1; i < bpp; i++)
02566 {
02567 v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
02568
02569 sum += (v < 128) ? v : 256 - v;
02570 }
02571
02572 for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
02573 {
02574 int a, b, c, pa, pb, pc, p;
02575
02576 b = *pp++;
02577 c = *cp++;
02578 a = *lp++;
02579
02580 #ifndef PNG_SLOW_PAETH
02581 p = b - c;
02582 pc = a - c;
02583 #ifdef PNG_USE_ABS
02584 pa = abs(p);
02585 pb = abs(pc);
02586 pc = abs(p + pc);
02587 #else
02588 pa = p < 0 ? -p : p;
02589 pb = pc < 0 ? -pc : pc;
02590 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
02591 #endif
02592 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
02593 #else
02594 p = a + b - c;
02595 pa = abs(p - a);
02596 pb = abs(p - b);
02597 pc = abs(p - c);
02598 if (pa <= pb && pa <= pc)
02599 p = a;
02600 else if (pb <= pc)
02601 p = b;
02602 else
02603 p = c;
02604 #endif
02605
02606 v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
02607
02608 sum += (v < 128) ? v : 256 - v;
02609
02610 if (sum > lmins)
02611 break;
02612 }
02613
02614 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
02615 if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
02616 {
02617 int j;
02618 png_uint_32 sumhi, sumlo;
02619 sumlo = sum & PNG_LOMASK;
02620 sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
02621
02622 for (j = 0; j < num_p_filters; j++)
02623 {
02624 if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
02625 {
02626 sumlo = (sumlo * png_ptr->filter_weights[j]) >>
02627 PNG_WEIGHT_SHIFT;
02628 sumhi = (sumhi * png_ptr->filter_weights[j]) >>
02629 PNG_WEIGHT_SHIFT;
02630 }
02631 }
02632
02633 sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
02634 PNG_COST_SHIFT;
02635 sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
02636 PNG_COST_SHIFT;
02637
02638 if (sumhi > PNG_HIMASK)
02639 sum = PNG_MAXSUM;
02640 else
02641 sum = (sumhi << PNG_HISHIFT) + sumlo;
02642 }
02643 #endif
02644
02645 if (sum < mins)
02646 {
02647 best_row = png_ptr->paeth_row;
02648 }
02649 }
02650
02651
02652
02653 png_write_filtered_row(png_ptr, best_row);
02654
02655 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
02656
02657 if (png_ptr->num_prev_filters > 0)
02658 {
02659 int j;
02660 for (j = 1; j < num_p_filters; j++)
02661 {
02662 png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
02663 }
02664 png_ptr->prev_filters[j] = best_row[0];
02665 }
02666 #endif
02667 }
02668
02669
02670
02671 void
02672 png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
02673 {
02674 png_debug(1, "in png_write_filtered_row\n");
02675 png_debug1(2, "filter = %d\n", filtered_row[0]);
02676
02677
02678 png_ptr->zstream.next_in = filtered_row;
02679 png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
02680
02681 do
02682 {
02683 int ret;
02684
02685
02686 ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
02687
02688 if (ret != Z_OK)
02689 {
02690 if (png_ptr->zstream.msg != NULL)
02691 png_error(png_ptr, png_ptr->zstream.msg);
02692 else
02693 png_error(png_ptr, "zlib error");
02694 }
02695
02696
02697 if (!(png_ptr->zstream.avail_out))
02698 {
02699
02700 png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
02701 png_ptr->zstream.next_out = png_ptr->zbuf;
02702 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
02703 }
02704
02705 } while (png_ptr->zstream.avail_in);
02706
02707
02708 if (png_ptr->prev_row != NULL)
02709 {
02710 png_bytep tptr;
02711
02712 tptr = png_ptr->prev_row;
02713 png_ptr->prev_row = png_ptr->row_buf;
02714 png_ptr->row_buf = tptr;
02715 }
02716
02717
02718 png_write_finish_row(png_ptr);
02719
02720 #if defined(PNG_WRITE_FLUSH_SUPPORTED)
02721 png_ptr->flush_rows++;
02722
02723 if (png_ptr->flush_dist > 0 &&
02724 png_ptr->flush_rows >= png_ptr->flush_dist)
02725 {
02726 png_write_flush(png_ptr);
02727 }
02728 #endif
02729 }
02730 #endif