pngwrite.c
Go to the documentation of this file.
00001 
00002 /* pngwrite.c - general routines to write a PNG file
00003  *
00004  * Last changed in libpng 1.2.31 [August 19, 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 /* get internal access to png.h */
00012 #define PNG_INTERNAL
00013 #include "png.h"
00014 #ifdef PNG_WRITE_SUPPORTED
00015 
00016 /* Writes all the PNG information.  This is the suggested way to use the
00017  * library.  If you have a new chunk to add, make a function to write it,
00018  * and put it in the correct location here.  If you want the chunk written
00019  * after the image data, put it in png_write_end().  I strongly encourage
00020  * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
00021  * the chunk, as that will keep the code from breaking if you want to just
00022  * write a plain PNG file.  If you have long comments, I suggest writing
00023  * them in png_write_end(), and compressing them.
00024  */
00025 void PNGAPI
00026 png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
00027 {
00028    png_debug(1, "in png_write_info_before_PLTE\n");
00029    if (png_ptr == NULL || info_ptr == NULL)
00030       return;
00031    if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
00032    {
00033    png_write_sig(png_ptr); /* write PNG signature */
00034 #if defined(PNG_MNG_FEATURES_SUPPORTED)
00035    if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted))
00036    {
00037       png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
00038       png_ptr->mng_features_permitted=0;
00039    }
00040 #endif
00041    /* write IHDR information. */
00042    png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
00043       info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
00044       info_ptr->filter_type,
00045 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
00046       info_ptr->interlace_type);
00047 #else
00048       0);
00049 #endif
00050    /* the rest of these check to see if the valid field has the appropriate
00051       flag set, and if it does, writes the chunk. */
00052 #if defined(PNG_WRITE_gAMA_SUPPORTED)
00053    if (info_ptr->valid & PNG_INFO_gAMA)
00054    {
00055 #  ifdef PNG_FLOATING_POINT_SUPPORTED
00056       png_write_gAMA(png_ptr, info_ptr->gamma);
00057 #else
00058 #ifdef PNG_FIXED_POINT_SUPPORTED
00059       png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma);
00060 #  endif
00061 #endif
00062    }
00063 #endif
00064 #if defined(PNG_WRITE_sRGB_SUPPORTED)
00065    if (info_ptr->valid & PNG_INFO_sRGB)
00066       png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
00067 #endif
00068 #if defined(PNG_WRITE_iCCP_SUPPORTED)
00069    if (info_ptr->valid & PNG_INFO_iCCP)
00070       png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
00071                      info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
00072 #endif
00073 #if defined(PNG_WRITE_sBIT_SUPPORTED)
00074    if (info_ptr->valid & PNG_INFO_sBIT)
00075       png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
00076 #endif
00077 #if defined(PNG_WRITE_cHRM_SUPPORTED)
00078    if (info_ptr->valid & PNG_INFO_cHRM)
00079    {
00080 #ifdef PNG_FLOATING_POINT_SUPPORTED
00081       png_write_cHRM(png_ptr,
00082          info_ptr->x_white, info_ptr->y_white,
00083          info_ptr->x_red, info_ptr->y_red,
00084          info_ptr->x_green, info_ptr->y_green,
00085          info_ptr->x_blue, info_ptr->y_blue);
00086 #else
00087 #  ifdef PNG_FIXED_POINT_SUPPORTED
00088       png_write_cHRM_fixed(png_ptr,
00089          info_ptr->int_x_white, info_ptr->int_y_white,
00090          info_ptr->int_x_red, info_ptr->int_y_red,
00091          info_ptr->int_x_green, info_ptr->int_y_green,
00092          info_ptr->int_x_blue, info_ptr->int_y_blue);
00093 #  endif
00094 #endif
00095    }
00096 #endif
00097 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
00098    if (info_ptr->unknown_chunks_num)
00099    {
00100        png_unknown_chunk *up;
00101 
00102        png_debug(5, "writing extra chunks\n");
00103 
00104        for (up = info_ptr->unknown_chunks;
00105             up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
00106             up++)
00107        {
00108          int keep=png_handle_as_unknown(png_ptr, up->name);
00109          if (keep != PNG_HANDLE_CHUNK_NEVER &&
00110             up->location && !(up->location & PNG_HAVE_PLTE) &&
00111             !(up->location & PNG_HAVE_IDAT) &&
00112             ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
00113             (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
00114          {
00115             if (up->size == 0)
00116                png_warning(png_ptr, "Writing zero-length unknown chunk");
00117             png_write_chunk(png_ptr, up->name, up->data, up->size);
00118          }
00119        }
00120    }
00121 #endif
00122       png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
00123    }
00124 }
00125 
00126 void PNGAPI
00127 png_write_info(png_structp png_ptr, png_infop info_ptr)
00128 {
00129 #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
00130    int i;
00131 #endif
00132 
00133    png_debug(1, "in png_write_info\n");
00134 
00135    if (png_ptr == NULL || info_ptr == NULL)
00136       return;
00137 
00138    png_write_info_before_PLTE(png_ptr, info_ptr);
00139 
00140    if (info_ptr->valid & PNG_INFO_PLTE)
00141       png_write_PLTE(png_ptr, info_ptr->palette,
00142          (png_uint_32)info_ptr->num_palette);
00143    else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
00144       png_error(png_ptr, "Valid palette required for paletted images");
00145 
00146 #if defined(PNG_WRITE_tRNS_SUPPORTED)
00147    if (info_ptr->valid & PNG_INFO_tRNS)
00148       {
00149 #if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
00150          /* invert the alpha channel (in tRNS) */
00151          if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
00152             info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
00153          {
00154             int j;
00155             for (j=0; j<(int)info_ptr->num_trans; j++)
00156                info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]);
00157          }
00158 #endif
00159       png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
00160          info_ptr->num_trans, info_ptr->color_type);
00161       }
00162 #endif
00163 #if defined(PNG_WRITE_bKGD_SUPPORTED)
00164    if (info_ptr->valid & PNG_INFO_bKGD)
00165       png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
00166 #endif
00167 #if defined(PNG_WRITE_hIST_SUPPORTED)
00168    if (info_ptr->valid & PNG_INFO_hIST)
00169       png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
00170 #endif
00171 #if defined(PNG_WRITE_oFFs_SUPPORTED)
00172    if (info_ptr->valid & PNG_INFO_oFFs)
00173       png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
00174          info_ptr->offset_unit_type);
00175 #endif
00176 #if defined(PNG_WRITE_pCAL_SUPPORTED)
00177    if (info_ptr->valid & PNG_INFO_pCAL)
00178       png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
00179          info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
00180          info_ptr->pcal_units, info_ptr->pcal_params);
00181 #endif
00182 #if defined(PNG_WRITE_sCAL_SUPPORTED)
00183    if (info_ptr->valid & PNG_INFO_sCAL)
00184 #if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
00185       png_write_sCAL(png_ptr, (int)info_ptr->scal_unit,
00186           info_ptr->scal_pixel_width, info_ptr->scal_pixel_height);
00187 #else
00188 #ifdef PNG_FIXED_POINT_SUPPORTED
00189       png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
00190           info_ptr->scal_s_width, info_ptr->scal_s_height);
00191 #else
00192       png_warning(png_ptr,
00193           "png_write_sCAL not supported; sCAL chunk not written.");
00194 #endif
00195 #endif
00196 #endif
00197 #if defined(PNG_WRITE_pHYs_SUPPORTED)
00198    if (info_ptr->valid & PNG_INFO_pHYs)
00199       png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
00200          info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
00201 #endif
00202 #if defined(PNG_WRITE_tIME_SUPPORTED)
00203    if (info_ptr->valid & PNG_INFO_tIME)
00204    {
00205       png_write_tIME(png_ptr, &(info_ptr->mod_time));
00206       png_ptr->mode |= PNG_WROTE_tIME;
00207    }
00208 #endif
00209 #if defined(PNG_WRITE_sPLT_SUPPORTED)
00210    if (info_ptr->valid & PNG_INFO_sPLT)
00211      for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
00212        png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
00213 #endif
00214 #if defined(PNG_WRITE_TEXT_SUPPORTED)
00215    /* Check to see if we need to write text chunks */
00216    for (i = 0; i < info_ptr->num_text; i++)
00217    {
00218       png_debug2(2, "Writing header text chunk %d, type %d\n", i,
00219          info_ptr->text[i].compression);
00220       /* an internationalized chunk? */
00221       if (info_ptr->text[i].compression > 0)
00222       {
00223 #if defined(PNG_WRITE_iTXt_SUPPORTED)
00224           /* write international chunk */
00225           png_write_iTXt(png_ptr,
00226                          info_ptr->text[i].compression,
00227                          info_ptr->text[i].key,
00228                          info_ptr->text[i].lang,
00229                          info_ptr->text[i].lang_key,
00230                          info_ptr->text[i].text);
00231 #else
00232           png_warning(png_ptr, "Unable to write international text");
00233 #endif
00234           /* Mark this chunk as written */
00235           info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
00236       }
00237       /* If we want a compressed text chunk */
00238       else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
00239       {
00240 #if defined(PNG_WRITE_zTXt_SUPPORTED)
00241          /* write compressed chunk */
00242          png_write_zTXt(png_ptr, info_ptr->text[i].key,
00243             info_ptr->text[i].text, 0,
00244             info_ptr->text[i].compression);
00245 #else
00246          png_warning(png_ptr, "Unable to write compressed text");
00247 #endif
00248          /* Mark this chunk as written */
00249          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
00250       }
00251       else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
00252       {
00253 #if defined(PNG_WRITE_tEXt_SUPPORTED)
00254          /* write uncompressed chunk */
00255          png_write_tEXt(png_ptr, info_ptr->text[i].key,
00256                          info_ptr->text[i].text,
00257                          0);
00258 #else
00259          png_warning(png_ptr, "Unable to write uncompressed text");
00260 #endif
00261          /* Mark this chunk as written */
00262          info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
00263       }
00264    }
00265 #endif
00266 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
00267    if (info_ptr->unknown_chunks_num)
00268    {
00269        png_unknown_chunk *up;
00270 
00271        png_debug(5, "writing extra chunks\n");
00272 
00273        for (up = info_ptr->unknown_chunks;
00274             up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
00275             up++)
00276        {
00277          int keep=png_handle_as_unknown(png_ptr, up->name);
00278          if (keep != PNG_HANDLE_CHUNK_NEVER &&
00279             up->location && (up->location & PNG_HAVE_PLTE) &&
00280             !(up->location & PNG_HAVE_IDAT) &&
00281             ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
00282             (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
00283          {
00284             png_write_chunk(png_ptr, up->name, up->data, up->size);
00285          }
00286        }
00287    }
00288 #endif
00289 }
00290 
00291 /* Writes the end of the PNG file.  If you don't want to write comments or
00292  * time information, you can pass NULL for info.  If you already wrote these
00293  * in png_write_info(), do not write them again here.  If you have long
00294  * comments, I suggest writing them here, and compressing them.
00295  */
00296 void PNGAPI
00297 png_write_end(png_structp png_ptr, png_infop info_ptr)
00298 {
00299    png_debug(1, "in png_write_end\n");
00300    if (png_ptr == NULL)
00301       return;
00302    if (!(png_ptr->mode & PNG_HAVE_IDAT))
00303       png_error(png_ptr, "No IDATs written into file");
00304 
00305    /* see if user wants us to write information chunks */
00306    if (info_ptr != NULL)
00307    {
00308 #if defined(PNG_WRITE_TEXT_SUPPORTED)
00309       int i; /* local index variable */
00310 #endif
00311 #if defined(PNG_WRITE_tIME_SUPPORTED)
00312       /* check to see if user has supplied a time chunk */
00313       if ((info_ptr->valid & PNG_INFO_tIME) &&
00314          !(png_ptr->mode & PNG_WROTE_tIME))
00315          png_write_tIME(png_ptr, &(info_ptr->mod_time));
00316 #endif
00317 #if defined(PNG_WRITE_TEXT_SUPPORTED)
00318       /* loop through comment chunks */
00319       for (i = 0; i < info_ptr->num_text; i++)
00320       {
00321          png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
00322             info_ptr->text[i].compression);
00323          /* an internationalized chunk? */
00324          if (info_ptr->text[i].compression > 0)
00325          {
00326 #if defined(PNG_WRITE_iTXt_SUPPORTED)
00327              /* write international chunk */
00328              png_write_iTXt(png_ptr,
00329                          info_ptr->text[i].compression,
00330                          info_ptr->text[i].key,
00331                          info_ptr->text[i].lang,
00332                          info_ptr->text[i].lang_key,
00333                          info_ptr->text[i].text);
00334 #else
00335              png_warning(png_ptr, "Unable to write international text");
00336 #endif
00337              /* Mark this chunk as written */
00338              info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
00339          }
00340          else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
00341          {
00342 #if defined(PNG_WRITE_zTXt_SUPPORTED)
00343             /* write compressed chunk */
00344             png_write_zTXt(png_ptr, info_ptr->text[i].key,
00345                info_ptr->text[i].text, 0,
00346                info_ptr->text[i].compression);
00347 #else
00348             png_warning(png_ptr, "Unable to write compressed text");
00349 #endif
00350             /* Mark this chunk as written */
00351             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
00352          }
00353          else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
00354          {
00355 #if defined(PNG_WRITE_tEXt_SUPPORTED)
00356             /* write uncompressed chunk */
00357             png_write_tEXt(png_ptr, info_ptr->text[i].key,
00358                info_ptr->text[i].text, 0);
00359 #else
00360             png_warning(png_ptr, "Unable to write uncompressed text");
00361 #endif
00362 
00363             /* Mark this chunk as written */
00364             info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
00365          }
00366       }
00367 #endif
00368 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
00369    if (info_ptr->unknown_chunks_num)
00370    {
00371        png_unknown_chunk *up;
00372 
00373        png_debug(5, "writing extra chunks\n");
00374 
00375        for (up = info_ptr->unknown_chunks;
00376             up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
00377             up++)
00378        {
00379          int keep=png_handle_as_unknown(png_ptr, up->name);
00380          if (keep != PNG_HANDLE_CHUNK_NEVER &&
00381             up->location && (up->location & PNG_AFTER_IDAT) &&
00382             ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
00383             (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
00384          {
00385             png_write_chunk(png_ptr, up->name, up->data, up->size);
00386          }
00387        }
00388    }
00389 #endif
00390    }
00391 
00392    png_ptr->mode |= PNG_AFTER_IDAT;
00393 
00394    /* write end of PNG file */
00395    png_write_IEND(png_ptr);
00396    /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,
00397     * and restored again in libpng-1.2.30, may cause some applications that
00398     * do not set png_ptr->output_flush_fn to crash.  If your application
00399     * experiences a problem, please try building libpng with
00400     * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to
00401     * png-mng-implement at lists.sf.net .  This kludge will be removed
00402     * from libpng-1.4.0.
00403     */
00404 #if defined(PNG_WRITE_FLUSH_SUPPORTED) && \
00405     defined(PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED)
00406    png_flush(png_ptr);
00407 #endif
00408 }
00409 
00410 #if defined(PNG_WRITE_tIME_SUPPORTED)
00411 #if !defined(_WIN32_WCE)
00412 /* "time.h" functions are not supported on WindowsCE */
00413 void PNGAPI
00414 png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
00415 {
00416    png_debug(1, "in png_convert_from_struct_tm\n");
00417    ptime->year = (png_uint_16)(1900 + ttime->tm_year);
00418    ptime->month = (png_byte)(ttime->tm_mon + 1);
00419    ptime->day = (png_byte)ttime->tm_mday;
00420    ptime->hour = (png_byte)ttime->tm_hour;
00421    ptime->minute = (png_byte)ttime->tm_min;
00422    ptime->second = (png_byte)ttime->tm_sec;
00423 }
00424 
00425 void PNGAPI
00426 png_convert_from_time_t(png_timep ptime, time_t ttime)
00427 {
00428    struct tm *tbuf;
00429 
00430    png_debug(1, "in png_convert_from_time_t\n");
00431    tbuf = gmtime(&ttime);
00432    png_convert_from_struct_tm(ptime, tbuf);
00433 }
00434 #endif
00435 #endif
00436 
00437 /* Initialize png_ptr structure, and allocate any memory needed */
00438 png_structp PNGAPI
00439 png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr,
00440    png_error_ptr error_fn, png_error_ptr warn_fn)
00441 {
00442 #ifdef PNG_USER_MEM_SUPPORTED
00443    return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
00444       warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL));
00445 }
00446 
00447 /* Alternate initialize png_ptr structure, and allocate any memory needed */
00448 png_structp PNGAPI
00449 png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
00450    png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
00451    png_malloc_ptr malloc_fn, png_free_ptr free_fn)
00452 {
00453 #endif /* PNG_USER_MEM_SUPPORTED */
00454 #ifdef PNG_SETJMP_SUPPORTED
00455     volatile
00456 #endif
00457     png_structp png_ptr;
00458 #ifdef PNG_SETJMP_SUPPORTED
00459 #ifdef USE_FAR_KEYWORD
00460    jmp_buf jmpbuf;
00461 #endif
00462 #endif
00463    int i;
00464    png_debug(1, "in png_create_write_struct\n");
00465 #ifdef PNG_USER_MEM_SUPPORTED
00466    png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
00467       (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
00468 #else
00469    png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
00470 #endif /* PNG_USER_MEM_SUPPORTED */
00471    if (png_ptr == NULL)
00472       return (NULL);
00473 
00474    /* added at libpng-1.2.6 */
00475 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
00476    png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
00477    png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
00478 #endif
00479 
00480 #ifdef PNG_SETJMP_SUPPORTED
00481 #ifdef USE_FAR_KEYWORD
00482    if (setjmp(jmpbuf))
00483 #else
00484    if (setjmp(png_ptr->jmpbuf))
00485 #endif
00486    {
00487       png_free(png_ptr, png_ptr->zbuf);
00488        png_ptr->zbuf=NULL;
00489       png_destroy_struct(png_ptr);
00490       return (NULL);
00491    }
00492 #ifdef USE_FAR_KEYWORD
00493    png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf));
00494 #endif
00495 #endif
00496 
00497 #ifdef PNG_USER_MEM_SUPPORTED
00498    png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
00499 #endif /* PNG_USER_MEM_SUPPORTED */
00500    png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
00501 
00502    if (user_png_ver)
00503    {
00504      i=0;
00505      do
00506      {
00507        if (user_png_ver[i] != png_libpng_ver[i])
00508           png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
00509      } while (png_libpng_ver[i++]);
00510    }
00511 
00512    if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
00513    {
00514      /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
00515       * we must recompile any applications that use any older library version.
00516       * For versions after libpng 1.0, we will be compatible, so we need
00517       * only check the first digit.
00518       */
00519      if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
00520          (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
00521          (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
00522      {
00523 #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
00524         char msg[80];
00525         if (user_png_ver)
00526         {
00527           png_snprintf(msg, 80,
00528              "Application was compiled with png.h from libpng-%.20s",
00529              user_png_ver);
00530           png_warning(png_ptr, msg);
00531         }
00532         png_snprintf(msg, 80,
00533            "Application  is  running with png.c from libpng-%.20s",
00534            png_libpng_ver);
00535         png_warning(png_ptr, msg);
00536 #endif
00537 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
00538         png_ptr->flags=0;
00539 #endif
00540         png_error(png_ptr,
00541            "Incompatible libpng version in application and library");
00542      }
00543    }
00544 
00545    /* initialize zbuf - compression buffer */
00546    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
00547    png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
00548       (png_uint_32)png_ptr->zbuf_size);
00549 
00550    png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
00551       png_flush_ptr_NULL);
00552 
00553 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
00554    png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
00555       1, png_doublep_NULL, png_doublep_NULL);
00556 #endif
00557 
00558 #ifdef PNG_SETJMP_SUPPORTED
00559 /* Applications that neglect to set up their own setjmp() and then encounter
00560    a png_error() will longjmp here.  Since the jmpbuf is then meaningless we
00561    abort instead of returning. */
00562 #ifdef USE_FAR_KEYWORD
00563    if (setjmp(jmpbuf))
00564       PNG_ABORT();
00565    png_memcpy(png_ptr->jmpbuf, jmpbuf, png_sizeof(jmp_buf));
00566 #else
00567    if (setjmp(png_ptr->jmpbuf))
00568       PNG_ABORT();
00569 #endif
00570 #endif
00571    return (png_ptr);
00572 }
00573 
00574 /* Initialize png_ptr structure, and allocate any memory needed */
00575 #if defined(PNG_1_0_X) || defined(PNG_1_2_X)
00576 /* Deprecated. */
00577 #undef png_write_init
00578 void PNGAPI
00579 png_write_init(png_structp png_ptr)
00580 {
00581    /* We only come here via pre-1.0.7-compiled applications */
00582    png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0);
00583 }
00584 
00585 void PNGAPI
00586 png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver,
00587    png_size_t png_struct_size, png_size_t png_info_size)
00588 {
00589    /* We only come here via pre-1.0.12-compiled applications */
00590    if (png_ptr == NULL) return;
00591 #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
00592    if (png_sizeof(png_struct) > png_struct_size ||
00593       png_sizeof(png_info) > png_info_size)
00594    {
00595       char msg[80];
00596       png_ptr->warning_fn=NULL;
00597       if (user_png_ver)
00598       {
00599         png_snprintf(msg, 80,
00600            "Application was compiled with png.h from libpng-%.20s",
00601            user_png_ver);
00602         png_warning(png_ptr, msg);
00603       }
00604       png_snprintf(msg, 80,
00605          "Application  is  running with png.c from libpng-%.20s",
00606          png_libpng_ver);
00607       png_warning(png_ptr, msg);
00608    }
00609 #endif
00610    if (png_sizeof(png_struct) > png_struct_size)
00611      {
00612        png_ptr->error_fn=NULL;
00613 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
00614        png_ptr->flags=0;
00615 #endif
00616        png_error(png_ptr,
00617        "The png struct allocated by the application for writing is too small.");
00618      }
00619    if (png_sizeof(png_info) > png_info_size)
00620      {
00621        png_ptr->error_fn=NULL;
00622 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
00623        png_ptr->flags=0;
00624 #endif
00625        png_error(png_ptr,
00626        "The info struct allocated by the application for writing is too small.");
00627      }
00628    png_write_init_3(&png_ptr, user_png_ver, png_struct_size);
00629 }
00630 #endif /* PNG_1_0_X || PNG_1_2_X */
00631 
00632 
00633 void PNGAPI
00634 png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
00635    png_size_t png_struct_size)
00636 {
00637    png_structp png_ptr=*ptr_ptr;
00638 #ifdef PNG_SETJMP_SUPPORTED
00639    jmp_buf tmp_jmp; /* to save current jump buffer */
00640 #endif
00641 
00642    int i = 0;
00643 
00644    if (png_ptr == NULL)
00645       return;
00646 
00647    do
00648    {
00649      if (user_png_ver[i] != png_libpng_ver[i])
00650      {
00651 #ifdef PNG_LEGACY_SUPPORTED
00652        png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
00653 #else
00654        png_ptr->warning_fn=NULL;
00655        png_warning(png_ptr,
00656  "Application uses deprecated png_write_init() and should be recompiled.");
00657        break;
00658 #endif
00659      }
00660    } while (png_libpng_ver[i++]);
00661 
00662    png_debug(1, "in png_write_init_3\n");
00663 
00664 #ifdef PNG_SETJMP_SUPPORTED
00665    /* save jump buffer and error functions */
00666    png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf));
00667 #endif
00668 
00669    if (png_sizeof(png_struct) > png_struct_size)
00670      {
00671        png_destroy_struct(png_ptr);
00672        png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
00673        *ptr_ptr = png_ptr;
00674      }
00675 
00676    /* reset all variables to 0 */
00677    png_memset(png_ptr, 0, png_sizeof(png_struct));
00678 
00679    /* added at libpng-1.2.6 */
00680 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
00681    png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
00682    png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
00683 #endif
00684 
00685 #ifdef PNG_SETJMP_SUPPORTED
00686    /* restore jump buffer */
00687    png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf));
00688 #endif
00689 
00690    png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
00691       png_flush_ptr_NULL);
00692 
00693    /* initialize zbuf - compression buffer */
00694    png_ptr->zbuf_size = PNG_ZBUF_SIZE;
00695    png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
00696       (png_uint_32)png_ptr->zbuf_size);
00697 
00698 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
00699    png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
00700       1, png_doublep_NULL, png_doublep_NULL);
00701 #endif
00702 }
00703 
00704 /* Write a few rows of image data.  If the image is interlaced,
00705  * either you will have to write the 7 sub images, or, if you
00706  * have called png_set_interlace_handling(), you will have to
00707  * "write" the image seven times.
00708  */
00709 void PNGAPI
00710 png_write_rows(png_structp png_ptr, png_bytepp row,
00711    png_uint_32 num_rows)
00712 {
00713    png_uint_32 i; /* row counter */
00714    png_bytepp rp; /* row pointer */
00715 
00716    png_debug(1, "in png_write_rows\n");
00717 
00718    if (png_ptr == NULL)
00719       return;
00720 
00721    /* loop through the rows */
00722    for (i = 0, rp = row; i < num_rows; i++, rp++)
00723    {
00724       png_write_row(png_ptr, *rp);
00725    }
00726 }
00727 
00728 /* Write the image.  You only need to call this function once, even
00729  * if you are writing an interlaced image.
00730  */
00731 void PNGAPI
00732 png_write_image(png_structp png_ptr, png_bytepp image)
00733 {
00734    png_uint_32 i; /* row index */
00735    int pass, num_pass; /* pass variables */
00736    png_bytepp rp; /* points to current row */
00737 
00738    if (png_ptr == NULL)
00739       return;
00740 
00741    png_debug(1, "in png_write_image\n");
00742 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
00743    /* intialize interlace handling.  If image is not interlaced,
00744       this will set pass to 1 */
00745    num_pass = png_set_interlace_handling(png_ptr);
00746 #else
00747    num_pass = 1;
00748 #endif
00749    /* loop through passes */
00750    for (pass = 0; pass < num_pass; pass++)
00751    {
00752       /* loop through image */
00753       for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
00754       {
00755          png_write_row(png_ptr, *rp);
00756       }
00757    }
00758 }
00759 
00760 /* called by user to write a row of image data */
00761 void PNGAPI
00762 png_write_row(png_structp png_ptr, png_bytep row)
00763 {
00764    if (png_ptr == NULL)
00765       return;
00766    png_debug2(1, "in png_write_row (row %ld, pass %d)\n",
00767       png_ptr->row_number, png_ptr->pass);
00768 
00769    /* initialize transformations and other stuff if first time */
00770    if (png_ptr->row_number == 0 && png_ptr->pass == 0)
00771    {
00772    /* make sure we wrote the header info */
00773    if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
00774       png_error(png_ptr,
00775          "png_write_info was never called before png_write_row.");
00776 
00777    /* check for transforms that have been set but were defined out */
00778 #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
00779    if (png_ptr->transformations & PNG_INVERT_MONO)
00780       png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined.");
00781 #endif
00782 #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
00783    if (png_ptr->transformations & PNG_FILLER)
00784       png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined.");
00785 #endif
00786 #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED)
00787    if (png_ptr->transformations & PNG_PACKSWAP)
00788       png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined.");
00789 #endif
00790 #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
00791    if (png_ptr->transformations & PNG_PACK)
00792       png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined.");
00793 #endif
00794 #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
00795    if (png_ptr->transformations & PNG_SHIFT)
00796       png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined.");
00797 #endif
00798 #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
00799    if (png_ptr->transformations & PNG_BGR)
00800       png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined.");
00801 #endif
00802 #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
00803    if (png_ptr->transformations & PNG_SWAP_BYTES)
00804       png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined.");
00805 #endif
00806 
00807       png_write_start_row(png_ptr);
00808    }
00809 
00810 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
00811    /* if interlaced and not interested in row, return */
00812    if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
00813    {
00814       switch (png_ptr->pass)
00815       {
00816          case 0:
00817             if (png_ptr->row_number & 0x07)
00818             {
00819                png_write_finish_row(png_ptr);
00820                return;
00821             }
00822             break;
00823          case 1:
00824             if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
00825             {
00826                png_write_finish_row(png_ptr);
00827                return;
00828             }
00829             break;
00830          case 2:
00831             if ((png_ptr->row_number & 0x07) != 4)
00832             {
00833                png_write_finish_row(png_ptr);
00834                return;
00835             }
00836             break;
00837          case 3:
00838             if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
00839             {
00840                png_write_finish_row(png_ptr);
00841                return;
00842             }
00843             break;
00844          case 4:
00845             if ((png_ptr->row_number & 0x03) != 2)
00846             {
00847                png_write_finish_row(png_ptr);
00848                return;
00849             }
00850             break;
00851          case 5:
00852             if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
00853             {
00854                png_write_finish_row(png_ptr);
00855                return;
00856             }
00857             break;
00858          case 6:
00859             if (!(png_ptr->row_number & 0x01))
00860             {
00861                png_write_finish_row(png_ptr);
00862                return;
00863             }
00864             break;
00865       }
00866    }
00867 #endif
00868 
00869    /* set up row info for transformations */
00870    png_ptr->row_info.color_type = png_ptr->color_type;
00871    png_ptr->row_info.width = png_ptr->usr_width;
00872    png_ptr->row_info.channels = png_ptr->usr_channels;
00873    png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
00874    png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
00875       png_ptr->row_info.channels);
00876 
00877    png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
00878       png_ptr->row_info.width);
00879 
00880    png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
00881    png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width);
00882    png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels);
00883    png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
00884    png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
00885    png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes);
00886 
00887    /* Copy user's row into buffer, leaving room for filter byte. */
00888    png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row,
00889       png_ptr->row_info.rowbytes);
00890 
00891 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
00892    /* handle interlacing */
00893    if (png_ptr->interlaced && png_ptr->pass < 6 &&
00894       (png_ptr->transformations & PNG_INTERLACE))
00895    {
00896       png_do_write_interlace(&(png_ptr->row_info),
00897          png_ptr->row_buf + 1, png_ptr->pass);
00898       /* this should always get caught above, but still ... */
00899       if (!(png_ptr->row_info.width))
00900       {
00901          png_write_finish_row(png_ptr);
00902          return;
00903       }
00904    }
00905 #endif
00906 
00907    /* handle other transformations */
00908    if (png_ptr->transformations)
00909       png_do_write_transformations(png_ptr);
00910 
00911 #if defined(PNG_MNG_FEATURES_SUPPORTED)
00912    /* Write filter_method 64 (intrapixel differencing) only if
00913     * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
00914     * 2. Libpng did not write a PNG signature (this filter_method is only
00915     *    used in PNG datastreams that are embedded in MNG datastreams) and
00916     * 3. The application called png_permit_mng_features with a mask that
00917     *    included PNG_FLAG_MNG_FILTER_64 and
00918     * 4. The filter_method is 64 and
00919     * 5. The color_type is RGB or RGBA
00920     */
00921    if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
00922       (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
00923    {
00924       /* Intrapixel differencing */
00925       png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
00926    }
00927 #endif
00928 
00929    /* Find a filter if necessary, filter the row and write it out. */
00930    png_write_find_filter(png_ptr, &(png_ptr->row_info));
00931 
00932    if (png_ptr->write_row_fn != NULL)
00933       (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
00934 }
00935 
00936 #if defined(PNG_WRITE_FLUSH_SUPPORTED)
00937 /* Set the automatic flush interval or 0 to turn flushing off */
00938 void PNGAPI
00939 png_set_flush(png_structp png_ptr, int nrows)
00940 {
00941    png_debug(1, "in png_set_flush\n");
00942    if (png_ptr == NULL)
00943       return;
00944    png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
00945 }
00946 
00947 /* flush the current output buffers now */
00948 void PNGAPI
00949 png_write_flush(png_structp png_ptr)
00950 {
00951    int wrote_IDAT;
00952 
00953    png_debug(1, "in png_write_flush\n");
00954    if (png_ptr == NULL)
00955       return;
00956    /* We have already written out all of the data */
00957    if (png_ptr->row_number >= png_ptr->num_rows)
00958      return;
00959 
00960    do
00961    {
00962       int ret;
00963 
00964       /* compress the data */
00965       ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
00966       wrote_IDAT = 0;
00967 
00968       /* check for compression errors */
00969       if (ret != Z_OK)
00970       {
00971          if (png_ptr->zstream.msg != NULL)
00972             png_error(png_ptr, png_ptr->zstream.msg);
00973          else
00974             png_error(png_ptr, "zlib error");
00975       }
00976 
00977       if (!(png_ptr->zstream.avail_out))
00978       {
00979          /* write the IDAT and reset the zlib output buffer */
00980          png_write_IDAT(png_ptr, png_ptr->zbuf,
00981                         png_ptr->zbuf_size);
00982          png_ptr->zstream.next_out = png_ptr->zbuf;
00983          png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
00984          wrote_IDAT = 1;
00985       }
00986    } while(wrote_IDAT == 1);
00987 
00988    /* If there is any data left to be output, write it into a new IDAT */
00989    if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
00990    {
00991       /* write the IDAT and reset the zlib output buffer */
00992       png_write_IDAT(png_ptr, png_ptr->zbuf,
00993                      png_ptr->zbuf_size - png_ptr->zstream.avail_out);
00994       png_ptr->zstream.next_out = png_ptr->zbuf;
00995       png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
00996    }
00997    png_ptr->flush_rows = 0;
00998    png_flush(png_ptr);
00999 }
01000 #endif /* PNG_WRITE_FLUSH_SUPPORTED */
01001 
01002 /* free all memory used by the write */
01003 void PNGAPI
01004 png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
01005 {
01006    png_structp png_ptr = NULL;
01007    png_infop info_ptr = NULL;
01008 #ifdef PNG_USER_MEM_SUPPORTED
01009    png_free_ptr free_fn = NULL;
01010    png_voidp mem_ptr = NULL;
01011 #endif
01012 
01013    png_debug(1, "in png_destroy_write_struct\n");
01014    if (png_ptr_ptr != NULL)
01015    {
01016       png_ptr = *png_ptr_ptr;
01017 #ifdef PNG_USER_MEM_SUPPORTED
01018       free_fn = png_ptr->free_fn;
01019       mem_ptr = png_ptr->mem_ptr;
01020 #endif
01021    }
01022 
01023 #ifdef PNG_USER_MEM_SUPPORTED
01024    if (png_ptr != NULL)
01025    {
01026       free_fn = png_ptr->free_fn;
01027       mem_ptr = png_ptr->mem_ptr;
01028    }
01029 #endif
01030 
01031    if (info_ptr_ptr != NULL)
01032       info_ptr = *info_ptr_ptr;
01033 
01034    if (info_ptr != NULL)
01035    {
01036       if (png_ptr != NULL)
01037       {
01038         png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
01039 
01040 #if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
01041         if (png_ptr->num_chunk_list)
01042         {
01043            png_free(png_ptr, png_ptr->chunk_list);
01044            png_ptr->chunk_list=NULL;
01045            png_ptr->num_chunk_list = 0;
01046         }
01047 #endif
01048       }
01049 
01050 #ifdef PNG_USER_MEM_SUPPORTED
01051       png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
01052          (png_voidp)mem_ptr);
01053 #else
01054       png_destroy_struct((png_voidp)info_ptr);
01055 #endif
01056       *info_ptr_ptr = NULL;
01057    }
01058 
01059    if (png_ptr != NULL)
01060    {
01061       png_write_destroy(png_ptr);
01062 #ifdef PNG_USER_MEM_SUPPORTED
01063       png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
01064          (png_voidp)mem_ptr);
01065 #else
01066       png_destroy_struct((png_voidp)png_ptr);
01067 #endif
01068       *png_ptr_ptr = NULL;
01069    }
01070 }
01071 
01072 
01073 /* Free any memory used in png_ptr struct (old method) */
01074 void /* PRIVATE */
01075 png_write_destroy(png_structp png_ptr)
01076 {
01077 #ifdef PNG_SETJMP_SUPPORTED
01078    jmp_buf tmp_jmp; /* save jump buffer */
01079 #endif
01080    png_error_ptr error_fn;
01081    png_error_ptr warning_fn;
01082    png_voidp error_ptr;
01083 #ifdef PNG_USER_MEM_SUPPORTED
01084    png_free_ptr free_fn;
01085 #endif
01086 
01087    png_debug(1, "in png_write_destroy\n");
01088    /* free any memory zlib uses */
01089    deflateEnd(&png_ptr->zstream);
01090 
01091    /* free our memory.  png_free checks NULL for us. */
01092    png_free(png_ptr, png_ptr->zbuf);
01093    png_free(png_ptr, png_ptr->row_buf);
01094 #ifndef PNG_NO_WRITE_FILTER
01095    png_free(png_ptr, png_ptr->prev_row);
01096    png_free(png_ptr, png_ptr->sub_row);
01097    png_free(png_ptr, png_ptr->up_row);
01098    png_free(png_ptr, png_ptr->avg_row);
01099    png_free(png_ptr, png_ptr->paeth_row);
01100 #endif
01101 
01102 #if defined(PNG_TIME_RFC1123_SUPPORTED)
01103    png_free(png_ptr, png_ptr->time_buffer);
01104 #endif
01105 
01106 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
01107    png_free(png_ptr, png_ptr->prev_filters);
01108    png_free(png_ptr, png_ptr->filter_weights);
01109    png_free(png_ptr, png_ptr->inv_filter_weights);
01110    png_free(png_ptr, png_ptr->filter_costs);
01111    png_free(png_ptr, png_ptr->inv_filter_costs);
01112 #endif
01113 
01114 #ifdef PNG_SETJMP_SUPPORTED
01115    /* reset structure */
01116    png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof(jmp_buf));
01117 #endif
01118 
01119    error_fn = png_ptr->error_fn;
01120    warning_fn = png_ptr->warning_fn;
01121    error_ptr = png_ptr->error_ptr;
01122 #ifdef PNG_USER_MEM_SUPPORTED
01123    free_fn = png_ptr->free_fn;
01124 #endif
01125 
01126    png_memset(png_ptr, 0, png_sizeof(png_struct));
01127 
01128    png_ptr->error_fn = error_fn;
01129    png_ptr->warning_fn = warning_fn;
01130    png_ptr->error_ptr = error_ptr;
01131 #ifdef PNG_USER_MEM_SUPPORTED
01132    png_ptr->free_fn = free_fn;
01133 #endif
01134 
01135 #ifdef PNG_SETJMP_SUPPORTED
01136    png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof(jmp_buf));
01137 #endif
01138 }
01139 
01140 /* Allow the application to select one or more row filters to use. */
01141 void PNGAPI
01142 png_set_filter(png_structp png_ptr, int method, int filters)
01143 {
01144    png_debug(1, "in png_set_filter\n");
01145    if (png_ptr == NULL)
01146       return;
01147 #if defined(PNG_MNG_FEATURES_SUPPORTED)
01148    if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
01149       (method == PNG_INTRAPIXEL_DIFFERENCING))
01150          method = PNG_FILTER_TYPE_BASE;
01151 #endif
01152    if (method == PNG_FILTER_TYPE_BASE)
01153    {
01154       switch (filters & (PNG_ALL_FILTERS | 0x07))
01155       {
01156 #ifndef PNG_NO_WRITE_FILTER
01157          case 5:
01158          case 6:
01159          case 7: png_warning(png_ptr, "Unknown row filter for method 0");
01160 #endif /* PNG_NO_WRITE_FILTER */
01161          case PNG_FILTER_VALUE_NONE:
01162               png_ptr->do_filter=PNG_FILTER_NONE; break;
01163 #ifndef PNG_NO_WRITE_FILTER
01164          case PNG_FILTER_VALUE_SUB:
01165               png_ptr->do_filter=PNG_FILTER_SUB; break;
01166          case PNG_FILTER_VALUE_UP:
01167               png_ptr->do_filter=PNG_FILTER_UP; break;
01168          case PNG_FILTER_VALUE_AVG:
01169               png_ptr->do_filter=PNG_FILTER_AVG; break;
01170          case PNG_FILTER_VALUE_PAETH:
01171               png_ptr->do_filter=PNG_FILTER_PAETH; break;
01172          default: png_ptr->do_filter = (png_byte)filters; break;
01173 #else
01174          default: png_warning(png_ptr, "Unknown row filter for method 0");
01175 #endif /* PNG_NO_WRITE_FILTER */
01176       }
01177 
01178       /* If we have allocated the row_buf, this means we have already started
01179        * with the image and we should have allocated all of the filter buffers
01180        * that have been selected.  If prev_row isn't already allocated, then
01181        * it is too late to start using the filters that need it, since we
01182        * will be missing the data in the previous row.  If an application
01183        * wants to start and stop using particular filters during compression,
01184        * it should start out with all of the filters, and then add and
01185        * remove them after the start of compression.
01186        */
01187       if (png_ptr->row_buf != NULL)
01188       {
01189 #ifndef PNG_NO_WRITE_FILTER
01190          if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
01191          {
01192             png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
01193               (png_ptr->rowbytes + 1));
01194             png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
01195          }
01196 
01197          if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
01198          {
01199             if (png_ptr->prev_row == NULL)
01200             {
01201                png_warning(png_ptr, "Can't add Up filter after starting");
01202                png_ptr->do_filter &= ~PNG_FILTER_UP;
01203             }
01204             else
01205             {
01206                png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
01207                   (png_ptr->rowbytes + 1));
01208                png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
01209             }
01210          }
01211 
01212          if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
01213          {
01214             if (png_ptr->prev_row == NULL)
01215             {
01216                png_warning(png_ptr, "Can't add Average filter after starting");
01217                png_ptr->do_filter &= ~PNG_FILTER_AVG;
01218             }
01219             else
01220             {
01221                png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
01222                   (png_ptr->rowbytes + 1));
01223                png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
01224             }
01225          }
01226 
01227          if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
01228              png_ptr->paeth_row == NULL)
01229          {
01230             if (png_ptr->prev_row == NULL)
01231             {
01232                png_warning(png_ptr, "Can't add Paeth filter after starting");
01233                png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
01234             }
01235             else
01236             {
01237                png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
01238                   (png_ptr->rowbytes + 1));
01239                png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
01240             }
01241          }
01242 
01243          if (png_ptr->do_filter == PNG_NO_FILTERS)
01244 #endif /* PNG_NO_WRITE_FILTER */
01245             png_ptr->do_filter = PNG_FILTER_NONE;
01246       }
01247    }
01248    else
01249       png_error(png_ptr, "Unknown custom filter method");
01250 }
01251 
01252 /* This allows us to influence the way in which libpng chooses the "best"
01253  * filter for the current scanline.  While the "minimum-sum-of-absolute-
01254  * differences metric is relatively fast and effective, there is some
01255  * question as to whether it can be improved upon by trying to keep the
01256  * filtered data going to zlib more consistent, hopefully resulting in
01257  * better compression.
01258  */
01259 #if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)      /* GRR 970116 */
01260 void PNGAPI
01261 png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
01262    int num_weights, png_doublep filter_weights,
01263    png_doublep filter_costs)
01264 {
01265    int i;
01266 
01267    png_debug(1, "in png_set_filter_heuristics\n");
01268    if (png_ptr == NULL)
01269       return;
01270    if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
01271    {
01272       png_warning(png_ptr, "Unknown filter heuristic method");
01273       return;
01274    }
01275 
01276    if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
01277    {
01278       heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
01279    }
01280 
01281    if (num_weights < 0 || filter_weights == NULL ||
01282       heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
01283    {
01284       num_weights = 0;
01285    }
01286 
01287    png_ptr->num_prev_filters = (png_byte)num_weights;
01288    png_ptr->heuristic_method = (png_byte)heuristic_method;
01289 
01290    if (num_weights > 0)
01291    {
01292       if (png_ptr->prev_filters == NULL)
01293       {
01294          png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
01295             (png_uint_32)(png_sizeof(png_byte) * num_weights));
01296 
01297          /* To make sure that the weighting starts out fairly */
01298          for (i = 0; i < num_weights; i++)
01299          {
01300             png_ptr->prev_filters[i] = 255;
01301          }
01302       }
01303 
01304       if (png_ptr->filter_weights == NULL)
01305       {
01306          png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
01307             (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
01308 
01309          png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
01310             (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
01311          for (i = 0; i < num_weights; i++)
01312          {
01313             png_ptr->inv_filter_weights[i] =
01314             png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
01315          }
01316       }
01317 
01318       for (i = 0; i < num_weights; i++)
01319       {
01320          if (filter_weights[i] < 0.0)
01321          {
01322             png_ptr->inv_filter_weights[i] =
01323             png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
01324          }
01325          else
01326          {
01327             png_ptr->inv_filter_weights[i] =
01328                (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
01329             png_ptr->filter_weights[i] =
01330                (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
01331          }
01332       }
01333    }
01334 
01335    /* If, in the future, there are other filter methods, this would
01336     * need to be based on png_ptr->filter.
01337     */
01338    if (png_ptr->filter_costs == NULL)
01339    {
01340       png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
01341          (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
01342 
01343       png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
01344          (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
01345 
01346       for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
01347       {
01348          png_ptr->inv_filter_costs[i] =
01349          png_ptr->filter_costs[i] = PNG_COST_FACTOR;
01350       }
01351    }
01352 
01353    /* Here is where we set the relative costs of the different filters.  We
01354     * should take the desired compression level into account when setting
01355     * the costs, so that Paeth, for instance, has a high relative cost at low
01356     * compression levels, while it has a lower relative cost at higher
01357     * compression settings.  The filter types are in order of increasing
01358     * relative cost, so it would be possible to do this with an algorithm.
01359     */
01360    for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
01361    {
01362       if (filter_costs == NULL || filter_costs[i] < 0.0)
01363       {
01364          png_ptr->inv_filter_costs[i] =
01365          png_ptr->filter_costs[i] = PNG_COST_FACTOR;
01366       }
01367       else if (filter_costs[i] >= 1.0)
01368       {
01369          png_ptr->inv_filter_costs[i] =
01370             (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
01371          png_ptr->filter_costs[i] =
01372             (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
01373       }
01374    }
01375 }
01376 #endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
01377 
01378 void PNGAPI
01379 png_set_compression_level(png_structp png_ptr, int level)
01380 {
01381    png_debug(1, "in png_set_compression_level\n");
01382    if (png_ptr == NULL)
01383       return;
01384    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
01385    png_ptr->zlib_level = level;
01386 }
01387 
01388 void PNGAPI
01389 png_set_compression_mem_level(png_structp png_ptr, int mem_level)
01390 {
01391    png_debug(1, "in png_set_compression_mem_level\n");
01392    if (png_ptr == NULL)
01393       return;
01394    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
01395    png_ptr->zlib_mem_level = mem_level;
01396 }
01397 
01398 void PNGAPI
01399 png_set_compression_strategy(png_structp png_ptr, int strategy)
01400 {
01401    png_debug(1, "in png_set_compression_strategy\n");
01402    if (png_ptr == NULL)
01403       return;
01404    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
01405    png_ptr->zlib_strategy = strategy;
01406 }
01407 
01408 void PNGAPI
01409 png_set_compression_window_bits(png_structp png_ptr, int window_bits)
01410 {
01411    if (png_ptr == NULL)
01412       return;
01413    if (window_bits > 15)
01414       png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
01415    else if (window_bits < 8)
01416       png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
01417 #ifndef WBITS_8_OK
01418    /* avoid libpng bug with 256-byte windows */
01419    if (window_bits == 8)
01420      {
01421        png_warning(png_ptr, "Compression window is being reset to 512");
01422        window_bits=9;
01423      }
01424 #endif
01425    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
01426    png_ptr->zlib_window_bits = window_bits;
01427 }
01428 
01429 void PNGAPI
01430 png_set_compression_method(png_structp png_ptr, int method)
01431 {
01432    png_debug(1, "in png_set_compression_method\n");
01433    if (png_ptr == NULL)
01434       return;
01435    if (method != 8)
01436       png_warning(png_ptr, "Only compression method 8 is supported by PNG");
01437    png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
01438    png_ptr->zlib_method = method;
01439 }
01440 
01441 void PNGAPI
01442 png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
01443 {
01444    if (png_ptr == NULL)
01445       return;
01446    png_ptr->write_row_fn = write_row_fn;
01447 }
01448 
01449 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
01450 void PNGAPI
01451 png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
01452    write_user_transform_fn)
01453 {
01454    png_debug(1, "in png_set_write_user_transform_fn\n");
01455    if (png_ptr == NULL)
01456       return;
01457    png_ptr->transformations |= PNG_USER_TRANSFORM;
01458    png_ptr->write_user_transform_fn = write_user_transform_fn;
01459 }
01460 #endif
01461 
01462 
01463 #if defined(PNG_INFO_IMAGE_SUPPORTED)
01464 void PNGAPI
01465 png_write_png(png_structp png_ptr, png_infop info_ptr,
01466               int transforms, voidp params)
01467 {
01468    if (png_ptr == NULL || info_ptr == NULL)
01469       return;
01470 #if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
01471    /* invert the alpha channel from opacity to transparency */
01472    if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
01473        png_set_invert_alpha(png_ptr);
01474 #endif
01475 
01476    /* Write the file header information. */
01477    png_write_info(png_ptr, info_ptr);
01478 
01479    /* ------ these transformations don't touch the info structure ------- */
01480 
01481 #if defined(PNG_WRITE_INVERT_SUPPORTED)
01482    /* invert monochrome pixels */
01483    if (transforms & PNG_TRANSFORM_INVERT_MONO)
01484        png_set_invert_mono(png_ptr);
01485 #endif
01486 
01487 #if defined(PNG_WRITE_SHIFT_SUPPORTED)
01488    /* Shift the pixels up to a legal bit depth and fill in
01489     * as appropriate to correctly scale the image.
01490     */
01491    if ((transforms & PNG_TRANSFORM_SHIFT)
01492                && (info_ptr->valid & PNG_INFO_sBIT))
01493        png_set_shift(png_ptr, &info_ptr->sig_bit);
01494 #endif
01495 
01496 #if defined(PNG_WRITE_PACK_SUPPORTED)
01497    /* pack pixels into bytes */
01498    if (transforms & PNG_TRANSFORM_PACKING)
01499        png_set_packing(png_ptr);
01500 #endif
01501 
01502 #if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
01503    /* swap location of alpha bytes from ARGB to RGBA */
01504    if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
01505        png_set_swap_alpha(png_ptr);
01506 #endif
01507 
01508 #if defined(PNG_WRITE_FILLER_SUPPORTED)
01509    /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
01510     * RGB (4 channels -> 3 channels). The second parameter is not used.
01511     */
01512    if (transforms & PNG_TRANSFORM_STRIP_FILLER)
01513        png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
01514 #endif
01515 
01516 #if defined(PNG_WRITE_BGR_SUPPORTED)
01517    /* flip BGR pixels to RGB */
01518    if (transforms & PNG_TRANSFORM_BGR)
01519        png_set_bgr(png_ptr);
01520 #endif
01521 
01522 #if defined(PNG_WRITE_SWAP_SUPPORTED)
01523    /* swap bytes of 16-bit files to most significant byte first */
01524    if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
01525        png_set_swap(png_ptr);
01526 #endif
01527 
01528 #if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
01529    /* swap bits of 1, 2, 4 bit packed pixel formats */
01530    if (transforms & PNG_TRANSFORM_PACKSWAP)
01531        png_set_packswap(png_ptr);
01532 #endif
01533 
01534    /* ----------------------- end of transformations ------------------- */
01535 
01536    /* write the bits */
01537    if (info_ptr->valid & PNG_INFO_IDAT)
01538        png_write_image(png_ptr, info_ptr->row_pointers);
01539 
01540    /* It is REQUIRED to call this to finish writing the rest of the file */
01541    png_write_end(png_ptr, info_ptr);
01542 
01543    transforms = transforms; /* quiet compiler warnings */
01544    params = params;
01545 }
01546 #endif
01547 #endif /* PNG_WRITE_SUPPORTED */


openhrp3
Author(s): AIST, General Robotix Inc., Nakamura Lab of Dept. of Mechano Informatics at University of Tokyo
autogenerated on Thu Apr 11 2019 03:30:18