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


openhrp3
Author(s): AIST, General Robotix Inc., Nakamura Lab of Dept. of Mechano Informatics at University of Tokyo
autogenerated on Sun Apr 2 2017 03:43:56