CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/ext/libpng17/pngwrite.c
Views: 1401
1/* pngwrite.c - general routines to write a PNG file2*3* Last changed in libpng 1.7.0 [(PENDING RELEASE)]4* Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson5* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)6* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)7*8* This code is released under the libpng license.9* For conditions of distribution and use, see the disclaimer10* and license in png.h11*/1213#include "pngpriv.h"14#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED15# include <errno.h>16#endif /* SIMPLIFIED_WRITE_STDIO */1718#define PNG_SRC_FILE PNG_SRC_FILE_pngwrite1920#ifdef PNG_WRITE_SUPPORTED2122#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED23/* Write out all the unknown chunks for the current given location */24static void25write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr,26unsigned int where)27{28if (info_ptr->unknown_chunks_num != 0)29{30png_const_unknown_chunkp up;3132png_debug(5, "writing extra chunks");3334for (up = info_ptr->unknown_chunks;35up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;36++up)37if ((up->location & where) != 0)38{39/* If per-chunk unknown chunk handling is enabled use it, otherwise40* just write the chunks the application has set.41*/42#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED43int keep = png_handle_as_unknown(png_ptr, up->name);4445/* NOTE: this code is radically different from the read side in the46* matter of handling an ancillary unknown chunk. In the read side47* the default behavior is to discard it, in the code below the default48* behavior is to write it. Critical chunks are, however, only49* written if explicitly listed or if the default is set to write all50* unknown chunks.51*52* The default handling is also slightly weird - it is not possible to53* stop the writing of all unsafe-to-copy chunks!54*55* TODO: REVIEW: this would seem to be a bug.56*/57if (keep != PNG_HANDLE_CHUNK_NEVER &&58((up->name[3] & 0x20) /* safe-to-copy overrides everything */ ||59keep == PNG_HANDLE_CHUNK_ALWAYS ||60(keep == PNG_HANDLE_CHUNK_AS_DEFAULT &&61png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS)))62#endif63png_write_chunk(png_ptr, up->name, up->data, up->size);64}65}66}67#endif /* WRITE_UNKNOWN_CHUNKS */6869#ifdef PNG_WRITE_TEXT_SUPPORTED70static void71png_write_text(png_structrp png_ptr, png_const_inforp info_ptr, png_byte where)72/* Text chunk helper */73{74int i;7576/* Check to see if we need to write text chunks */77for (i = 0; i < info_ptr->num_text; i++)78{79png_debug2(2, "Writing text chunk %d, type %d", i,80info_ptr->text[i].compression);8182/* Text chunks are written at info_ptr->text[i].location, skip the chunk83* if we are not writing at that location:84*/85if ((info_ptr->text[i].location & where) == 0U)86continue;8788switch (info_ptr->text[i].compression)89{90case PNG_ITXT_COMPRESSION_NONE:91case PNG_ITXT_COMPRESSION_zTXt:92# ifdef PNG_WRITE_iTXt_SUPPORTED93/* Write international chunk */94png_write_iTXt(png_ptr, info_ptr->text[i].compression,95info_ptr->text[i].key, info_ptr->text[i].lang,96info_ptr->text[i].lang_key, info_ptr->text[i].text);97# else /* !WRITE_iTXT */98png_app_error(png_ptr, "Unable to write international text");99# endif /* !WRITE_iTXT */100break;101102case PNG_TEXT_COMPRESSION_zTXt:103# ifdef PNG_WRITE_zTXt_SUPPORTED104/* Write compressed chunk */105png_write_zTXt(png_ptr, info_ptr->text[i].key,106info_ptr->text[i].text, info_ptr->text[i].compression);107# else /* !WRITE_zTXT */108png_app_error(png_ptr, "Unable to write compressed text");109# endif /* !WRITE_zTXT */110break;111112case PNG_TEXT_COMPRESSION_NONE:113# ifdef PNG_WRITE_tEXt_SUPPORTED114/* Write uncompressed chunk */115png_write_tEXt(png_ptr, info_ptr->text[i].key,116info_ptr->text[i].text, 0);117# else /* !WRITE_tEXt */118/* Can't get here TODO: why not? */119png_app_error(png_ptr, "Unable to write uncompressed text");120# endif /* !WRITE_tEXt */121break;122123default:124/* This is an internal error because the libpng checking should125* never manage to set any 'compression' except the above values.126*/127impossible("invalid text compression");128}129130/* The chunk was written, record where. This allows the location to have131* multiple bits set; the first successful write freezes the location.132*/133info_ptr->text[i].location = where;134}135}136#endif /* WRITE_TEXT */137138/* Writes all the PNG information. This is the suggested way to use the139* library. If you have a new chunk to add, make a function to write it,140* and put it in the correct location here. If you want the chunk written141* after the image data, put it in png_write_end(). I strongly encourage142* you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing143* the chunk, as that will keep the code from breaking if you want to just144* write a plain PNG file. If you have long comments, I suggest writing145* them in png_write_end(), and compressing them.146*/147void PNGAPI148png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)149{150png_debug(1, "in png_write_info_before_PLTE");151152if (png_ptr == NULL || info_ptr == NULL)153return;154155if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)156{157int color_type = PNG_COLOR_TYPE_FROM_FORMAT(info_ptr->format);158159/* Write PNG signature; doesn't set PNG_HAVE_PNG_SIGNATURE if it has160* already been written (or rather, if at least 3 bytes have already been161* written; undocumented wackiness, it means the 'PNG' at the start can be162* replace by, e.g. "FOO" or "BAR" or "MNG").163*/164png_write_sig(png_ptr);165166# ifdef PNG_MNG_FEATURES_SUPPORTED167if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 &&168png_ptr->mng_features_permitted != 0)169{170png_app_error(png_ptr,171"MNG features are not allowed in a PNG datastream");172/* Recovery: disable MNG features: */173png_ptr->mng_features_permitted = 0;174}175# endif /* MNG_FEATURES */176177/* Write IHDR information. */178png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,179info_ptr->bit_depth, color_type, info_ptr->compression_type,180info_ptr->filter_type, info_ptr->interlace_type);181182# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED183/* This are used for checking later on: */184png_ptr->info_format = info_ptr->format;185# endif /* WRITE_TRANSFORMS */186187/* This sets the flag that prevents re-entry to the 'before PLTE' case: */188affirm((png_ptr->mode & PNG_HAVE_IHDR) != 0);189190/* The rest of these check to see if the valid field has the appropriate191* flag set, and if it does, writes the chunk.192*193* 1.6.0: COLORSPACE support controls the writing of these chunks too, and194* the chunks will be written if the WRITE routine is there and195* information is available in the COLORSPACE. (See196* png_colorspace_sync_info in png.c for where the valid flags get set.)197*198* Under certain circumstances the colorspace can be invalidated without199* syncing the info_struct 'valid' flags; this happens if libpng detects200* an error and calls png_error while the color space is being set, yet201* the application continues writing the PNG. So check the 'invalid'202* flag here too.203*/204# ifdef PNG_WRITE_tIME_SUPPORTED205if ((info_ptr->valid & PNG_INFO_tIME) != 0 &&206(info_ptr->time_location & PNG_HAVE_IHDR) != 0)207png_write_tIME(png_ptr, &(info_ptr->mod_time));208# endif /* WRITE_tIME */209210# ifdef PNG_WRITE_gAMA_SUPPORTED /* enables GAMMA */211if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&212(info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 &&213(info_ptr->valid & PNG_INFO_gAMA) != 0)214{215/* This is the inverse of the test in png.c: */216affirm(info_ptr->colorspace.gamma >= 16 &&217info_ptr->colorspace.gamma <= 625000000);218png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma);219}220# endif /* WRITE_gAMA */221222/* Write only one of sRGB or an ICC profile. If a profile was supplied223* and it matches one of the known sRGB ones issue a warning.224*/225# ifdef PNG_WRITE_iCCP_SUPPORTED /* enables COLORSPACE, GAMMA */226if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&227(info_ptr->valid & PNG_INFO_iCCP) != 0)228{229# ifdef PNG_WRITE_sRGB_SUPPORTED230/* The app must have supplied an sRGB iCCP profile (and one that231* is recognized and therefore known to be correct) so we write232* that profile, even though it increases the size of the PNG233* significantly. A warning is reasonable:234*/235if ((info_ptr->valid & PNG_INFO_sRGB) != 0)236png_app_warning(png_ptr,237"profile matches sRGB but writing iCCP instead");238# endif /* WRITE_sRGB */239240png_write_iCCP(png_ptr, info_ptr->iccp_name,241info_ptr->iccp_profile);242}243# ifdef PNG_WRITE_sRGB_SUPPORTED244else /* iCCP not written */245# endif /* WRITE_sRGB */246# endif /* WRITE_iCCP */247248# ifdef PNG_WRITE_sRGB_SUPPORTED /* enables COLORSPACE, GAMMA */249if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&250(info_ptr->valid & PNG_INFO_sRGB) != 0)251png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent);252# endif /* WRITE_sRGB */253254# ifdef PNG_WRITE_sBIT_SUPPORTED255if ((info_ptr->valid & PNG_INFO_sBIT) != 0)256png_write_sBIT(png_ptr, &(info_ptr->sig_bit), color_type);257# endif /* WRITE_sBIT */258259# ifdef PNG_WRITE_cHRM_SUPPORTED /* enables COLORSPACE */260if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&261(info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 &&262(info_ptr->valid & PNG_INFO_cHRM) != 0)263png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy);264# endif /* WRITE_cHRM */265266# ifdef PNG_WRITE_TEXT_SUPPORTED267if (info_ptr->num_text > 0)268png_write_text(png_ptr, info_ptr, PNG_HAVE_IHDR);269# endif /* WRITE_TEXT */270271# ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED272/* The third arugment must encode only one bit, otherwise chunks will273* be written twice because the test in write_unknown_chunks is274* 'location & where'.275*/276write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR);277# endif278}279280else /* 1.7.0: flag multiple calls; previously ignored */281png_app_error(png_ptr,282"png_write_info_before_PLTE called more than once");283}284285void PNGAPI286png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)287{288png_debug(1, "in png_write_info");289290if (png_ptr == NULL || info_ptr == NULL)291return;292293if ((png_ptr->mode & (PNG_HAVE_PLTE+PNG_HAVE_IDAT)) != 0)294{295png_app_error(png_ptr, "late call to png_write_info");296return;297}298299/* The app may do this for us, and in 1.7.0 multiple calls are flagged as an300* application error, so this code must check:301*/302if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)303png_write_info_before_PLTE(png_ptr, info_ptr);304305if ((info_ptr->valid & PNG_INFO_PLTE) != 0)306png_write_PLTE(png_ptr, info_ptr->palette, info_ptr->num_palette);307308/* Validate the consistency of the PNG being produced; a palette must have309* been written if a palette mapped PNG is to be valid:310*/311if ((png_ptr->mode & PNG_HAVE_PLTE) == 0 &&312png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)313png_error(png_ptr, "Valid palette required for paletted images");314315/* But always set the mode flag because without this we don't know when to316* write the post-palette text or unknown chunks.317*/318png_ptr->mode |= PNG_HAVE_PLTE;319320# ifdef PNG_WRITE_tRNS_SUPPORTED321if ((info_ptr->valid & PNG_INFO_tRNS) !=0)322{323png_write_tRNS(png_ptr, info_ptr->trans_alpha,324&(info_ptr->trans_color), info_ptr->num_trans,325PNG_COLOR_TYPE_FROM_FORMAT(info_ptr->format));326}327# endif /* WRITE_tRNS */328329# ifdef PNG_WRITE_bKGD_SUPPORTED330if ((info_ptr->valid & PNG_INFO_bKGD) != 0)331png_write_bKGD(png_ptr, &(info_ptr->background),332PNG_COLOR_TYPE_FROM_FORMAT(info_ptr->format));333# endif /* WRITE_bKGD */334335# ifdef PNG_WRITE_hIST_SUPPORTED336if ((info_ptr->valid & PNG_INFO_hIST) != 0)337png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);338# endif /* WRITE_hIST */339340# ifdef PNG_WRITE_oFFs_SUPPORTED341if ((info_ptr->valid & PNG_INFO_oFFs) != 0)342png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,343info_ptr->offset_unit_type);344# endif /* WRITE_oFFs */345346# ifdef PNG_WRITE_pCAL_SUPPORTED347if ((info_ptr->valid & PNG_INFO_pCAL) != 0)348png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,349info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,350info_ptr->pcal_units, info_ptr->pcal_params);351# endif /* WRITE_pCAL */352353# ifdef PNG_WRITE_sCAL_SUPPORTED354if ((info_ptr->valid & PNG_INFO_sCAL) != 0)355png_write_sCAL_s(png_ptr, info_ptr->scal_unit, info_ptr->scal_s_width,356info_ptr->scal_s_height);357# endif /* WRITE_sCAL */358359# ifdef PNG_WRITE_pHYs_SUPPORTED360if ((info_ptr->valid & PNG_INFO_pHYs) != 0)361png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,362info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);363# endif /* WRITE_pHYs */364365# ifdef PNG_WRITE_tIME_SUPPORTED366if ((info_ptr->valid & PNG_INFO_tIME) != 0 &&367(info_ptr->time_location & PNG_HAVE_PLTE) != 0)368png_write_tIME(png_ptr, &(info_ptr->mod_time));369# endif /* WRITE_tIME */370371# ifdef PNG_WRITE_sPLT_SUPPORTED372if ((info_ptr->valid & PNG_INFO_sPLT) != 0)373{374int i;375376for (i = 0; i < info_ptr->splt_palettes_num; i++)377png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);378}379# endif /* WRITE_sPLT */380381# ifdef PNG_WRITE_TEXT_SUPPORTED382if (info_ptr->num_text > 0)383png_write_text(png_ptr, info_ptr, PNG_HAVE_PLTE);384# endif /* WRITE_TEXT */385386# ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED387write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE);388# endif /* WRITE_UNKNOWN_CHUNKS */389}390391/* Writes the end of the PNG file. If you don't want to write comments or392* time information, you can pass NULL for info. If you already wrote these393* in png_write_info(), do not write them again here. If you have long394* comments, I suggest writing them here, and compressing them.395*/396void PNGAPI397png_write_end(png_structrp png_ptr, png_inforp info_ptr)398{399png_debug(1, "in png_write_end");400401if (png_ptr == NULL)402return;403404if ((png_ptr->mode &405(PNG_HAVE_IHDR+PNG_HAVE_IDAT+PNG_AFTER_IDAT+PNG_HAVE_IEND)) !=406(PNG_HAVE_IHDR+PNG_HAVE_IDAT+PNG_AFTER_IDAT))407{408/* Out of place png_write_end: */409if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)410png_error(png_ptr, "Missing call to png_write_info");411412else if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && png_ptr->zowner == 0)413{414/* TODO: write unknown IDAT here, for the moment allow the app to write415* IDAT then call write_end:416*/417png_app_error(png_ptr, "No IDATs written into file");418png_ptr->mode |= PNG_HAVE_IDAT+PNG_AFTER_IDAT;419}420421else if ((png_ptr->mode & PNG_AFTER_IDAT) == 0)422{423affirm(png_ptr->zowner == png_IDAT);424png_error(png_ptr, "incomplete PNG image"); /* unrecoverable */425}426427else if ((png_ptr->mode & PNG_HAVE_IEND) != 0)428{429png_app_error(png_ptr, "multiple calls to png_write_end");430return;431}432433else434impossible("not reached");435}436437/* And double check that the image rows were all written; this is actually438* a harmless error on an interlaced image because the image rows with439* data were all passed in or the above check would not work.440*441* Don't do this if the IDAT came from unknowns (TBD) or the app, above.442*443* The check depends on the precise logic in png_write_row.444*/445else if (png_ptr->pass != 7U)446png_app_error(png_ptr, "png_write_row not called to last row");447448else449debug(png_ptr->row_number == 0U);450451/* See if user wants us to write information chunks */452if (info_ptr != NULL)453{454# ifdef PNG_WRITE_tIME_SUPPORTED455/* Check to see if user has supplied a time chunk */456if ((info_ptr->valid & PNG_INFO_tIME) != 0 &&457(info_ptr->time_location & PNG_AFTER_IDAT) != 0)458png_write_tIME(png_ptr, &(info_ptr->mod_time));459# endif460461# ifdef PNG_WRITE_TEXT_SUPPORTED462if (info_ptr->num_text > 0)463png_write_text(png_ptr, info_ptr, PNG_AFTER_IDAT);464# endif /* WRITE_TEXT */465466# ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED467write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT);468# endif469}470471/* Write end of PNG file */472png_write_IEND(png_ptr);473474/* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03,475* and restored again in libpng-1.2.30, may cause some applications that476* do not set png_ptr->output_flush_fn to crash. If your application477* experiences a problem, please try building libpng with478* PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to479* png-mng-implement at lists.sf.net .480*/481# ifdef PNG_WRITE_FLUSH_SUPPORTED482# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED483if (png_ptr->output_flush_fn != NULL)484png_ptr->output_flush_fn(png_ptr);485# endif486# endif487}488489#ifdef PNG_CONVERT_tIME_SUPPORTED490void PNGAPI491png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime)492{493png_debug(1, "in png_convert_from_struct_tm");494495ptime->year = png_check_u16(0/*TODO: fixme*/, 1900 + ttime->tm_year);496ptime->month = png_check_byte(0/*TODO: fixme*/, ttime->tm_mon + 1);497ptime->day = png_check_byte(0/*TODO: fixme*/, ttime->tm_mday);498ptime->hour = png_check_byte(0/*TODO: fixme*/, ttime->tm_hour);499ptime->minute = png_check_byte(0/*TODO: fixme*/, ttime->tm_min);500ptime->second = png_check_byte(0/*TODO: fixme*/, ttime->tm_sec);501}502503void PNGAPI504png_convert_from_time_t(png_timep ptime, time_t ttime)505{506struct tm *tbuf;507508png_debug(1, "in png_convert_from_time_t");509510tbuf = gmtime(&ttime);511png_convert_from_struct_tm(ptime, tbuf);512}513#endif514515/* Initialize png_ptr structure, and allocate any memory needed */516PNG_FUNCTION(png_structp,PNGAPI517png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr,518png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)519{520#ifndef PNG_USER_MEM_SUPPORTED521png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,522error_fn, warn_fn, NULL, NULL, NULL);523#else524return png_create_write_struct_2(user_png_ver, error_ptr, error_fn,525warn_fn, NULL, NULL, NULL);526}527528/* Alternate initialize png_ptr structure, and allocate any memory needed */529PNG_FUNCTION(png_structp,PNGAPI530png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,531png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,532png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)533{534png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr,535error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);536#endif /* USER_MEM */537538if (png_ptr != NULL)539{540# ifdef PNG_BENIGN_ERRORS_SUPPORTED541# if !PNG_RELEASE_BUILD542/* Always quit on error prior to release */543png_ptr->benign_error_action = PNG_ERROR;544png_ptr->app_warning_action = PNG_WARN;545png_ptr->app_error_action = PNG_ERROR;546# else /* RELEASE_BUILD */547/* Allow benign errors on write, subject to app control. */548# ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED549png_ptr->benign_error_action = PNG_WARN;550png_ptr->app_error_action = PNG_WARN;551png_ptr->app_warning_action = PNG_WARN;552# else /* !BENIGN_WRITE_ERRORS */553/* libpng build without benign error support; the application554* author has to be assumed to be correct, so:555*/556png_ptr->benign_error_action = PNG_ERROR;557png_ptr->app_warning_action = PNG_WARN;558png_ptr->app_error_action = PNG_ERROR;559# endif /* !BENIGN_WRITE_ERRORS */560# endif /* RELEASE_BUILD */561# endif /* BENIGN_ERRORS */562}563564return png_ptr;565}566567568#if defined(PNG_WRITE_INTERLACING_SUPPORTED) ||\569defined(PNG_WRITE_TRANSFORMS_SUPPORTED)570static void571write_row_buffered(png_structrp png_ptr,572png_const_bytep row, unsigned int row_info_flags,573void (*copy_fn)(png_const_structrp png_ptr, png_bytep row_buffer,574png_const_bytep row, png_uint_32 x, unsigned int count, unsigned int p),575unsigned int copy_parameter)576{577unsigned int max_pixels = png_max_pixel_block(png_ptr);578const unsigned int pass = png_ptr->pass;579const png_uint_32 width = png_ptr->interlaced == PNG_INTERLACE_NONE ?580png_ptr->width : PNG_PASS_COLS(png_ptr->width, pass);581png_uint_32 x;582png_byte prev_pixels[4*2*2]; /* 2 pixels up to 4 2-byte channels each */583584memset(prev_pixels, 0U, sizeof prev_pixels);585586for (x = 0U; x < width; x += max_pixels)587{588union589{590PNG_ROW_BUFFER_ALIGN_TYPE force_buffer_alignment;591png_byte buffer[PNG_ROW_BUFFER_SIZE];592} pixel_buffer;593594if (max_pixels > width - x)595max_pixels = (unsigned int)/*SAFE*/(width - x);596597debug((row_info_flags & png_row_end) == 0U); /* must be set here at end */598if (x + max_pixels >= width)599row_info_flags |= png_row_end;600601/* Copy a block of input pixels into the buffer, effecting the interlace602* on the way if required. The argument is the number of pixels in the603* buffer, not the number handled from the input which will be larger in604* the interlaced case.605*/606copy_fn(png_ptr, pixel_buffer.buffer, row, x, max_pixels, copy_parameter);607608/* Now pixel_buffer[0..max_pixels-1] contains max_pixels pixels which may609* need to be transformed (the interlace has already been handled).610*/611# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED612if (png_ptr->transform_list != NULL)613{614png_transform_control tc;615616/* The initial values are the memory format; this was worked out in617* png_init_row_info below.618*/619memset(&tc, 0, sizeof tc);620tc.png_ptr = png_ptr;621tc.sp = tc.dp = pixel_buffer.buffer;622623tc.width = max_pixels; /* width of block that we have */624tc.format = png_ptr->row_format;625tc.range = png_ptr->row_range;626tc.bit_depth = png_ptr->row_bit_depth;627/* tc.init == 0 */628/* tc.caching: not used */629/* tc.palette: not used */630debug(PNG_TC_PIXEL_DEPTH(tc) == png_ptr->row_input_pixel_depth);631632/* Run the list. */633png_run_transform_list_backwards(png_ptr, &tc);634635/* Make sure the format that resulted is compatible with PNG: */636affirm((tc.format & PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA +637PNG_FORMAT_FLAG_COLOR + PNG_FORMAT_FLAG_LINEAR +638PNG_FORMAT_FLAG_COLORMAP)) == 0);639640/* Now we must have the PNG format from the IHDR: */641affirm(png_ptr->bit_depth == tc.bit_depth &&642png_ptr->color_type == PNG_COLOR_TYPE_FROM_FORMAT(tc.format));643}644# endif /* WRITE_TRANSFORMS */645646/* Call png_write_png_data to write this block of data, the test on647* maxpixels says if this is the final block in the row.648*/649png_write_png_data(png_ptr, prev_pixels, pixel_buffer.buffer, x,650max_pixels, row_info_flags);651}652}653#endif /* WRITE { INTERLACING || TRANSFORMS } */654655#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED656static void657copy_row(png_const_structrp png_ptr, png_bytep row_buffer,658png_const_bytep row, png_uint_32 x, unsigned int count,659unsigned int pixel_depth)660{661/* Copy row[x..x+count] pixels to row_buffer. */662png_copy_row(png_ptr, row_buffer, row, x, count, pixel_depth, 1/*clear*/,6630/* x_in_dest; row[x]->row_buffer */);664}665#endif /* WRITE_TRANSFORMS */666667#ifdef PNG_WRITE_INTERLACING_SUPPORTED668static void669interlace_row_lbd(png_const_structrp png_ptr, png_bytep dp, png_const_bytep sp,670png_uint_32 x, unsigned int count, const unsigned int B)671{672/* Pick out the correct pixels for the interlace pass. The basic idea here673* is to go through the row with a source pointer and a destination pointer674* (sp and dp), and copy the correct pixels for the pass. As the row gets675* compacted, sp will always be >= dp, so we should never overwrite anything.676* See the default: case for the easiest code to understand.677*/678const unsigned int pass = png_ptr->pass;679png_uint_32 i = PNG_COL_FROM_PASS_COL(x, pass);680const unsigned int inc = PNG_PASS_COL_OFFSET(pass);681682/* For pixels less than one byte wide the correct pixels have to be683* extracted from the input bytes. Because we are reading data in684* the application memory format we cannot rely on the PNG big685* endian order. Notice that this was apparently broken before686* 1.7.0.687*688* In libpng 1.7.0 libpng uses a classic bit-pump to optimize the689* extraction. In all passes before the last (6/7) no two pixels690* are adjacent in the input, so we are always extracting 1 bit.691* At present the code uses an 8-bit buffer to avoid coding for692* different byte sexes, but this could easily be changed.693*694* 'i' is the bit-index of bit in the input (sp[]), so,695* considering the 1-bit per pixel case, sp[i>>3] is the byte696* and the bit is bit (i&7) (0 lowest) on swapped (little endian)697* data or 7-(i&7) on PNG default (big-endian) data.698*699* Define these macros, where:700*701* B: the log2 bit depth (0, 1, 2 for 1bpp, 2bpp or 4bpp) of702* the data; this should be a constant.703* sp: the source pointer (sp) (a png_const_bytep)704* i: the pixel index in the input (png_uint_32)705* j: the bit index in the output (unsigned int)706*707* Unlike 'i', 'j' is interpreted directly; for LSB bytes it counts708* up, for MSB it counts down.709*710* NOTE: this could all be expanded to eliminate the code below by711* the time honoured copy'n'paste into three separate functions. This712* might be worth doing in the future.713*/714# define PIXEL_MASK ((1U << (1<<B))-1U)715# define BIT_MASK ((1U << (3-(B)))-1U) /* within a byte */716# define SP_BYTE (sp[i>>(3-(B))]) /* byte to use */717# define SP_OFFSET_LSB ((BIT_MASK & i) << (B))718# define SP_OFFSET_MSB ((BIT_MASK & ~i) << (B))719# define SP_PIXEL(sex) ((SP_BYTE >> SP_OFFSET_ ## sex) & PIXEL_MASK)720{721unsigned int j;722unsigned int d;723724/* The data is always in the PNG, big-endian, format: */725for (j = 8U, d = 0U; count > 0U; --count, i += inc)726{ /* big-endian */727j -= 1U<<B;728d |= SP_PIXEL(MSB) << j;729if (j == 0U) *dp++ = png_check_byte(png_ptr, d), j = 8U, d = 0U;730}731732/* The end condition: if j is not 0 the last byte was not733* written:734*/735if (j != 0U) *dp = png_check_byte(png_ptr, d);736}737# undef PIXEL_MASK738# undef BIT_MASK739# undef SP_BYTE740# undef SP_OFFSET_MSB741# undef SP_OFFSET_LSB742# undef SP_PIXEL743}744745static void746interlace_row_byte(png_const_structrp png_ptr, png_bytep dp, png_const_bytep sp,747png_uint_32 x, unsigned int count, unsigned int cbytes)748{749const unsigned int pass = png_ptr->pass;750const unsigned int inc = PNG_PASS_COL_OFFSET(pass);751752/* Loop through the input copying each pixel to the correct place753* in the output. Note that the loop may be executed 0 times if754* this is called on a narrow image that does not contain this755* pass.756*/757for (sp += PNG_COL_FROM_PASS_COL(x, pass) * cbytes; count > 0;758--count, sp += inc * cbytes, dp += cbytes)759memcpy(dp, sp, cbytes);760}761#endif /* WRITE_INTERLACING */762763#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED764static void765write_row_core(png_structrp png_ptr, png_const_bytep row,766unsigned int row_info_flags)767{768# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED769if (png_ptr->transform_list != NULL)770write_row_buffered(png_ptr, row, row_info_flags,771copy_row, png_ptr->row_input_pixel_depth);772773else774# endif /* WRITE_TRANSFORMS */775776/* If control reaches this point the intermediate buffer is not required and777* the input data can be used unmodified.778*/779png_write_png_rows(png_ptr, &row, 1U);780PNG_UNUSED(row_info_flags)781}782783/* Write a single non-interlaced row. */784static void785write_row_non_interlaced(png_structrp png_ptr, png_const_bytep row)786{787const png_uint_32 row_number = png_ptr->row_number+1U;788/* There is only one pass, so this is the last pass: */789const unsigned int row_info_flags =790(row_number == 1U ? png_pass_first_row : 0) |791(row_number >= png_ptr->height ? png_pass_last_row : 0) |792png_pass_last;793794debug(png_ptr->interlaced == PNG_INTERLACE_NONE);795796write_row_core(png_ptr, row, row_info_flags);797}798799/* Write a single interlaced row. */800static void801write_row_interlaced(png_structrp png_ptr, png_const_bytep row)802{803const png_uint_32 row_number = png_ptr->row_number+1U;804const png_uint_32 height = png_ptr->height;805const unsigned int pass = png_ptr->pass;806const unsigned int row_info_flags =807(row_number == 1U ? png_pass_first_row : 0) |808(row_number == PNG_PASS_ROWS(height, pass) ? png_pass_last_row : 0) |809(pass == PNG_LAST_PASS(png_ptr->width, height) ? png_pass_last : 0);810811# ifdef PNG_WRITE_INTERLACING_SUPPORTED812/* Check that libpng is not doing the interlace: */813debug(png_ptr->interlaced != PNG_INTERLACE_NONE &&814!png_ptr->do_interlace);815# endif /* WRITE_INTERLACING */816817write_row_core(png_ptr, row, row_info_flags);818}819#endif /* WRITE_TRANSFORMS */820821#ifdef PNG_WRITE_INTERLACING_SUPPORTED822/* Interlace a row then write it out. */823static void824interlace_row(png_structrp png_ptr, png_const_bytep row)825{826/* The row may not exist in the image (for this pass). */827const png_uint_32 row_number = png_ptr->row_number; /* in image */828const unsigned int pass = png_ptr->pass;829830if (png_ptr->width > PNG_PASS_START_COL(pass) &&831PNG_ROW_IN_INTERLACE_PASS(row_number, pass))832{833const unsigned int row_info_flags =834(row_number == PNG_PASS_START_ROW(pass) ? png_pass_first_row : 0) |835(PNG_LAST_PASS_ROW(row_number, pass, png_ptr->height) ?836png_pass_last_row : 0) |837(pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height) ?838png_pass_last : 0);839840if (pass < 6)841{842/* Libpng is doing the interlacing and pixels need to be selected843* from the input row for this pass.844*/845/* row interlacing uses either the log bit depth for low bit846* depth input or the byte count for 8bpp or bigger pixels.847*/848const unsigned int input_depth = png_ptr->row_input_pixel_depth;849unsigned int B = 0; /* log2(input_depth) */850851switch (input_depth)852{853case 4U: /* B will be 2 */854++B;855/*FALL THROUGH*/856case 2U: /* B will be 1 */857++B;858/*FALL THROUGH*/859case 1U: /* B will be 0 */860write_row_buffered(png_ptr, row, row_info_flags,861interlace_row_lbd, B);862break;863864default: /* Parameter is the pixel size in bytes */865write_row_buffered(png_ptr, row, row_info_flags,866interlace_row_byte, input_depth >> 3);867break;868}869} /* pass < 6 */870871else /* pass 6: no interlacing required */872write_row_core(png_ptr, row, row_info_flags);873}874875else876{877/* This code must advance row_number/pass itself; the row has been878* skipped.879*/880if (row_number+1U < png_ptr->height)881png_ptr->row_number = row_number+1U;882883else884{885png_ptr->row_number = 0U;886png_ptr->pass = 0x7U & (pass+1U);887}888}889}890#endif /* WRITE_INTERLACING */891892/* Bottleneck API to actually write a number of rows, only exists because the893* rows parameter to png_write_rows is wrong.894*/895static void896png_write_rows_internal(png_structrp png_ptr, png_const_bytep *rows,897png_uint_32 num_rows)898{899if (png_ptr != NULL && num_rows > 0U && rows != NULL)900{901/* Unlike the read code initialization happens automatically: */902if (png_ptr->row_number == 0U && png_ptr->pass == 0U)903{904png_init_row_info(png_ptr);905906# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED907/* If the app takes a png_info from a read operation and if the app has908* performed transforms on the data the png_info can contain IHDR909* information that cannot be represented in PNG. The code that writes910* the IHDR takes the color type from the png_info::format. The app911* adds transforms, before or after writing the IHDR, then the IHDR912* color_type stored in png_struct::color_type is used in913* png_init_row_info above to work out the actual row format.914*915* Prior to 1.7.0 this was not verified (there was no easy way to do916* so). Now we can check it here, however this is an:917*918* API CHANGE: in 1.7.0 an error may be flagged against bogus919* info_struct formats even though the app had removed them itself.920* It's just a warning at present.921*922* The test is that either the row_format produced by the write923* transforms exactly matches that in the original info_struct::format924* or that the info_struct::format was a simple mapping of the925* color_type that ended up in the IHDR:926*/927if (png_ptr->row_format != png_ptr->info_format &&928PNG_FORMAT_FROM_COLOR_TYPE(png_ptr->color_type) !=929png_ptr->info_format)930png_app_warning(png_ptr, "info_struct format does not match IHDR");931# endif /* WRITE_TRANSFORMS */932933/* Perform initialization required before IDATs are written. */934png_write_start_IDAT(png_ptr);935}936937else if (png_ptr->pass >= 7U) /* too many calls; write already ended */938{939debug(png_ptr->row_number == 0U);940png_app_error(png_ptr, "Too many calls to png_write_row");941return;942}943944/* The remainder of these tests detect internal errors in libpng */945else if (png_ptr->interlaced == PNG_INTERLACE_NONE)946affirm(png_ptr->row_number < png_ptr->height && png_ptr->pass == 0U);947948# ifdef PNG_WRITE_INTERLACING_SUPPORTED949else if (png_ptr->do_interlace)950affirm(png_ptr->row_number < png_ptr->height);951# endif /* WRITE_INTERLACING */952953else /* app does interlace */954affirm(955PNG_PASS_IN_IMAGE(png_ptr->width, png_ptr->height, png_ptr->pass) &&956png_ptr->row_number < PNG_PASS_ROWS(png_ptr->height, png_ptr->pass)957);958959/* First handle rows that require buffering because of the need to960* interlace them or the need to perform write transforms.961*/962# ifdef PNG_WRITE_INTERLACING_SUPPORTED963/* libpng is doing the interlacing, but this only makes a difference to964* the first six passes (numbered, in libpng, 0..5); the seventh pass965* (numbered 6 by libpng) consists of complete image rows.966*/967if (png_ptr->do_interlace) while (num_rows > 0U && png_ptr->pass < 6)968interlace_row(png_ptr, *rows++), --num_rows;969# endif /* WRITE_INTERLACING */970971# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED972/* Transforms required however the row interlacing has already been973* handled and we have a complete (PNG) row.974*/975if (png_ptr->transform_list != NULL)976{977if (png_ptr->interlaced == PNG_INTERLACE_NONE)978while (num_rows > 0U)979write_row_non_interlaced(png_ptr, *rows++), --num_rows;980981# ifdef PNG_WRITE_INTERLACING_SUPPORTED982else if (png_ptr->do_interlace)983while (num_rows > 0U)984interlace_row(png_ptr, *rows++), --num_rows;985# endif /* WRITE_INTERLACING */986987else /* app does the interlacing */988while (num_rows > 0U)989write_row_interlaced(png_ptr, *rows++), --num_rows;990}991# endif /* WRITE_TRANSFORMS */992993/* Finally handle any remaining rows that require no (libpng) interlace994* and no transforms.995*/996if (num_rows > 0U)997png_write_png_rows(png_ptr, rows, num_rows);998999/* Repeat the checks above, but allow for end-of-image. */1000if (png_ptr->pass < 7U)1001{1002if (png_ptr->interlaced == PNG_INTERLACE_NONE)1003affirm(png_ptr->row_number < png_ptr->height &&1004png_ptr->pass == 0U);10051006# ifdef PNG_WRITE_INTERLACING_SUPPORTED1007else if (png_ptr->do_interlace)1008affirm(png_ptr->row_number < png_ptr->height);1009# endif /* WRITE_INTERLACING */10101011else /* app does interlace */1012affirm(PNG_PASS_IN_IMAGE(png_ptr->width, png_ptr->height,1013png_ptr->pass) &&1014png_ptr->row_number <1015PNG_PASS_ROWS(png_ptr->height, png_ptr->pass));1016}1017} /* png_ptr, rows, num_rows all valid */10181019else if (png_ptr != NULL)1020png_app_warning(png_ptr, "Missing rows to row write API");1021}10221023/* ROW WRITE APIs */1024/* Called by user to write a single row of image data */1025void PNGAPI1026png_write_row(png_structrp png_ptr, png_const_bytep row)1027{1028png_debug(1, "in png_write_row");1029png_write_rows_internal(png_ptr, &row, 1U);1030}10311032/* Write a few rows of image data. If the image is interlaced,1033* either you will have to write the 7 sub images, or, if you1034* have called png_set_interlace_handling(), you will have to1035* "write" the image seven times.1036*/1037void PNGAPI1038png_write_rows(png_structrp png_ptr, png_bytepp rows, png_uint_32 num_rows)1039{1040png_debug(1, "in png_write_rows");10411042if (png_ptr != NULL)1043png_write_rows_internal(png_ptr, png_constcast(png_const_bytep*,rows),1044num_rows);1045}10461047/* Write the image. You only need to call this function once, even1048* if you are writing an interlaced image.1049*/1050void PNGAPI1051png_write_image(png_structrp png_ptr, png_bytepp image)1052{1053png_debug(1, "in png_write_image");10541055if (png_ptr != NULL)1056{1057int num_pass = 1;10581059/* The image is always an non-interlaced image. To write it as interlaced1060* interlace handling must be present:1061*/1062if (png_ptr->interlaced)1063{1064# ifdef PNG_WRITE_INTERLACING_SUPPORTED1065num_pass = png_set_interlace_handling(png_ptr);1066# else /* !WRITE_INTERLACING */1067/* There is no recovery because the IHDR has already been written.1068*/1069png_error(png_ptr, "No interlace support");1070# endif /* !WRITE_INTERLACING */1071}10721073/* And write the whole thing, 7 times if interlacing it: */1074for (; num_pass > 0; --num_pass)1075png_write_rows(png_ptr, image, png_ptr->height);1076}1077}10781079/* Free any memory used in png_ptr struct without freeing the struct itself. */1080static void1081png_write_destroy(png_structrp png_ptr)1082{1083png_debug(1, "in png_write_destroy");10841085png_deflate_destroy(png_ptr);10861087#ifdef PNG_TRANSFORM_MECH_SUPPORTED1088png_transform_free(png_ptr, &png_ptr->transform_list);1089#endif10901091#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED1092png_free(png_ptr, png_ptr->chunk_list);1093png_ptr->chunk_list = NULL;1094#endif10951096/* The error handling and memory handling information is left intact at this1097* point: the jmp_buf may still have to be freed. See png_destroy_png_struct1098* for how this happens.1099*/1100}11011102/* Free all memory used by the write.1103* In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for1104* *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free1105* the passed in info_structs but it would quietly fail to free any of the data1106* inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it1107* has no png_ptr.)1108*/1109void PNGAPI1110png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)1111{1112png_debug(1, "in png_destroy_write_struct");11131114if (png_ptr_ptr != NULL)1115{1116png_structrp png_ptr = *png_ptr_ptr;11171118if (png_ptr != NULL) /* added in libpng 1.6.0 */1119{1120png_destroy_info_struct(png_ptr, info_ptr_ptr);11211122*png_ptr_ptr = NULL;1123png_write_destroy(png_ptr);1124png_destroy_png_struct(png_ptr);1125}1126}1127}11281129void PNGAPI1130png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn)1131{1132if (png_ptr == NULL)1133return;11341135png_ptr->write_row_fn = write_row_fn;1136}11371138#ifdef PNG_WRITE_PNG_SUPPORTED1139void PNGAPI1140png_write_png(png_structrp png_ptr, png_inforp info_ptr,1141int transforms, voidp params)1142{1143if (png_ptr == NULL || info_ptr == NULL)1144return;11451146if ((info_ptr->valid & PNG_INFO_IDAT) == 0)1147{1148png_app_error(png_ptr, "no rows for png_write_image to write");1149return;1150}11511152/* Write the file header information. */1153png_write_info(png_ptr, info_ptr);11541155/* ------ these transformations don't touch the info structure ------- */11561157/* Invert monochrome pixels */1158if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0)1159#ifdef PNG_WRITE_INVERT_SUPPORTED1160png_set_invert_mono(png_ptr);1161#else1162png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported");1163#endif11641165/* Shift the pixels up to a legal bit depth and fill in1166* as appropriate to correctly scale the image.1167*/1168if ((transforms & PNG_TRANSFORM_SHIFT) != 0)1169#ifdef PNG_WRITE_SHIFT_SUPPORTED1170if ((info_ptr->valid & PNG_INFO_sBIT) != 0)1171png_set_shift(png_ptr, &info_ptr->sig_bit);1172#else1173png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported");1174#endif11751176/* Pack pixels into bytes */1177if ((transforms & PNG_TRANSFORM_PACKING) != 0)1178#ifdef PNG_WRITE_PACK_SUPPORTED1179png_set_packing(png_ptr);1180#else1181png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported");1182#endif11831184/* Swap location of alpha bytes from ARGB to RGBA */1185if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0)1186#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED1187png_set_swap_alpha(png_ptr);1188#else1189png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported");1190#endif11911192/* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into1193* RGB, note that the code expects the input color type to be G or RGB; no1194* alpha channel.1195*/1196if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER|1197PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0)1198{1199#ifdef PNG_WRITE_FILLER_SUPPORTED1200if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0)1201{1202if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)1203png_app_error(png_ptr,1204"PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported");12051206/* Continue if ignored - this is the pre-1.6.10 behavior */1207png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);1208}12091210else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0)1211png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);1212#else1213png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported");1214#endif1215}12161217/* Flip BGR pixels to RGB */1218if ((transforms & PNG_TRANSFORM_BGR) != 0)1219#ifdef PNG_WRITE_BGR_SUPPORTED1220png_set_bgr(png_ptr);1221#else1222png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported");1223#endif12241225/* Swap bytes of 16-bit files to most significant byte first */1226if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0)1227#ifdef PNG_WRITE_SWAP_SUPPORTED1228png_set_swap(png_ptr);1229#else1230png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported");1231#endif12321233/* Swap bits of 1, 2, 4 bit packed pixel formats */1234if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0)1235#ifdef PNG_WRITE_PACKSWAP_SUPPORTED1236png_set_packswap(png_ptr);1237#else1238png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported");1239#endif12401241/* Invert the alpha channel from opacity to transparency */1242if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0)1243#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED1244png_set_invert_alpha(png_ptr);1245#else1246png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported");1247#endif12481249/* ----------------------- end of transformations ------------------- */12501251/* Write the bits */1252png_write_image(png_ptr, info_ptr->row_pointers);12531254/* It is REQUIRED to call this to finish writing the rest of the file */1255png_write_end(png_ptr, info_ptr);12561257PNG_UNUSED(params)1258}1259#endif /* WRITE_PNG */126012611262#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED1263/* Initialize the write structure - general purpose utility. */1264static int1265png_image_write_init(png_imagep image)1266{1267png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image,1268png_safe_error, png_safe_warning);12691270if (png_ptr != NULL)1271{1272png_infop info_ptr = png_create_info_struct(png_ptr);12731274if (info_ptr != NULL)1275{1276png_controlp control = png_voidcast(png_controlp,1277png_malloc_warn(png_ptr, (sizeof *control)));12781279if (control != NULL)1280{1281memset(control, 0, (sizeof *control));12821283control->png_ptr = png_ptr;1284control->info_ptr = info_ptr;1285control->for_write = 1;12861287image->opaque = control;1288return 1;1289}12901291/* Error clean up */1292png_destroy_info_struct(png_ptr, &info_ptr);1293}12941295png_destroy_write_struct(&png_ptr, NULL);1296}12971298return png_image_error(image, "png_image_write_: out of memory");1299}13001301/* Arguments to png_image_write_main: */1302typedef struct1303{1304/* Arguments: */1305png_imagep image;1306png_const_voidp buffer;1307ptrdiff_t row_stride;1308png_const_voidp colormap;1309int convert_to_8bit;1310/* Local variables: */1311png_const_voidp first_row;1312ptrdiff_t row_bytes;1313png_voidp local_row;1314/* Byte count for memory writing */1315png_bytep memory;1316png_alloc_size_t memory_bytes; /* not used for STDIO */1317png_alloc_size_t output_bytes; /* running total */1318} png_image_write_control;13191320/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to1321* do any necessary byte swapping. The component order is defined by the1322* png_image format value.1323*/1324static int1325png_write_image_16bit(png_voidp argument)1326{1327png_image_write_control *display = png_voidcast(png_image_write_control*,1328argument);1329png_imagep image = display->image;1330png_structrp png_ptr = image->opaque->png_ptr;13311332png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,1333display->first_row);1334png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row);1335png_uint_16p row_end;1336const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1;1337int aindex = 0;1338png_uint_32 y = image->height;13391340if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)1341{1342# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED1343if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)1344{1345aindex = -1;1346++input_row; /* To point to the first component */1347++output_row;1348}13491350else1351# endif1352aindex = channels;1353}13541355else1356png_error(png_ptr, "png_write_image: internal call error");13571358/* Work out the output row end and count over this, note that the increment1359* above to 'row' means that row_end can actually be beyond the end of the1360* row; this is correct.1361*/1362row_end = output_row + image->width * (channels+1);13631364while (y-- > 0)1365{1366png_const_uint_16p in_ptr = input_row;1367png_uint_16p out_ptr = output_row;13681369while (out_ptr < row_end)1370{1371const png_uint_16 alpha = in_ptr[aindex];1372png_uint_32 reciprocal = 0;1373int c;13741375out_ptr[aindex] = alpha;13761377/* Calculate a reciprocal. The correct calculation is simply1378* component/alpha*65535 << 15. (I.e. 15 bits of precision); this1379* allows correct rounding by adding .5 before the shift. 'reciprocal'1380* is only initialized when required.1381*/1382if (alpha > 0 && alpha < 65535)1383reciprocal = ((0xffff<<15)+(alpha>>1))/alpha;13841385c = channels;1386do /* always at least one channel */1387{1388png_uint_16 component = *in_ptr++;13891390/* The following gives 65535 for an alpha of 0, which is fine,1391* otherwise if 0/0 is represented as some other value there is more1392* likely to be a discontinuity which will probably damage1393* compression when moving from a fully transparent area to a1394* nearly transparent one. (The assumption here is that opaque1395* areas tend not to be 0 intensity.)1396*/1397if (component >= alpha)1398component = 65535;13991400/* component<alpha, so component/alpha is less than one and1401* component*reciprocal is less than 2^31.1402*/1403else if (component > 0 && alpha < 65535)1404{1405png_uint_32 calc = component * reciprocal;1406calc += 16384; /* round to nearest */1407component = png_check_u16(png_ptr, calc >> 15);1408}14091410*out_ptr++ = component;1411}1412while (--c > 0);14131414/* Skip to next component (skip the intervening alpha channel) */1415++in_ptr;1416++out_ptr;1417}14181419png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row));1420input_row += display->row_bytes/(sizeof (png_uint_16));1421}14221423return 1;1424}14251426/* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel1427* is present it must be removed from the components, the components are then1428* written in sRGB encoding. No components are added or removed.1429*1430* Calculate an alpha reciprocal to reverse pre-multiplication. As above the1431* calculation can be done to 15 bits of accuracy; however, the output needs to1432* be scaled in the range 0..255*65535, so include that scaling here.1433*/1434#define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha)14351436static png_byte1437png_unpremultiply(png_const_structrp png_ptr, png_uint_32 component,1438png_uint_32 alpha, png_uint_32 reciprocal/*from the above macro*/)1439{1440/* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/01441* is represented as some other value there is more likely to be a1442* discontinuity which will probably damage compression when moving from a1443* fully transparent area to a nearly transparent one. (The assumption here1444* is that opaque areas tend not to be 0 intensity.)1445*1446* There is a rounding problem here; if alpha is less than 128 it will end up1447* as 0 when scaled to 8 bits. To avoid introducing spurious colors into the1448* output change for this too.1449*/1450if (component >= alpha || alpha < 128)1451return 255;14521453/* component<alpha, so component/alpha is less than one and1454* component*reciprocal is less than 2^31.1455*/1456else if (component > 0)1457{1458/* The test is that alpha/257 (rounded) is less than 255, the first value1459* that becomes 255 is 65407.1460* NOTE: this must agree with the PNG_DIV257 macro (which must, therefore,1461* be exact!) [Could also test reciprocal != 0]1462*/1463if (alpha < 65407)1464{1465component *= reciprocal;1466component += 64; /* round to nearest */1467component >>= 7;1468}14691470else1471component *= 255;14721473/* Convert the component to sRGB. */1474return PNG_sRGB_FROM_LINEAR(png_ptr, component);1475}14761477else1478return 0;14791480PNG_UNUSEDRC(png_ptr)1481}14821483static int1484png_write_image_8bit(png_voidp argument)1485{1486png_image_write_control *display = png_voidcast(png_image_write_control*,1487argument);1488png_imagep image = display->image;1489png_structrp png_ptr = image->opaque->png_ptr;14901491png_const_uint_16p input_row = png_voidcast(png_const_uint_16p,1492display->first_row);1493png_bytep output_row = png_voidcast(png_bytep, display->local_row);1494png_uint_32 y = image->height;1495const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1;14961497if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0)1498{1499png_bytep row_end;1500int aindex;15011502# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED1503if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0)1504{1505aindex = -1;1506++input_row; /* To point to the first component */1507++output_row;1508}15091510else1511# endif1512aindex = channels;15131514/* Use row_end in place of a loop counter: */1515row_end = output_row + image->width * (channels+1);15161517while (y-- > 0)1518{1519png_const_uint_16p in_ptr = input_row;1520png_bytep out_ptr = output_row;15211522while (out_ptr < row_end)1523{1524png_uint_16 alpha = in_ptr[aindex];1525png_byte alphabyte = png_check_byte(png_ptr, PNG_DIV257(alpha));1526png_uint_32 reciprocal = 0;1527int c;15281529/* Scale and write the alpha channel. */1530out_ptr[aindex] = alphabyte;15311532if (alphabyte > 0 && alphabyte < 255)1533reciprocal = UNP_RECIPROCAL(alpha);15341535c = channels;1536do /* always at least one channel */1537*out_ptr++ = png_unpremultiply(png_ptr, *in_ptr++, alpha,1538reciprocal);1539while (--c > 0);15401541/* Skip to next component (skip the intervening alpha channel) */1542++in_ptr;1543++out_ptr;1544} /* while out_ptr < row_end */15451546png_write_row(png_ptr, png_voidcast(png_const_bytep,1547display->local_row));1548input_row += display->row_bytes/(sizeof (png_uint_16));1549} /* while y */1550}15511552else1553{1554/* No alpha channel, so the row_end really is the end of the row and it1555* is sufficient to loop over the components one by one.1556*/1557png_bytep row_end = output_row + image->width * channels;15581559while (y-- > 0)1560{1561png_const_uint_16p in_ptr = input_row;1562png_bytep out_ptr = output_row;15631564while (out_ptr < row_end)1565{1566png_uint_32 component = *in_ptr++;15671568component *= 255;1569*out_ptr++ = PNG_sRGB_FROM_LINEAR(png_ptr, component);1570}15711572png_write_row(png_ptr, output_row);1573input_row += display->row_bytes/(sizeof (png_uint_16));1574}1575}15761577return 1;1578}15791580static void1581png_image_set_PLTE(png_image_write_control *display)1582{1583const png_imagep image = display->image;1584const void *cmap = display->colormap;1585const int entries = image->colormap_entries > 256 ? 256 :1586(int)image->colormap_entries;15871588/* NOTE: the caller must check for cmap != NULL and entries != 0 */1589const png_uint_32 format = image->format;1590const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format);15911592# if defined(PNG_FORMAT_BGR_SUPPORTED) &&\1593defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED)1594const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 &&1595(format & PNG_FORMAT_FLAG_ALPHA) != 0;1596# else1597# define afirst 01598# endif15991600# ifdef PNG_FORMAT_BGR_SUPPORTED1601const int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0;1602# else1603# define bgr 01604# endif16051606int i, num_trans;1607png_color palette[256];1608png_byte tRNS[256];16091610memset(tRNS, 255, (sizeof tRNS));1611memset(palette, 0, (sizeof palette));16121613for (i=num_trans=0; i<entries; ++i)1614{1615/* This gets automatically converted to sRGB with reversal of the1616* pre-multiplication if the color-map has an alpha channel.1617*/1618if ((format & PNG_FORMAT_FLAG_LINEAR) != 0)1619{1620png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap);16211622entry += i * channels;16231624if ((channels & 1) != 0) /* no alpha */1625{1626if (channels >= 3) /* RGB */1627{1628palette[i].blue = PNG_sRGB_FROM_LINEAR(1629display->image->opaque->png_ptr, 255 * entry[(2 ^ bgr)]);1630palette[i].green = PNG_sRGB_FROM_LINEAR(1631display->image->opaque->png_ptr, 255 * entry[1]);1632palette[i].red = PNG_sRGB_FROM_LINEAR(1633display->image->opaque->png_ptr, 255 * entry[bgr]);1634}16351636else /* Gray */1637palette[i].blue = palette[i].red = palette[i].green =1638PNG_sRGB_FROM_LINEAR(display->image->opaque->png_ptr,1639255 * *entry);1640}16411642else /* alpha */1643{1644png_uint_16 alpha = entry[afirst ? 0 : channels-1];1645png_byte alphabyte = png_check_byte(1646display->image->opaque->png_ptr, PNG_DIV257(alpha));1647png_uint_32 reciprocal = 0;16481649/* Calculate a reciprocal, as in the png_write_image_8bit code above1650* this is designed to produce a value scaled to 255*65535 when1651* divided by 128 (i.e. asr 7).1652*/1653if (alphabyte > 0 && alphabyte < 255)1654reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha;16551656tRNS[i] = alphabyte;1657if (alphabyte < 255)1658num_trans = i+1;16591660if (channels >= 3) /* RGB */1661{1662palette[i].blue = png_unpremultiply(1663display->image->opaque->png_ptr, entry[afirst + (2 ^ bgr)],1664alpha, reciprocal);1665palette[i].green = png_unpremultiply(1666display->image->opaque->png_ptr, entry[afirst + 1], alpha,1667reciprocal);1668palette[i].red = png_unpremultiply(1669display->image->opaque->png_ptr, entry[afirst + bgr], alpha,1670reciprocal);1671}16721673else /* gray */1674palette[i].blue = palette[i].red = palette[i].green =1675png_unpremultiply(display->image->opaque->png_ptr,1676entry[afirst], alpha, reciprocal);1677}1678}16791680else /* Color-map has sRGB values */1681{1682png_const_bytep entry = png_voidcast(png_const_bytep, cmap);16831684entry += i * channels;16851686switch (channels)1687{1688case 4:1689tRNS[i] = entry[afirst ? 0 : 3];1690if (tRNS[i] < 255)1691num_trans = i+1;1692/* FALL THROUGH */1693case 3:1694palette[i].blue = entry[afirst + (2 ^ bgr)];1695palette[i].green = entry[afirst + 1];1696palette[i].red = entry[afirst + bgr];1697break;16981699case 2:1700tRNS[i] = entry[1 ^ afirst];1701if (tRNS[i] < 255)1702num_trans = i+1;1703/* FALL THROUGH */1704case 1:1705palette[i].blue = palette[i].red = palette[i].green =1706entry[afirst];1707break;17081709default:1710break;1711}1712}1713}17141715# ifdef afirst1716# undef afirst1717# endif1718# ifdef bgr1719# undef bgr1720# endif17211722png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette,1723entries);17241725if (num_trans > 0)1726png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS,1727num_trans, NULL);17281729image->colormap_entries = entries;1730}17311732static int1733png_image_write_main(png_voidp argument)1734{1735png_image_write_control *display = png_voidcast(png_image_write_control*,1736argument);1737png_imagep image = display->image;1738png_structrp png_ptr = image->opaque->png_ptr;1739png_inforp info_ptr = image->opaque->info_ptr;1740png_uint_32 format = image->format;17411742/* The following four ints are actually booleans */1743int colormap = (format & PNG_FORMAT_FLAG_COLORMAP);1744int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */1745int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA);1746int write_16bit = linear && !colormap && (display->convert_to_8bit == 0);17471748# ifdef PNG_BENIGN_ERRORS_SUPPORTED1749/* Make sure we error out on any bad situation */1750png_set_benign_errors(png_ptr, 0/*error*/);1751# endif17521753/* Default the 'row_stride' parameter if required, also check the row stride1754* and total image size to ensure that they are within the system limits.1755*/1756{1757const unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format);17581759/* The test is slightly evil: it assumes that a signed pointer difference1760* (ptrdiff_t) can hold a maximum value of half, rounded down, of the1761* maximum of a (size_t). This is almost certain to be true.1762*/1763if (image->width <= (PNG_SIZE_MAX >> 1)/channels) /* no overflow */1764{1765png_alloc_size_t check;1766const png_alloc_size_t png_row_stride =1767(png_alloc_size_t)/*SAFE*/image->width * channels;17681769if (display->row_stride == 0)1770display->row_stride = (ptrdiff_t)png_row_stride;17711772if (display->row_stride < 0)1773check = -display->row_stride;17741775else1776check = display->row_stride;17771778if (check >= png_row_stride)1779{1780/* Now check for overflow of the image buffer calculation; check for1781* (size_t) overflow here. This detects issues with the1782* PNG_IMAGE_BUFFER_SIZE macro.1783*/1784if (image->height > PNG_SIZE_MAX/png_row_stride)1785png_error(image->opaque->png_ptr, "memory image too large");1786}17871788else1789png_error(image->opaque->png_ptr, "supplied row stride too small");1790}17911792else1793png_error(image->opaque->png_ptr, "image row stride too large");1794}17951796/* Set the required transforms then write the rows in the correct order. */1797if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0)1798{1799if (display->colormap != NULL && image->colormap_entries > 0)1800{1801png_uint_32 entries = image->colormap_entries;18021803png_set_IHDR(png_ptr, info_ptr, image->width, image->height,1804entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)),1805PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,1806PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);18071808png_image_set_PLTE(display);1809}18101811else1812png_error(image->opaque->png_ptr,1813"no color-map for color-mapped image");1814}18151816else1817png_set_IHDR(png_ptr, info_ptr, image->width, image->height,1818write_16bit ? 16 : 8,1819((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) +1820((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0),1821PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);18221823/* Counter-intuitively the data transformations must be called *after*1824* png_write_info, not before as in the read code, but the 'set' functions1825* must still be called before. Just set the color space information, never1826* write an interlaced image.1827*/18281829if (write_16bit != 0)1830{1831/* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */1832png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR);18331834if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)1835png_set_cHRM_fixed(png_ptr, info_ptr,1836/* color x y */1837/* white */ 31270, 32900,1838/* red */ 64000, 33000,1839/* green */ 30000, 60000,1840/* blue */ 15000, 60001841);1842}18431844else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0)1845png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);18461847/* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit1848* space must still be gamma encoded.1849*/1850else1851png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);18521853/* Write the file header. */1854png_write_info(png_ptr, info_ptr);18551856/* Now set up the data transformations (*after* the header is written),1857* remove the handled transformations from the 'format' flags for checking.1858*1859* First check for a little endian system if writing 16 bit files.1860*/1861if (write_16bit != 0)1862{1863PNG_CONST png_uint_16 le = 0x0001;18641865if ((*(png_const_bytep) & le) != 0)1866png_set_swap(png_ptr);1867}18681869# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED1870if ((format & PNG_FORMAT_FLAG_BGR) != 0)1871{1872if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0)1873png_set_bgr(png_ptr);1874format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_BGR);1875}1876# endif18771878# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED1879if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)1880{1881if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0)1882png_set_swap_alpha(png_ptr);1883format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_AFIRST);1884}1885# endif18861887/* If there are 16 or fewer color-map entries we wrote a lower bit depth1888* above, but the application data is still byte packed.1889*/1890if (colormap != 0 && image->colormap_entries <= 16)1891png_set_packing(png_ptr);18921893/* That should have handled all (both) the transforms. */1894if ((format & PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR |1895PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0)1896png_error(png_ptr, "png_write_image: unsupported transformation");18971898{1899png_const_bytep row = png_voidcast(png_const_bytep, display->buffer);1900ptrdiff_t row_bytes = display->row_stride;19011902if (linear != 0)1903row_bytes *= (sizeof (png_uint_16));19041905if (row_bytes < 0)1906row += (image->height-1) * (-row_bytes);19071908display->first_row = row;1909display->row_bytes = row_bytes;1910}19111912/* Select the right compression mode based on the presence or absence of the1913* 'fast' flag. This will use whatever options are available in the libpng1914* build. It is always supported.1915*/1916png_set_compression(png_ptr, (image->flags & PNG_IMAGE_FLAG_FAST) != 0 ?1917PNG_COMPRESSION_HIGH_SPEED : PNG_COMPRESSION_HIGH);19181919/* Check for the cases that currently require a pre-transform on the row1920* before it is written. This only applies when the input is 16-bit and1921* either there is an alpha channel or it is converted to 8-bit.1922*/1923if ((linear != 0 && alpha != 0 ) ||1924(colormap == 0 && display->convert_to_8bit != 0))1925{1926png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr,1927png_get_rowbytes(png_ptr, info_ptr)));1928int result;19291930display->local_row = row;1931if (write_16bit != 0)1932result = png_safe_execute(image, png_write_image_16bit, display);1933else1934result = png_safe_execute(image, png_write_image_8bit, display);1935display->local_row = NULL;19361937png_free(png_ptr, row);19381939/* Skip the 'write_end' on error: */1940if (result == 0)1941return 0;1942}19431944/* Otherwise this is the case where the input is in a format currently1945* supported by the rest of the libpng write code; call it directly.1946*/1947else1948{1949png_const_bytep row = png_voidcast(png_const_bytep, display->first_row);1950ptrdiff_t row_bytes = display->row_bytes;1951png_uint_32 y = image->height;19521953while (y-- > 0)1954{1955png_write_row(png_ptr, row);1956row += row_bytes;1957}1958}19591960png_write_end(png_ptr, info_ptr);1961return 1;1962}196319641965static void (PNGCBAPI1966image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data,1967png_size_t size)1968{1969png_image_write_control *display = png_voidcast(png_image_write_control*,1970png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/);1971const png_alloc_size_t ob = display->output_bytes;19721973/* Check for overflow; this should never happen: */1974if (size <= ((png_alloc_size_t)-1) - ob)1975{1976/* I don't think libpng ever does this, but just in case: */1977if (size > 0)1978{1979if (display->memory_bytes >= ob+size) /* writing */1980memcpy(display->memory+ob, data, size);19811982/* Always update the size: */1983display->output_bytes = ob+size;1984}1985}19861987else1988png_error(png_ptr, "png_image_write_to_memory: PNG too big");1989}19901991static void (PNGCBAPI1992image_memory_flush)(png_structp png_ptr)1993{1994PNG_UNUSED(png_ptr)1995}19961997static int1998png_image_write_memory(png_voidp argument)1999{2000png_image_write_control *display = png_voidcast(png_image_write_control*,2001argument);20022003/* The rest of the memory-specific init and write_main in an error protected2004* environment. This case needs to use callbacks for the write operations2005* since libpng has no built in support for writing to memory.2006*/2007png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/,2008image_memory_write, image_memory_flush);20092010return png_image_write_main(display);2011}20122013int PNGAPI2014png_image_write_to_memory(png_imagep image, void *memory,2015png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit,2016const void *buffer, ptrdiff_t row_stride, const void *colormap)2017{2018/* Write the image to the given buffer, or count the bytes if it is NULL */2019if (image != NULL && image->version == PNG_IMAGE_VERSION)2020{2021if (memory_bytes != NULL && buffer != NULL)2022{2023/* This is to give the caller an easier error detection in the NULL2024* case and guard against uninitialized variable problems:2025*/2026if (memory == NULL)2027*memory_bytes = 0;20282029if (png_image_write_init(image) != 0)2030{2031png_image_write_control display;2032int result;20332034memset(&display, 0, (sizeof display));2035display.image = image;2036display.buffer = buffer;2037display.row_stride = row_stride;2038display.colormap = colormap;2039display.convert_to_8bit = convert_to_8bit;2040display.memory = png_voidcast(png_bytep, memory);2041display.memory_bytes = *memory_bytes;2042display.output_bytes = 0;20432044result = png_safe_execute(image, png_image_write_memory, &display);2045png_image_free(image);20462047/* write_memory returns true even if we ran out of buffer. */2048if (result)2049{2050/* On out-of-buffer this function returns '0' but still updates2051* memory_bytes:2052*/2053if (memory != NULL && display.output_bytes > *memory_bytes)2054result = 0;20552056*memory_bytes = display.output_bytes;2057}20582059return result;2060}20612062else2063return 0;2064}20652066else2067return png_image_error(image,2068"png_image_write_to_memory: invalid argument");2069}20702071else if (image != NULL)2072return png_image_error(image,2073"png_image_write_to_memory: incorrect PNG_IMAGE_VERSION");20742075else2076return 0;2077}20782079#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED2080int PNGAPI2081png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit,2082const void *buffer, ptrdiff_t row_stride, const void *colormap)2083{2084/* Write the image to the given (FILE*). */2085if (image != NULL && image->version == PNG_IMAGE_VERSION)2086{2087if (file != NULL && buffer != NULL)2088{2089if (png_image_write_init(image) != 0 &&2090png_image_init_io(image, file) != 0)2091{2092png_image_write_control display;2093int result;20942095memset(&display, 0, (sizeof display));2096display.image = image;2097display.buffer = buffer;2098display.row_stride = row_stride;2099display.colormap = colormap;2100display.convert_to_8bit = convert_to_8bit;21012102result = png_safe_execute(image, png_image_write_main, &display);2103png_image_free(image);2104return result;2105}21062107else2108return 0;2109}21102111else2112return png_image_error(image,2113"png_image_write_to_stdio: invalid argument");2114}21152116else if (image != NULL)2117return png_image_error(image,2118"png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION");21192120else2121return 0;2122}21232124int PNGAPI2125png_image_write_to_file(png_imagep image, const char *file_name,2126int convert_to_8bit, const void *buffer, ptrdiff_t row_stride,2127const void *colormap)2128{2129/* Write the image to the named file. */2130if (image != NULL && image->version == PNG_IMAGE_VERSION)2131{2132if (file_name != NULL && buffer != NULL)2133{2134FILE *fp = fopen(file_name, "wb");21352136if (fp != NULL)2137{2138if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer,2139row_stride, colormap) != 0)2140{2141int error; /* from fflush/fclose */21422143/* Make sure the file is flushed correctly. */2144if (fflush(fp) == 0 && ferror(fp) == 0)2145{2146if (fclose(fp) == 0)2147return 1;21482149error = errno; /* from fclose */2150}21512152else2153{2154error = errno; /* from fflush or ferror */2155(void)fclose(fp);2156}21572158(void)remove(file_name);2159/* The image has already been cleaned up; this is just used to2160* set the error (because the original write succeeded).2161*/2162return png_image_error(image, strerror(error));2163}21642165else2166{2167/* Clean up: just the opened file. */2168(void)fclose(fp);2169(void)remove(file_name);2170return 0;2171}2172}21732174else2175return png_image_error(image, strerror(errno));2176}21772178else2179return png_image_error(image,2180"png_image_write_to_file: invalid argument");2181}21822183else if (image != NULL)2184return png_image_error(image,2185"png_image_write_to_file: incorrect PNG_IMAGE_VERSION");21862187else2188return 0;2189}2190#endif /* SIMPLIFIED_WRITE_STDIO */2191#endif /* SIMPLIFIED_WRITE */2192#endif /* WRITE */219321942195