Back to index

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