writepng.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------
00002 
00003    wpng - simple PNG-writing program                             writepng.c
00004 
00005   ---------------------------------------------------------------------------
00006 
00007       Copyright (c) 1998-2000 Greg Roelofs.  All rights reserved.
00008 
00009       This software is provided "as is," without warranty of any kind,
00010       express or implied.  In no event shall the author or contributors
00011       be held liable for any damages arising in any way from the use of
00012       this software.
00013 
00014       Permission is granted to anyone to use this software for any purpose,
00015       including commercial applications, and to alter it and redistribute
00016       it freely, subject to the following restrictions:
00017 
00018       1. Redistributions of source code must retain the above copyright
00019          notice, disclaimer, and this list of conditions.
00020       2. Redistributions in binary form must reproduce the above copyright
00021          notice, disclaimer, and this list of conditions in the documenta-
00022          tion and/or other materials provided with the distribution.
00023       3. All advertising materials mentioning features or use of this
00024          software must display the following acknowledgment:
00025 
00026             This product includes software developed by Greg Roelofs
00027             and contributors for the book, "PNG: The Definitive Guide,"
00028             published by O'Reilly and Associates.
00029 
00030   ---------------------------------------------------------------------------*/
00031 
00032 
00033 #include <cstdlib>     /* for exit() prototype */
00034 
00035 #include "png.h"        /* libpng header; includes zlib.h and setjmp.h */
00036 #include "writepng.h"   /* typedefs, common macros, public prototypes */
00037 
00038 using namespace std;
00039 
00040 /* local prototype */
00041 
00042 static void writepng_error_handler(png_structp png_ptr, png_const_charp msg);
00043 
00044 
00045 
00046 void writepng_version_info(void)
00047 {
00048   fprintf(stderr, "   Compiled with libpng %s; using libpng %s.\n",
00049     PNG_LIBPNG_VER_STRING, png_libpng_ver);
00050   fprintf(stderr, "   Compiled with zlib %s; using zlib %s.\n",
00051     ZLIB_VERSION, zlib_version);
00052 }
00053 
00054 
00055 
00056 
00057 /* returns 0 for success, 2 for libpng problem, 4 for out of memory, 11 for
00058  *  unexpected pnmtype; note that outfile might be stdout */
00059 
00060 int writepng_init(mainprog_info *mainprog_ptr)
00061 {
00062     png_structp  png_ptr;       /* note:  temporary variables! */
00063     png_infop  info_ptr;
00064     int color_type, interlace_type;
00065 
00066 
00067     /* could also replace libpng warning-handler (final NULL), but no need: */
00068 
00069     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr,
00070       writepng_error_handler, NULL);
00071     if (!png_ptr)
00072         return 4;   /* out of memory */
00073 
00074     info_ptr = png_create_info_struct(png_ptr);
00075     if (!info_ptr) {
00076         png_destroy_write_struct(&png_ptr, NULL);
00077         return 4;   /* out of memory */
00078     }
00079 
00080 
00081     /* setjmp() must be called in every function that calls a PNG-writing
00082      * libpng function, unless an alternate error handler was installed--
00083      * but compatible error handlers must either use longjmp() themselves
00084      * (as in this program) or exit immediately, so here we go: */
00085 
00086     if (setjmp(mainprog_ptr->jmpbuf)) {
00087         png_destroy_write_struct(&png_ptr, &info_ptr);
00088         return 2;
00089     }
00090 
00091 
00092     /* make sure outfile is (re)opened in BINARY mode */
00093 
00094     png_init_io(png_ptr, mainprog_ptr->outfile);
00095 
00096 
00097     /* set the compression levels--in general, always want to leave filtering
00098      * turned on (except for palette images) and allow all of the filters,
00099      * which is the default; want 32K zlib window, unless entire image buffer
00100      * is 16K or smaller (unknown here)--also the default; usually want max
00101      * compression (NOT the default); and remaining compression flags should
00102      * be left alone */
00103 
00104     png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
00105 /*
00106     >> this is default for no filtering; Z_FILTERED is default otherwise:
00107     png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
00108     >> these are all defaults:
00109     png_set_compression_mem_level(png_ptr, 8);
00110     png_set_compression_window_bits(png_ptr, 15);
00111     png_set_compression_method(png_ptr, 8);
00112  */
00113 
00114 
00115     /* set the image parameters appropriately */
00116 
00117     if (mainprog_ptr->pnmtype == 5)
00118         color_type = PNG_COLOR_TYPE_GRAY;
00119     else if (mainprog_ptr->pnmtype == 6)
00120         color_type = PNG_COLOR_TYPE_RGB;
00121     else if (mainprog_ptr->pnmtype == 8)
00122         color_type = PNG_COLOR_TYPE_RGB_ALPHA;
00123     else {
00124         png_destroy_write_struct(&png_ptr, &info_ptr);
00125         return 11;
00126     }
00127 
00128     interlace_type = mainprog_ptr->interlaced? PNG_INTERLACE_ADAM7 :
00129                                                PNG_INTERLACE_NONE;
00130 
00131     png_set_IHDR(png_ptr, info_ptr, mainprog_ptr->width, mainprog_ptr->height,
00132       mainprog_ptr->sample_depth, color_type, interlace_type,
00133       PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00134 
00135     if (mainprog_ptr->gamma > 0.0)
00136         png_set_gAMA(png_ptr, info_ptr, mainprog_ptr->gamma);
00137 
00138     if (mainprog_ptr->have_bg) {   /* we know it's RGBA, not gray+alpha */
00139         png_color_16  background;
00140 
00141         background.red = mainprog_ptr->bg_red;
00142         background.green = mainprog_ptr->bg_green;
00143         background.blue = mainprog_ptr->bg_blue;
00144         png_set_bKGD(png_ptr, info_ptr, &background);
00145     }
00146 
00147     if (mainprog_ptr->have_time) {
00148         png_time  modtime;
00149 
00150         png_convert_from_time_t(&modtime, mainprog_ptr->modtime);
00151         png_set_tIME(png_ptr, info_ptr, &modtime);
00152     }
00153 
00154     if (mainprog_ptr->have_text) {
00155         png_text  text[6];
00156         int  num_text = 0;
00157 
00158         if (mainprog_ptr->have_text & TEXT_TITLE) {
00159             text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
00160             text[num_text].key = "Title";
00161             text[num_text].text = mainprog_ptr->title;
00162             ++num_text;
00163         }
00164         if (mainprog_ptr->have_text & TEXT_AUTHOR) {
00165             text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
00166             text[num_text].key = "Author";
00167             text[num_text].text = mainprog_ptr->author;
00168             ++num_text;
00169         }
00170         if (mainprog_ptr->have_text & TEXT_DESC) {
00171             text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
00172             text[num_text].key = "Description";
00173             text[num_text].text = mainprog_ptr->desc;
00174             ++num_text;
00175         }
00176         if (mainprog_ptr->have_text & TEXT_COPY) {
00177             text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
00178             text[num_text].key = "Copyright";
00179             text[num_text].text = mainprog_ptr->copyright;
00180             ++num_text;
00181         }
00182         if (mainprog_ptr->have_text & TEXT_EMAIL) {
00183             text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
00184             text[num_text].key = "E-mail";
00185             text[num_text].text = mainprog_ptr->email;
00186             ++num_text;
00187         }
00188         if (mainprog_ptr->have_text & TEXT_URL) {
00189             text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
00190             text[num_text].key = "URL";
00191             text[num_text].text = mainprog_ptr->url;
00192             ++num_text;
00193         }
00194         png_set_text(png_ptr, info_ptr, text, num_text);
00195     }
00196 
00197 
00198     /* write all chunks up to (but not including) first IDAT */
00199 
00200     png_write_info(png_ptr, info_ptr);
00201 
00202 
00203     /* if we wanted to write any more text info *after* the image data, we
00204      * would set up text struct(s) here and call png_set_text() again, with
00205      * just the new data; png_set_tIME() could also go here, but it would
00206      * have no effect since we already called it above (only one tIME chunk
00207      * allowed) */
00208 
00209 
00210     /* set up the transformations:  for now, just pack low-bit-depth pixels
00211      * into bytes (one, two or four pixels per byte) */
00212 
00213     png_set_packing(png_ptr);
00214 /*  png_set_shift(png_ptr, &sig_bit);  to scale low-bit-depth values */
00215 
00216 
00217     /* make sure we save our pointers for use in writepng_encode_image() */
00218 
00219     mainprog_ptr->png_ptr = png_ptr;
00220     mainprog_ptr->info_ptr = info_ptr;
00221 
00222 
00223     /* OK, that's all we need to do for now; return happy */
00224 
00225     return 0;
00226 }
00227 
00228 
00229 
00230 
00231 
00232 /* returns 0 for success, 2 for libpng (longjmp) problem */
00233 
00234 int writepng_encode_image(mainprog_info *mainprog_ptr)
00235 {
00236     png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
00237     png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
00238 
00239 
00240     /* as always, setjmp() must be called in every function that calls a
00241      * PNG-writing libpng function */
00242 
00243     if (setjmp(mainprog_ptr->jmpbuf)) {
00244         png_destroy_write_struct(&png_ptr, &info_ptr);
00245         mainprog_ptr->png_ptr = NULL;
00246         mainprog_ptr->info_ptr = NULL;
00247         return 2;
00248     }
00249 
00250 
00251     /* and now we just write the whole image; libpng takes care of interlacing
00252      * for us */
00253 
00254     png_write_image(png_ptr, mainprog_ptr->row_pointers);
00255 
00256 
00257     /* since that's it, we also close out the end of the PNG file now--if we
00258      * had any text or time info to write after the IDATs, second argument
00259      * would be info_ptr, but we optimize slightly by sending NULL pointer: */
00260 
00261     png_write_end(png_ptr, NULL);
00262 
00263     return 0;
00264 }
00265 
00266 
00267 
00268 
00269 
00270 /* returns 0 if succeeds, 2 if libpng problem */
00271 
00272 int writepng_encode_row(mainprog_info *mainprog_ptr)  /* NON-interlaced only! */
00273 {
00274     png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
00275     png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
00276 
00277 
00278     /* as always, setjmp() must be called in every function that calls a
00279      * PNG-writing libpng function */
00280 
00281     if (setjmp(mainprog_ptr->jmpbuf)) {
00282         png_destroy_write_struct(&png_ptr, &info_ptr);
00283         mainprog_ptr->png_ptr = NULL;
00284         mainprog_ptr->info_ptr = NULL;
00285         return 2;
00286     }
00287 
00288 
00289     /* image_data points at our one row of image data */
00290 
00291     png_write_row(png_ptr, mainprog_ptr->image_data);
00292 
00293     return 0;
00294 }
00295 
00296 
00297 
00298 
00299 
00300 /* returns 0 if succeeds, 2 if libpng problem */
00301 
00302 int writepng_encode_finish(mainprog_info *mainprog_ptr)   /* NON-interlaced! */
00303 {
00304     png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
00305     png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
00306 
00307 
00308     /* as always, setjmp() must be called in every function that calls a
00309      * PNG-writing libpng function */
00310 
00311     if (setjmp(mainprog_ptr->jmpbuf)) {
00312         png_destroy_write_struct(&png_ptr, &info_ptr);
00313         mainprog_ptr->png_ptr = NULL;
00314         mainprog_ptr->info_ptr = NULL;
00315         return 2;
00316     }
00317 
00318 
00319     /* close out PNG file; if we had any text or time info to write after
00320      * the IDATs, second argument would be info_ptr: */
00321 
00322     png_write_end(png_ptr, NULL);
00323 
00324     return 0;
00325 }
00326 
00327 
00328 
00329 
00330 
00331 void writepng_cleanup(mainprog_info *mainprog_ptr)
00332 {
00333     png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
00334     png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
00335 
00336     if (png_ptr && info_ptr)
00337         png_destroy_write_struct(&png_ptr, &info_ptr);
00338 }
00339 
00340 
00341 
00342 
00343 
00344 static void writepng_error_handler(png_structp png_ptr, png_const_charp msg)
00345 {
00346     mainprog_info  *mainprog_ptr;
00347 
00348     /* This function, aside from the extra step of retrieving the "error
00349      * pointer" (below) and the fact that it exists within the application
00350      * rather than within libpng, is essentially identical to libpng's
00351      * default error handler.  The second point is critical:  since both
00352      * setjmp() and longjmp() are called from the same code, they are
00353      * guaranteed to have compatible notions of how big a jmp_buf is,
00354      * regardless of whether _BSD_SOURCE or anything else has (or has not)
00355      * been defined. */
00356 
00357     fprintf(stderr, "writepng libpng error: %s\n", msg);
00358     fflush(stderr);
00359 
00360     mainprog_ptr = (mainprog_info*) png_get_error_ptr(png_ptr);
00361     if (mainprog_ptr == NULL) {         /* we are completely hosed now */
00362         fprintf(stderr,
00363           "writepng severe error:  jmpbuf not recoverable; terminating.\n");
00364         fflush(stderr);
00365         exit(99);
00366     }
00367 
00368     longjmp(mainprog_ptr->jmpbuf, 1);
00369 }

Generated on Sat Apr 1 09:04:27 2006 for GXSM by  doxygen 1.4.6