Back to index

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