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)  

pngwutil.c

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