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 */