ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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

Generated on Sun May 27 2012 04:19:32 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.