123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- /*---------------------------------------------------------------------------
- wpng - simple PNG-writing program writepng.c
- ---------------------------------------------------------------------------
- Copyright (c) 1998-2007 Greg Roelofs. All rights reserved.
- This software is provided "as is," without warranty of any kind,
- express or implied. In no event shall the author or contributors
- be held liable for any damages arising in any way from the use of
- this software.
- The contents of this file are DUAL-LICENSED. You may modify and/or
- redistribute this software according to the terms of one of the
- following two licenses (at your option):
- LICENSE 1 ("BSD-like with advertising clause"):
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute
- it freely, subject to the following restrictions:
- 1. Redistributions of source code must retain the above copyright
- notice, disclaimer, and this list of conditions.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, disclaimer, and this list of conditions in the documenta-
- tion and/or other materials provided with the distribution.
- 3. All advertising materials mentioning features or use of this
- software must display the following acknowledgment:
- This product includes software developed by Greg Roelofs
- and contributors for the book, "PNG: The Definitive Guide,"
- published by O'Reilly and Associates.
- LICENSE 2 (GNU GPL v2 or later):
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- ---------------------------------------------------------------------------*/
- #include <stdlib.h> /* for exit() prototype */
- #include <zlib.h>
- #include "png.h" /* libpng header, includes setjmp.h */
- #include "writepng.h" /* typedefs, common macros, public prototypes */
- /* local prototype */
- static void writepng_error_handler(png_structp png_ptr, png_const_charp msg);
- void writepng_version_info(void)
- {
- fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n",
- PNG_LIBPNG_VER_STRING, png_libpng_ver);
- fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n",
- ZLIB_VERSION, zlib_version);
- }
- /* returns 0 for success, 2 for libpng problem, 4 for out of memory, 11 for
- * unexpected pnmtype; note that outfile might be stdout */
- int writepng_init(mainprog_info *mainprog_ptr)
- {
- png_structp png_ptr; /* note: temporary variables! */
- png_infop info_ptr;
- int color_type, interlace_type;
- /* could also replace libpng warning-handler (final NULL), but no need: */
- png_ptr = png_create_write_struct(png_get_libpng_ver(NULL), mainprog_ptr,
- writepng_error_handler, NULL);
- if (!png_ptr)
- return 4; /* out of memory */
- info_ptr = png_create_info_struct(png_ptr);
- if (!info_ptr) {
- png_destroy_write_struct(&png_ptr, NULL);
- return 4; /* out of memory */
- }
- /* setjmp() must be called in every function that calls a PNG-writing
- * libpng function, unless an alternate error handler was installed--
- * but compatible error handlers must either use longjmp() themselves
- * (as in this program) or some other method to return control to
- * application code, so here we go: */
- if (setjmp(mainprog_ptr->jmpbuf)) {
- png_destroy_write_struct(&png_ptr, &info_ptr);
- return 2;
- }
- /* make sure outfile is (re)opened in BINARY mode */
- png_init_io(png_ptr, mainprog_ptr->outfile);
- /* set the compression levels--in general, always want to leave filtering
- * turned on (except for palette images) and allow all of the filters,
- * which is the default; want 32K zlib window, unless entire image buffer
- * is 16K or smaller (unknown here)--also the default; usually want max
- * compression (NOT the default); and remaining compression flags should
- * be left alone */
- png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
- /*
- >> this is default for no filtering; Z_FILTERED is default otherwise:
- png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
- >> these are all defaults:
- png_set_compression_mem_level(png_ptr, 8);
- png_set_compression_window_bits(png_ptr, 15);
- png_set_compression_method(png_ptr, 8);
- */
- /* set the image parameters appropriately */
- if (mainprog_ptr->pnmtype == 5)
- color_type = PNG_COLOR_TYPE_GRAY;
- else if (mainprog_ptr->pnmtype == 6)
- color_type = PNG_COLOR_TYPE_RGB;
- else if (mainprog_ptr->pnmtype == 8)
- color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- else {
- png_destroy_write_struct(&png_ptr, &info_ptr);
- return 11;
- }
- interlace_type = mainprog_ptr->interlaced? PNG_INTERLACE_ADAM7 :
- PNG_INTERLACE_NONE;
- png_set_IHDR(png_ptr, info_ptr, mainprog_ptr->width, mainprog_ptr->height,
- mainprog_ptr->sample_depth, color_type, interlace_type,
- PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
- if (mainprog_ptr->gamma > 0.0)
- png_set_gAMA(png_ptr, info_ptr, mainprog_ptr->gamma);
- if (mainprog_ptr->have_bg) { /* we know it's RGBA, not gray+alpha */
- png_color_16 background;
- background.red = mainprog_ptr->bg_red;
- background.green = mainprog_ptr->bg_green;
- background.blue = mainprog_ptr->bg_blue;
- png_set_bKGD(png_ptr, info_ptr, &background);
- }
- if (mainprog_ptr->have_time) {
- png_time modtime;
- png_convert_from_time_t(&modtime, mainprog_ptr->modtime);
- png_set_tIME(png_ptr, info_ptr, &modtime);
- }
- if (mainprog_ptr->have_text) {
- png_text text[6];
- int num_text = 0;
- if (mainprog_ptr->have_text & TEXT_TITLE) {
- text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
- text[num_text].key = "Title";
- text[num_text].text = mainprog_ptr->title;
- ++num_text;
- }
- if (mainprog_ptr->have_text & TEXT_AUTHOR) {
- text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
- text[num_text].key = "Author";
- text[num_text].text = mainprog_ptr->author;
- ++num_text;
- }
- if (mainprog_ptr->have_text & TEXT_DESC) {
- text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
- text[num_text].key = "Description";
- text[num_text].text = mainprog_ptr->desc;
- ++num_text;
- }
- if (mainprog_ptr->have_text & TEXT_COPY) {
- text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
- text[num_text].key = "Copyright";
- text[num_text].text = mainprog_ptr->copyright;
- ++num_text;
- }
- if (mainprog_ptr->have_text & TEXT_EMAIL) {
- text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
- text[num_text].key = "E-mail";
- text[num_text].text = mainprog_ptr->email;
- ++num_text;
- }
- if (mainprog_ptr->have_text & TEXT_URL) {
- text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
- text[num_text].key = "URL";
- text[num_text].text = mainprog_ptr->url;
- ++num_text;
- }
- png_set_text(png_ptr, info_ptr, text, num_text);
- }
- /* write all chunks up to (but not including) first IDAT */
- png_write_info(png_ptr, info_ptr);
- /* if we wanted to write any more text info *after* the image data, we
- * would set up text struct(s) here and call png_set_text() again, with
- * just the new data; png_set_tIME() could also go here, but it would
- * have no effect since we already called it above (only one tIME chunk
- * allowed) */
- /* set up the transformations: for now, just pack low-bit-depth pixels
- * into bytes (one, two or four pixels per byte) */
- png_set_packing(png_ptr);
- /* png_set_shift(png_ptr, &sig_bit); to scale low-bit-depth values */
- /* make sure we save our pointers for use in writepng_encode_image() */
- mainprog_ptr->png_ptr = png_ptr;
- mainprog_ptr->info_ptr = info_ptr;
- /* OK, that's all we need to do for now; return happy */
- return 0;
- }
- /* returns 0 for success, 2 for libpng (longjmp) problem */
- int writepng_encode_image(mainprog_info *mainprog_ptr)
- {
- png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
- png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
- /* as always, setjmp() must be called in every function that calls a
- * PNG-writing libpng function */
- if (setjmp(mainprog_ptr->jmpbuf)) {
- png_destroy_write_struct(&png_ptr, &info_ptr);
- mainprog_ptr->png_ptr = NULL;
- mainprog_ptr->info_ptr = NULL;
- return 2;
- }
- /* and now we just write the whole image; libpng takes care of interlacing
- * for us */
- png_write_image(png_ptr, mainprog_ptr->row_pointers);
- /* since that's it, we also close out the end of the PNG file now--if we
- * had any text or time info to write after the IDATs, second argument
- * would be info_ptr, but we optimize slightly by sending NULL pointer: */
- png_write_end(png_ptr, NULL);
- return 0;
- }
- /* returns 0 if succeeds, 2 if libpng problem */
- int writepng_encode_row(mainprog_info *mainprog_ptr) /* NON-interlaced only! */
- {
- png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
- png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
- /* as always, setjmp() must be called in every function that calls a
- * PNG-writing libpng function */
- if (setjmp(mainprog_ptr->jmpbuf)) {
- png_destroy_write_struct(&png_ptr, &info_ptr);
- mainprog_ptr->png_ptr = NULL;
- mainprog_ptr->info_ptr = NULL;
- return 2;
- }
- /* image_data points at our one row of image data */
- png_write_row(png_ptr, mainprog_ptr->image_data);
- return 0;
- }
- /* returns 0 if succeeds, 2 if libpng problem */
- int writepng_encode_finish(mainprog_info *mainprog_ptr) /* NON-interlaced! */
- {
- png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
- png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
- /* as always, setjmp() must be called in every function that calls a
- * PNG-writing libpng function */
- if (setjmp(mainprog_ptr->jmpbuf)) {
- png_destroy_write_struct(&png_ptr, &info_ptr);
- mainprog_ptr->png_ptr = NULL;
- mainprog_ptr->info_ptr = NULL;
- return 2;
- }
- /* close out PNG file; if we had any text or time info to write after
- * the IDATs, second argument would be info_ptr: */
- png_write_end(png_ptr, NULL);
- return 0;
- }
- void writepng_cleanup(mainprog_info *mainprog_ptr)
- {
- png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
- png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
- if (png_ptr && info_ptr)
- png_destroy_write_struct(&png_ptr, &info_ptr);
- }
- static void writepng_error_handler(png_structp png_ptr, png_const_charp msg)
- {
- mainprog_info *mainprog_ptr;
- /* This function, aside from the extra step of retrieving the "error
- * pointer" (below) and the fact that it exists within the application
- * rather than within libpng, is essentially identical to libpng's
- * default error handler. The second point is critical: since both
- * setjmp() and longjmp() are called from the same code, they are
- * guaranteed to have compatible notions of how big a jmp_buf is,
- * regardless of whether _BSD_SOURCE or anything else has (or has not)
- * been defined. */
- fprintf(stderr, "writepng libpng error: %s\n", msg);
- fflush(stderr);
- mainprog_ptr = png_get_error_ptr(png_ptr);
- if (mainprog_ptr == NULL) { /* we are completely hosed now */
- fprintf(stderr,
- "writepng severe error: jmpbuf not recoverable; terminating.\n");
- fflush(stderr);
- exit(99);
- }
- /* Now we have our data structure we can use the information in it
- * to return control to our own higher level code (all the points
- * where 'setjmp' is called in this file.) This will work with other
- * error handling mechanisms as well - libpng always calls png_error
- * when it can proceed no further, thus, so long as the error handler
- * is intercepted, application code can do its own error recovery.
- */
- longjmp(mainprog_ptr->jmpbuf, 1);
- }
|