writepng.C

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

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