#include <pngutil.h>
Public Member Functions | |
CC_DECLARE_MEMDUMP (PNGUtil) | |
PNGUtil () | |
Default constructor for the class. | |
~PNGUtil () | |
Default destructor for the class. | |
Static Public Member Functions | |
static BOOL | ReadFromFile (CCLexFile *File, LPBITMAPINFO *Info, LPBYTE *Bits, INT32 *TransColour, String_64 *ProgressString=NULL, BaseCamelotFilter *pFilter=NULL) |
Reads a .PNG file into memory decompressing it as it goes. Errors on 16-bit builds*** A progress hourglass can be shown if required. | |
static void | DefaultErrorHandler () |
To handle errors within the PNG code in a nice fashion. Assumes a TRY CATCH block is present and a valid CCLexFile is specified as it uses the CCLexFile::GotError to throw an exception. This should become redundant as we replace the PNG error handling with IDs. | |
static BOOL | SetCCFilePointer (CCLexFile *pNewFile) |
Public access to the pFile exception handling pointer. | |
static CCLexFile * | GetCCFilePointer () |
Public access to the pFile exception handling pointer. | |
Static Protected Member Functions | |
static BOOL | ReadColourMap (INT32 Png_Entries, png_colorp pPNGPalette, INT32 number, LPRGBQUAD lpPalette) |
Copy the palette entries across from the PNG palette to the bitmap palette in Camelot. | |
static BOOL | GenerateGreyPalette (INT32 PaletteSize, LPRGBQUAD lpPalette) |
Generate a greyscale palette for a greyscale DIB. | |
Static Private Attributes | |
static INT32 | Transparent = -1 |
static CCLexFile * | pFile = NULL |
Definition at line 125 of file pngutil.h.
|
Default constructor for the class.
Definition at line 175 of file pngutil.cpp.
|
|
Default destructor for the class.
Definition at line 189 of file pngutil.cpp.
|
|
|
|
To handle errors within the PNG code in a nice fashion. Assumes a TRY CATCH block is present and a valid CCLexFile is specified as it uses the CCLexFile::GotError to throw an exception. This should become redundant as we replace the PNG error handling with IDs.
Definition at line 679 of file pngutil.cpp. 00680 { 00681 // Use the CCLexFile GotError function to do the error handling for us 00682 // Assumes TRY CATCH block in use 00683 if (pFile) 00684 { 00685 // if (pMessage) 00686 // pFile->GotError(MessageID, pMessage); 00687 // else 00688 // pFile->GotError(MessageID); 00689 pFile->GotError(_R(IDS_UNKNOWN_PNG_ERROR)); 00690 } 00691 00692 // This is the fall back position of oh my god we must stop execution as otherwise things 00693 // will go pear shaped. 00694 // ERROR2RAW(MessageID); 00695 ERROR2RAW(1); 00696 00697 // Use the C++ exception handling 00698 //AfxThrowFileException(CFileException::generic, _R(IDS_UNKNOWN_PNG_ERROR)); 00699 }
|
|
Generate a greyscale palette for a greyscale DIB.
Definition at line 752 of file pngutil.cpp. 00753 { 00754 ERROR2IF(lpPalette == NULL,FALSE,"PNGUtil::GenerateGreyPalette no lpPalette present"); 00755 ERROR2IF(PaletteSize <= 0,FALSE,"PNGUtil::GenerateGreyPalette no PNG palette entries present"); 00756 00757 // Work out the value we require per step so on a:- 00758 // 256 colour palette we can have 256 steps of 1 00759 // 16 colour palette we have 16 steps of 16 (16 * 16 = 256) 00760 INT32 inc = 255 / (PaletteSize - 1); // Changed so palette has the right range - Jonathan 00761 INT32 value = 0; 00762 for (INT32 i = 0; i < PaletteSize; i++ ) 00763 { 00764 lpPalette->rgbBlue = value; 00765 lpPalette->rgbGreen = value; 00766 lpPalette->rgbRed = value; 00767 lpPalette->rgbReserved = 0; 00768 lpPalette++; 00769 value += inc; 00770 if (value > 255) 00771 value = 255; 00772 } 00773 00774 return TRUE; 00775 }
|
|
Public access to the pFile exception handling pointer.
Definition at line 655 of file pngutil.cpp. 00656 { 00657 return pFile; 00658 }
|
|
Copy the palette entries across from the PNG palette to the bitmap palette in Camelot.
Definition at line 717 of file pngutil.cpp. 00718 { 00719 ERROR2IF(pPNGPalette == NULL,FALSE,"PNGUtil::ReadColourMap no PNG palette present"); 00720 ERROR2IF(lpPalette == NULL,FALSE,"PNGUtil::ReadColourMap no lpPalette present"); 00721 ERROR2IF(Png_Entries <= 0,FALSE,"PNGUtil::ReadColourMap no PNG palette entries present"); 00722 00723 for (INT32 i = 0; i < Png_Entries; i++) 00724 { 00725 lpPalette->rgbBlue = pPNGPalette->blue; 00726 lpPalette->rgbGreen = pPNGPalette->green; 00727 lpPalette->rgbRed = pPNGPalette->red; 00728 lpPalette->rgbReserved = 0; 00729 lpPalette++; 00730 pPNGPalette++; 00731 } 00732 00733 return TRUE; 00734 }
|
|
Reads a .PNG file into memory decompressing it as it goes. Errors on 16-bit builds*** A progress hourglass can be shown if required.
Definition at line 225 of file pngutil.cpp. 00229 { 00230 TRACEUSER( "Jonathan", _T("PNG read: Start\n")); 00231 *Info = NULL; // in case of early exit 00232 *Bits = NULL; 00233 pFile = File; 00234 Transparent = -1; 00235 *TransColour = -1; // in case of early exit set to none 00236 00237 UINT32 sig_read = 0; 00238 png_uint_32 width, height; 00239 INT32 bit_depth, color_type, interlace_type; 00240 00241 BOOL OldThrowingState = File->SetThrowExceptions( TRUE ); 00242 BOOL OldReportingState = File->SetReportErrors( FALSE ); 00243 00244 png_structp png_ptr = 0; // Must be zero to avoid bad free in case of exception 00245 png_infop info_ptr = 0; // Must be zero to avoid bad free in case of exception 00246 00247 png_bytepp ppbRowPointers= 0; // Must be zero to avoid bad free in case of exception 00248 00249 try { 00250 /* Create and initialize the png_struct with the desired error handler 00251 * functions. If you want to use the default stderr and longjump method, 00252 * you can supply NULL for the last three parameters. We also supply the 00253 * the compiler header file version, so that we know if the application 00254 * was compiled with a compatible version of the library. REQUIRED 00255 */ 00256 // png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 00257 // png_voidp user_error_ptr, user_error_fn, user_warning_fn); 00258 png_ptr = png_create_read_struct_2( 00259 PNG_LIBPNG_VER_STRING, // Version of libpng 00260 0, // Optional pointer to be sent with errors 00261 camelot_png_error, // Function called in case of error 00262 camelot_png_warning, // Function called for warnings 00263 0, // Optional pointer to be sent with mem ops 00264 camelot_png_malloc, // Function called to alloc memory 00265 camelot_png_free // Function called to free memory 00266 ); 00267 00268 if (png_ptr == NULL) 00269 File->GotError( _R(IDS_OUT_OF_MEMORY) ); 00270 00271 /* Allocate/initialize the memory for image information. REQUIRED. */ 00272 info_ptr = png_create_info_struct(png_ptr); 00273 if (info_ptr == NULL) 00274 { 00275 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); 00276 File->GotError( _R(IDS_OUT_OF_MEMORY) ); 00277 } 00278 00279 /* Set up the input control if you are using standard C streams */ 00280 iostream* pFStream = File->GetIOFile(); 00281 // Should use our own IO functions eg. 00282 png_set_read_fn(png_ptr, pFStream, camelot_png_read_data); 00283 // png_init_io(png_ptr, pFStream); 00284 00285 /* If we have already read some of the signature */ 00286 // Not sure about this - JP 00287 png_set_sig_bytes(png_ptr, sig_read); 00288 00289 /* The call to png_read_info() gives us all of the information from the 00290 * PNG file before the first IDAT (image data chunk). REQUIRED */ 00291 png_read_info(png_ptr, info_ptr); 00292 00293 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 00294 &interlace_type, NULL, NULL); 00295 00296 TRACEUSER( "Jonathan", _T("PNG read: Start transforms: %d channels of %d bits\n"), 00297 png_get_channels(png_ptr, info_ptr), 00298 png_get_bit_depth(png_ptr, info_ptr)); 00299 00300 /* tell libpng to strip 16 bit/color files down to 8 bits/color */ 00301 png_set_strip_16(png_ptr); 00302 00303 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ 00304 /* JP - Changed so just 2 bit images are expanded */ 00305 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 2) 00306 png_set_expand(png_ptr); 00307 00308 /* Expand paletted images to the full 8 bits from 2 bits/pixel */ 00309 if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth == 2) 00310 png_set_expand(png_ptr); 00311 00312 if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) 00313 png_set_gray_to_rgb(png_ptr); 00314 00315 /* Note that screen gamma is the display_exponent, which includes 00316 * the CRT_exponent and any correction for viewing conditions */ 00317 /* A good guess for a PC monitors in a dimly lit room is 2.2 */ 00318 const double screen_gamma = 2.2; 00319 00320 png_set_invert_alpha(png_ptr); 00321 00322 INT32 intent; 00323 00324 if (png_get_sRGB(png_ptr, info_ptr, &intent)) 00325 png_set_gamma(png_ptr, screen_gamma, 0.45455); 00326 else 00327 { 00328 double image_gamma; 00329 if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) 00330 png_set_gamma(png_ptr, screen_gamma, image_gamma); 00331 else 00332 png_set_gamma(png_ptr, screen_gamma, 0.45455); 00333 } 00334 00335 /* flip the RGB pixels to BGR (or RGBA to BGRA) */ 00336 if (color_type & PNG_COLOR_MASK_COLOR) 00337 png_set_bgr(png_ptr); 00338 00339 /* Scan the palletes */ 00340 png_colorp pPalette; 00341 INT32 num_palette; 00342 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) 00343 png_get_PLTE(png_ptr, info_ptr, &pPalette, &num_palette); 00344 00345 // TRACEUSER( "Jonathan", _T("PNG read: Number of palette colours = %d\n"), num_palette); 00346 00347 png_bytep pTrans; 00348 INT32 num_trans = 0; // if the 'if' statement is falue 0 is the correct value 00349 png_color_16p trans_values; 00350 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) 00351 png_get_tRNS(png_ptr, info_ptr, &pTrans, &num_trans, &trans_values); 00352 00353 TRACEUSER( "Jonathan", _T("PNG read: Number of transparent colours = %d\n"), num_trans); 00354 00355 00356 /* Take a look at the transparency list and see it there is only one 00357 colour which is not opaque and that that colour is fully transparent 00358 (so the exported bitmap can have one-bit transparency). If this 00359 condition is not meet, convert the bitmap up to full alpha transparency 00360 (should really give a bitmap that has paletted RGBA but the interface 00361 to the PNG stuff appears to limit our options). 00362 00363 Warning: If the PNG reading code is asked for 256 colour with a 00364 transparent colour, it must do this, otherwise the export dialog 00365 will go wrong when it re-imports the file for preview as it can not find 00366 a palette. */ 00367 00368 if ( 00369 png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr) <= 8 00370 && png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE 00371 ) 00372 { 00373 if (num_trans > 0) 00374 { 00375 // See if the palette has the format 00376 // Opaque (=256) 00377 // Opaque (=256) 00378 // Opaque (=256) 00379 // .... 00380 // Fully transparent (=0) 00381 // so we can use a one bit transparency paletted RGB image 00382 INT32 i = 0; 00383 png_byte * pCurrentTransEntry = pTrans; 00384 00385 // Scan throught opaque entrys 00386 while (i <= num_trans && pCurrentTransEntry[i] == 255) 00387 i++; 00388 00389 // This looks like a good bet for transparent colour 00390 if (pCurrentTransEntry[i] == 0) 00391 *TransColour = i; 00392 00393 // Check any entrys after this to make sure they are not transparent 00394 if (i < num_trans) 00395 i++; 00396 00397 while (i <= num_trans && pCurrentTransEntry[i] == 255) 00398 i++; 00399 00400 // Check we got to the end of the palette without finding any other 00401 // transparent colours 00402 if (i != num_trans) 00403 { 00404 // There are other transparent colours so convert to RGBA 00405 *TransColour = -1; 00406 00407 // Expand paletted or RGB images with transparency to full alpha channels 00408 // so the data will be available as RGBA quartets. 00409 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) 00410 png_set_expand(png_ptr); 00411 TRACEUSER( "Jonathan", _T("PNG read: Transparency: Converted to RGBA as there where multiple transparent colours\n")); 00412 } 00413 else 00414 { 00415 TRACEUSER( "Jonathan", _T("PNG read: Transparency: Only one transparent colour so keep the images as paletted\n")); 00416 } 00417 } 00418 else 00419 { 00420 TRACEUSER( "Jonathan", _T("PNG read: Transparency: No work needed as no transparency\n")); 00421 } 00422 } 00423 else 00424 { 00425 TRACEUSER( "Jonathan", _T("PNG read: Transparency: No work needed as no palette\n")); 00426 } 00427 00428 TRACEUSER( "Jonathan", _T("PNG read: transparent colour = %d\n"), *TransColour); 00429 00430 Transparent = *TransColour; 00431 00432 /* Optional call to gamma correct and add the background to the palette 00433 * and update info structure. REQUIRED if you are expecting libpng to 00434 * update the palette for you (ie you selected such a transform above). */ 00435 png_read_update_info(png_ptr, info_ptr); 00436 00437 /* Turn on interlace handling. REQUIRED if you are not using 00438 * png_read_image(). To see how to handle interlacing passes, 00439 * see the png_read_row() method below: */ 00440 // INT32 number_passes = png_set_interlace_handling(png_ptr); 00441 00442 00443 TRACEUSER( "Jonathan", _T("PNG read: End transforms: %d channels of %d bits\n"), 00444 png_get_channels(png_ptr, info_ptr), 00445 png_get_bit_depth(png_ptr, info_ptr)); 00446 00447 /* Allocate the memory to hold the image using the fields of info_ptr. */ 00448 INT32 bits_per_pixel = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr); 00449 if (bits_per_pixel == 1 || bits_per_pixel == 4 || bits_per_pixel == 8 || bits_per_pixel == 16 || bits_per_pixel == 24 || bits_per_pixel == 32) 00450 *Info = AllocDIB(width, height, png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr), Bits, NULL); 00451 else 00452 // This should never happen! 00453 File->GotError( _R(IDS_UNKNOWN_PNG_ERROR) ); 00454 00455 if (*Info == NULL || *Bits == NULL) 00456 File->GotError( _R(IDS_OUT_OF_MEMORY) ); 00457 00458 /* Set the bitmap DPI */ 00459 png_uint_32 x_res, y_res; 00460 INT32 unit_type; 00461 png_get_pHYs(png_ptr, info_ptr, &x_res, &y_res, &unit_type); 00462 TRACEUSER( "Jonathan", _T("PNG read: X dpi: %d, Y dpi %d, DPI type %d\n"), 00463 x_res, y_res, unit_type); 00464 00465 // If the unit type is in meters then use it 00466 if (unit_type == PNG_RESOLUTION_METER) 00467 { 00468 (*Info)->bmiHeader.biXPelsPerMeter = x_res; 00469 (*Info)->bmiHeader.biYPelsPerMeter = y_res; 00470 } 00471 00472 // Check if we require a palette if we are on low bpp images. 00473 // If so then allocate one 00474 if ( 00475 png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr) <= 8 00476 && png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE 00477 ) 00478 { 00479 // Palette is at info_ptr->palette 00480 INT32 PaletteSize = 1 << info_ptr->bit_depth; 00481 // Read in palette into the palette of the DIB 00482 LPRGBQUAD lpPalette = (*Info)->bmiColors; 00483 TRACEUSER( "Jonathan", _T("PNG read: allocate palette and copy size %d\n"),PaletteSize); 00484 00485 // Get our function to read the palette from the PNG definition to the one we are 00486 // going to apply to the bitmap. 00487 if ( 00488 lpPalette == NULL || 00489 !ReadColourMap(num_palette, pPalette, PaletteSize, lpPalette) 00490 ) 00491 { 00492 File->GotError( _R(IDS_PNG_ERR_READ_PALETTE) ); // Should be bad palette error 00493 } 00494 } 00495 else if (png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr) <= 8 00496 && png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY) 00497 { 00498 // We have a greyscale image and so generate a greyscale palette 00499 // Palette is at info_ptr->palette 00500 INT32 PaletteSize = 1 << info_ptr->bit_depth; 00501 TRACEUSER( "Jonathan", _T("PNG read: Greyscale, so set up a greyscale palette for the DIB size %d\n"),PaletteSize); 00502 // Read in palette into the palette of the DIB 00503 LPRGBQUAD lpPalette = (*Info)->bmiColors; 00504 // Get our function to read the palette from the PNG definition to the one we are 00505 // going to apply to the bitmap. 00506 if (lpPalette == NULL || !GenerateGreyPalette(PaletteSize, lpPalette)) 00507 File->GotError( _R(IDS_PNG_ERR_READ_PALETTE) ); // Should be bad palette error 00508 } 00509 00510 /* and allocate memory for an array of row-pointers */ 00511 if ((ppbRowPointers = (png_bytepp) png_malloc(png_ptr, (height) * sizeof(png_bytep))) == NULL) 00512 File->GotError(_R(IDS_OUT_OF_MEMORY)); 00513 00514 /* set the individual row-pointers to point at the correct offsets */ 00515 UINT32 ulRowBytes = png_get_rowbytes(png_ptr, info_ptr); 00516 00517 /* make the row finish on a word boundry */ 00518 if (ulRowBytes % 4 != 0) 00519 ulRowBytes += 4 - (ulRowBytes % 4); 00520 00521 for (UINT32 i = 0; i < height; i++) 00522 ppbRowPointers[height - 1 - i] = *Bits + i * ulRowBytes; 00523 00524 bool interlace; 00525 switch (png_get_interlace_type(png_ptr, info_ptr)) 00526 { 00527 case PNG_INTERLACE_NONE: 00528 interlace = false; 00529 break; 00530 00531 case PNG_INTERLACE_ADAM7: 00532 interlace = true; 00533 break; 00534 00535 default: 00536 File->GotError(_R(IDS_PNG_ERROR_BAD_INTERLACE)); 00537 break; 00538 } 00539 00540 /* Set up the progress bar */ 00541 PORTNOTE("other","PNGUtil::ReadFromFile - removed progressbar") 00542 #ifndef EXCLUDE_FROM_XARALX 00543 PNGProgressBar ProgressBar(ProgressString, interlace, height); 00544 png_progress_bar_read = &ProgressBar; 00545 #endif 00546 png_set_read_status_fn(png_ptr, camelot_png_read_row_callback); 00547 00548 /* now we can go ahead and just read the whole image */ 00549 png_read_image(png_ptr, ppbRowPointers); 00550 00551 #ifndef EXCLUDE_FROM_XARALX 00552 png_progress_bar_read = 0; 00553 #endif 00554 00555 png_free(png_ptr, ppbRowPointers); 00556 00557 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ 00558 png_read_end(png_ptr, info_ptr); 00559 00560 /* At this point the entire image has been read */ 00561 00562 /* clean up after the read, and free any memory allocated - REQUIRED */ 00563 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); 00564 00565 png_ptr = NULL; 00566 00567 /* Must set the exception throwing and reporting flags back to their entry states */ 00568 File->SetThrowExceptions( OldThrowingState ); 00569 File->SetReportErrors( OldReportingState ); 00570 00571 /* Reset the file pointer back to null for safety */ 00572 pFile = NULL; 00573 00574 TRACEUSER( "Jonathan", _T("PNG read: Finshed\n")); 00575 00576 /* that's it */ 00577 return (OK); 00578 } 00579 catch( CFileException ) 00580 { 00581 // catch our form of a file exception 00582 TRACE( _T("PNGUtil::ReadFromFile CC catch handler\n")); 00583 00584 //GAT png_progress_bar_read = 0; 00585 00586 if (ppbRowPointers != 0) 00587 png_free(png_ptr, ppbRowPointers); 00588 00589 /* clean up after the read, and free any memory allocated */ 00590 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); 00591 00592 png_ptr = NULL; 00593 00594 // Now our Camelot related bits 00595 if (*Info != NULL && *Bits != NULL) 00596 FreeDIB( *Info, *Bits ); // free any alloced memory 00597 *Info = NULL; // and NULL the pointers 00598 *Bits = NULL; 00599 00600 // Free up the bit of memory for a palette we grabbed, if present 00601 //if (lpGlobalPalette) 00602 //{ 00603 // CCFree(lpGlobalPalette); 00604 // lpGlobalPalette = NULL; 00605 //} 00606 00607 // Must set the exception throwing and reporting flags back to their entry states 00608 File->SetThrowExceptions( OldThrowingState ); 00609 File->SetReportErrors( OldReportingState ); 00610 00611 // Reset the file pointer back to null for safety 00612 pFile = NULL; 00613 00614 return FALSE; 00615 } 00616 00617 ERROR2( FALSE, "Escaped exception clause somehow" ); 00618 }
|
|
Public access to the pFile exception handling pointer.
Definition at line 635 of file pngutil.cpp.
|
|
|
|
|