apps/png/libpng/pngwutil.c

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

Generated on Fri Nov 28 00:06:22 2008 for elphel by  doxygen 1.5.1