Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

plpngenc.cpp

Go to the documentation of this file.
00001 /*
00002 /--------------------------------------------------------------------
00003 |
00004 |      $Id: plpngenc.cpp,v 1.1 2004/05/21 21:02:53 maxx Exp $
00005 |      PNG Encoder Class
00006 |
00007 |      PNG file encoder. Uses LIBPNG to do the actual conversion.
00008 |      TODO: Error handling is still missing.
00009 |
00010 |      Copyright (c) 1996-1998 Ulrich von Zadow
00011 |
00012 \--------------------------------------------------------------------
00013 */
00014 
00015 #include "plstdpch.h"
00016 
00017 // Quick PNG encoder -- needs more work :)
00018 //
00019 #include <stdarg.h>
00020 #include "plpngenc.h"
00021 #include "png.h"
00022 #include "plbitmap.h"
00023 #include "plexcept.h"
00024 
00025 
00027 // Class functions
00028 
00029 // Creates an encoder
00030 PLPNGEncoder::PLPNGEncoder()
00031   : PLPicEncoder(),
00032     m_pBmp(NULL),
00033     m_pDataSnk(NULL)
00034 {}
00035 
00036 
00037 
00038 PLPNGEncoder::~PLPNGEncoder()
00039 {}
00040 
00041 
00042 PLDataSink * PLPNGEncoder::GetDataSink()
00043 {
00044   return m_pDataSnk;
00045 }
00046 
00047 void raiseError (png_structp png_ptr, png_const_charp message)
00048 {
00049   char msg[256];  // TODO: check buffer size required for error string.
00050   // Note that raiseError has the same maximum!
00051 
00052   strcpy( msg, message );
00053 
00054   PLPicEncoder::raiseError (PL_ERRFORMAT_NOT_SUPPORTED, msg);
00055 }
00056 
00057 void raiseWarning (png_structp png_ptr, png_const_charp message)
00058 {
00059 }
00060 
00061 
00062 void EncodeExtraInfo (png_structp png_ptr)
00063 {
00064   /* Optionally write comments into the image */
00065   /*
00066    text_ptr[0].key = "Title";
00067    text_ptr[0].text = "Mona Lisa";
00068    text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
00069    text_ptr[1].key = "Author";
00070    text_ptr[1].text = "Leonardo DaVinci";
00071    text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
00072    text_ptr[2].key = "Description";
00073    text_ptr[2].text = "<long text>";
00074    text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
00075    png_set_text(png_ptr, info_ptr, text_ptr, 3);
00076   */
00077 
00078   /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */
00079   /* note that if sRGB is present the cHRM chunk must be ignored
00080    * on read and must be written in accordance with the sRGB profile */
00081 }
00082 
00083 void EncodeTransformation (PLBmp * pBmp, png_structp png_ptr)
00084 {
00085   /* Once we write out the header, the compression type on the text
00086    * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
00087    * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
00088    * at the end.
00089    */
00090 
00091   /* set up the transformations you want.  Note that these are
00092    * all optional.  Only call them if you want them.
00093    */
00094 
00095   /* invert monocrome pixels */
00096   //png_set_invert_mono(png_ptr);
00097 
00098   /* Shift the pixels up to a legal bit depth and fill in
00099    * as appropriate to correctly scale the image.
00100    */
00101   //png_set_shift(png_ptr, &sig_bit);
00102 
00103   /* pack pixels into bytes */
00104   //png_set_packing(png_ptr);
00105 
00106   /* swap location of alpha bytes from ARGB to RGBA */
00107   //png_set_swap_alpha(png_ptr);
00108 
00109   /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
00110    * RGB (4 channels -> 3 channels). The second parameter is not used.
00111    */
00112   if (pBmp->GetBitsPerPixel() == 32 && !(pBmp->HasAlpha()))
00113     png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
00114 
00115 #ifdef PL_PIXEL_BGRA_ORDER
00116   /* flip BGR pixels to RGB if this is the paintlib order */
00117   png_set_bgr(png_ptr);
00118 #endif
00119 
00120   /* swap bytes of 16-bit files to most significant byte first */
00121   //png_set_swap(png_ptr);
00122 
00123   /* swap bits of 1, 2, 4 bit packed pixel formats */
00124   //png_set_packswap(png_ptr);
00125 }
00126 
00127 
00128 png_color * createPNGPalette(PLBmp * pBmp, png_structp png_ptr)
00129 {
00130   int i;
00131   png_color * pPNGPal = (png_colorp)png_malloc(png_ptr, 256 * sizeof (png_color));
00132   PLPixel32 * pBmpPal = pBmp->GetPalette();
00133 
00134   for (i=0; i<256; i++)
00135   {
00136     PLBYTE * pPalEntry = (PLBYTE *)(pBmpPal+i);
00137     pPNGPal[i].red = pPalEntry[PL_RGBA_RED];
00138     pPNGPal[i].green = pPalEntry[PL_RGBA_GREEN];
00139     pPNGPal[i].blue = pPalEntry[PL_RGBA_BLUE];
00140   }
00141   return pPNGPal;
00142 }
00143 
00144 void EncodeData (png_structp png_ptr, png_bytep data, png_size_t length)
00145 {
00146   PLPNGEncoder *pClass;
00147 
00148   pClass = (PLPNGEncoder *)(png_ptr->io_ptr);
00149 
00150   PLASSERT (pClass);
00151   PLDataSink * pSink = pClass->GetDataSink();
00152   PLASSERT (pSink);
00153 
00154   // Write out PNG data & raise an error if the write fails
00155 
00156   if (pSink->WriteNBytes( length, data ) != length)
00157   {
00158     png_error(png_ptr, "Error writting file");
00159   }
00160   return;
00161 }
00162 
00163 void FlushData (png_structp png_ptr)
00164 {
00165   // Do nothing for now.
00166 }
00167 
00168 
00169 void PLPNGEncoder::DoEncode (PLBmp * pBmp, PLDataSink* pDataSnk)
00170 {
00171   png_structp png_ptr;
00172   png_infop info_ptr;
00173   png_color_8 sig_bit;
00174 
00175   /* Create and initialize the png_struct with the desired error handler
00176    * functions.  If you want to use the default stderr and longjump method,
00177    * you can supply NULL for the last three parameters.  We also check that
00178    * the library version is compatible with the one used at compile time,
00179    * in case we are using dynamically linked libraries.  REQUIRED.
00180    */
00181   png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
00182                                     (png_voidp) pDataSnk->GetName(), ::raiseError, ::raiseWarning);
00183 
00184   if (png_ptr == NULL)
00185   {
00186     /* close the file */
00187     return;
00188   }
00189 
00190   /* Allocate/initialize the image information data.  REQUIRED */
00191   info_ptr = png_create_info_struct(png_ptr);
00192   if (info_ptr == NULL)
00193   {
00194     /* close the file */
00195     // TODO: We should raise an exception so the caller knows what's
00196     // going on.
00197     png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
00198     return;
00199   }
00200 
00201   /* Set error handling.  REQUIRED if you aren't supplying your own
00202    * error handling functions in the png_create_write_struct() call.
00203    */
00204   if (setjmp(png_ptr->jmpbuf))
00205   {
00206     /* If we get here, we had a problem reading the file */
00207     /* close the file */
00208     png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
00209     return;
00210   }
00211 
00212   m_pBmp = pBmp;
00213   m_pDataSnk = pDataSnk;
00214 
00215   /* If you are using replacement read functions, instead of calling
00216    * png_init_io() here you would call */
00217   png_set_write_fn(png_ptr, (void *)this, EncodeData, FlushData);
00218   /* where pWriteInfo is a structure you want available to the callbacks */
00219 
00220 
00221   /* Set the image information here.  Width and height are up to 2^31,
00222    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
00223    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
00224    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
00225    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
00226    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
00227    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
00228    */
00229 
00230   int bit_depth, color_type;
00231 
00232   switch(pBmp->GetBitsPerPixel())
00233   {
00234     case 1:
00235       bit_depth = 1;
00236       color_type = PNG_COLOR_TYPE_GRAY;
00237       break;
00238     case 8:
00239       bit_depth = 8;
00240       color_type = PNG_COLOR_TYPE_PALETTE;
00241       break;
00242     case 24:
00243     case 32:
00244       bit_depth = 8;
00245       if (pBmp->HasAlpha())
00246         color_type = PNG_COLOR_TYPE_RGB_ALPHA;
00247       else
00248         color_type = PNG_COLOR_TYPE_RGB;
00249       break;
00250     default:
00251       // Can't handle other bit depths.
00252       PLASSERT (false);
00253   }
00254 
00255   png_set_IHDR (png_ptr,
00256                 info_ptr,
00257                 pBmp->GetWidth(),
00258                 pBmp->GetHeight(),
00259                 bit_depth,
00260                 color_type,
00261                 PNG_INTERLACE_NONE,
00262                 PNG_COMPRESSION_TYPE_BASE,
00263                 PNG_FILTER_TYPE_BASE);
00264 
00265 
00266   /* set the palette if there is one.  REQUIRED for indexed-color images */
00267   if (pBmp->GetPalette())
00268   {
00269     png_color * pPalette = createPNGPalette (pBmp, png_ptr);
00270     png_set_PLTE(png_ptr, info_ptr, pPalette, 256);
00271   }
00272 
00273   // TODO: Set grey or B&W information if available
00274 
00275   /* optional significant bit chunk */
00276   /* if we are dealing with a grayscale image then */
00277   //sig_bit.gray = true_bit_depth;
00278 
00279   /* otherwise, if we are dealing with a color image then */
00280   sig_bit.red   = bit_depth;
00281   sig_bit.green = bit_depth;
00282   sig_bit.blue  = bit_depth;
00283 
00284   if (pBmp->HasAlpha())
00285     sig_bit.alpha = 8;
00286   else
00287     sig_bit.alpha = 0;
00288   png_set_sBIT(png_ptr, info_ptr, &sig_bit);
00289 
00290   PLPoint Res = pBmp->GetResolution();
00291   if (Res.x != 0)
00292     png_set_pHYs(png_ptr, info_ptr, 
00293                  int (double(Res.x) * 39.37f), int (double (Res.y) * 39.37f),
00294                  PNG_RESOLUTION_METER);
00295   else
00296     png_set_pHYs(png_ptr, info_ptr, 0, 0, PNG_RESOLUTION_UNKNOWN);
00297 
00298   /* Optional gamma chunk is strongly suggested if you have any guess
00299    * as to the correct gamma of the image.
00300    */
00301   /*
00302   png_set_gAMA(png_ptr, info_ptr, gamma);
00303   */
00304 
00305   /* Write text image fields */
00306   EncodeExtraInfo( png_ptr );
00307 
00308   /* Write the file header information.  REQUIRED */
00309   png_write_info(png_ptr, info_ptr);
00310 
00311   /* Write image image transformation fields */
00312   EncodeTransformation(pBmp, png_ptr );
00313 
00314 
00315   /* turn on interlace handling if you are not using png_write_image() */
00316   //if (interlacing)
00317   //   number_passes = png_set_interlace_handling(png_ptr);
00318   //else
00319   int number_passes = 1;
00320 
00321   // iterate over data and write it out
00322   PLBYTE **pla = pBmp->GetLineArray();
00323   PLASSERT( pla );
00324 
00325   png_write_image(png_ptr, pla);
00326 
00327 
00328   /* You can write optional chunks like tEXt, zTXt, and tIME at the end
00329    * as well.
00330    */
00331 
00332   /* It is REQUIRED to call this to finish writing the rest of the file */
00333   png_write_end(png_ptr, info_ptr);
00334 
00335   /* if you allocated any text comments, free them here */
00336 
00337   /* clean up after the write, and free any memory allocated */
00338   png_destroy_write_struct(&png_ptr, &info_ptr);
00339 }
00340 
00341 /*
00342 /--------------------------------------------------------------------
00343 |
00344 |      $Log: plpngenc.cpp,v $
00345 |      Revision 1.1  2004/05/21 21:02:53  maxx
00346 |      Initial Version of vuVolume, moderatly changed to make it compile on my windows and linux machine.
00347 |
00348 |      Revision 1.1  2002/11/13 01:58:22  mspindle
00349 |      *** empty log message ***
00350 |
00351 |      Revision 1.5  2001/10/16 17:12:26  uzadow
00352 |      Added support for resolution information (Luca Piergentili)
00353 |
00354 |      Revision 1.4  2001/10/06 22:37:08  uzadow
00355 |      Linux compatibility.
00356 |
00357 |      Revision 1.3  2001/10/06 20:44:45  uzadow
00358 |      Linux compatibility
00359 |
00360 |      Revision 1.2  2001/09/28 19:50:56  uzadow
00361 |      Added some 24 bpp stuff & other minor features.
00362 |
00363 |      Revision 1.1  2001/09/16 19:03:22  uzadow
00364 |      Added global name prefix PL, changed most filenames.
00365 |
00366 |      Revision 1.12  2001/09/13 20:43:57  uzadow
00367 |      Removed palette free that was causing crashes under linux.
00368 |
00369 |      Revision 1.11  2001/02/04 14:31:52  uzadow
00370 |      Member initialization list cleanup (Erik Hoffmann).
00371 |
00372 |      Revision 1.10  2001/01/12 23:03:43  uzadow
00373 |      Fixed bogus delete of palette for nonpalette images.
00374 |
00375 |      Revision 1.9  2000/12/18 22:42:52  uzadow
00376 |      Replaced RGBAPIXEL with PLPixel32.
00377 |
00378 |      Revision 1.8  2000/07/11 17:11:01  Ulrich von Zadow
00379 |      Added support for RGBA pixel ordering (Jose Miguel Buenaposada Biencinto).
00380 |
00381 |      Revision 1.7  2000/05/28 10:11:46  Ulrich von Zadow
00382 |      Corrected alpha channel handling.
00383 |
00384 |      Revision 1.6  2000/05/27 16:34:05  Ulrich von Zadow
00385 |      Linux compatibility changes
00386 |
00387 |      Revision 1.5  2000/01/16 20:43:14  anonymous
00388 |      Removed MFC dependencies
00389 |
00390 |      Revision 1.4  2000/01/10 23:52:59  Ulrich von Zadow
00391 |      Changed formatting & removed tabs.
00392 |
00393 |      Revision 1.3  2000/01/08 23:24:21  Ulrich von Zadow
00394 |      Added encoder for palette files.
00395 |
00396 |      Revision 1.2  2000/01/08 15:53:12  Ulrich von Zadow
00397 |      Moved several functions to the cpp file so applications don't
00398 |      need the png directory in the include path.
00399 |
00400 |      Revision 1.1  2000/01/04 22:06:16  Ulrich von Zadow
00401 |      Initial version by Neville Richards.
00402 |
00403 |
00404 \--------------------------------------------------------------------
00405 */

Generated on Wed Dec 15 21:20:30 2004 for vuVolume by  doxygen 1.3.9.1