OutputPNG Class Reference

Contains functions to write a DIB to a PNG in segments, optionally with compression, optionally converting from one depth to another. To use: Open a CCFile for write. Call StartFile to write out the header. Call WriteBlock to write out each block of the bitmap, starting from low memory. When you're done, call TidyUp. Similar to OutputDIB and OutputGIF but strangely enough writes the data as a PNG instead of a BMP or via the AccusoftFilters. More...

#include <outptpng.h>

Inheritance diagram for OutputPNG:

OutputDIB List of all members.

Public Member Functions

 OutputPNG ()
 Default constructor for the class. Just sets up the pointers to our buffers that may be used to be null so that the TidyUp function can do its job.
virtual BOOL StartFile (LPBITMAPINFOHEADER lpHeader, LPLOGPALETTE Palette, UINT32 OutputDepth, DWORD CompressionType, UINT32 FinalHeight, INT32 ExportSize, UINT32 DitherType)
 Get ready to write a PNG to disk, maybe in chunks. In the DIB case we go out to disk, in this case we store the bitmap for possible later use in applying a transparency mask to it.
virtual BOOL ReStartFile (LOGPALETTE *pNewPal)
 Called to reset output before outputing another in a run of multiple images.
virtual BOOL WriteBlock (UINT32 YPos, UINT32 Height, LPBYTE BlockStart, UINT32 InputBPP=32, INT32 ProgressOffset=0)
 Writes a chunk of bitmap data to the device. Assumes a progress hourglass is required and the caller has started an hourglass with a size of 100 and will end it. Notes: Originally this routine assumed that it was being given a 32bpp bmp, but using the InputBPP param it will now handle 8bpp bmps as well...
virtual BOOL SetUpInfoHeader (const LPBITMAPINFOHEADER lpHeader, const UINT32 OutputDepth, const DWORD CompressionType, const UINT32 LIneWidth, const UINT32 FinalHeight, INT32 *PalSize)
 Set up the information header for the DIB.
virtual BOOL TidyUp ()
 When everything has been done via WriteBlock, call this to update the header etc. The caller is responsible for closing the file. The class CANNOT be used for further output until StartFile is called again.
BOOL OutputPNGHeader (CCLexFile *File, INT32 TransColour, BOOL InterlaceState=0)
 Writes out the file header for the cached bitmap within this class.
BOOL OutputPNGHeader (CCLexFile *File, LPBITMAPINFOHEADER pInfo, BOOL InterlaceState, INT32 TransparentColour, LPLOGPALETTE pPalette=NULL, LPRGBQUAD pQuadPalette=NULL)
 Output a PNG header for the specified bitmap to the file. If neither palette is specifed then none will be output.
BOOL OutputPNGBits (CCLexFile *File, LPBYTE pBlockStart, BOOL OneBlock=TRUE, BaseCamelotFilter *pFilter=NULL)
 Output the actual bits of a bitmap as compressed PNG data. Assumes that a header has already been output, possibly using OutputPNGHeader. Assumes that all the data is present.
virtual LPBITMAPINFO GetDestBitmapInfo (void)
 Access function to DestBitmapInfo.
virtual LPBYTE GetDestBitmapBits (void)
 Access function to DestBitmapBytes.

Private Member Functions

BOOL CleanUpPngStructures ()
 Clean up those bits that may have been claimed by the PNG bits.

Private Attributes

LPBITMAPINFO DestBitmapInfo
LPBYTE DestBitmapBytes
LPBYTE pNextStrip
png_structp png_ptr
png_infop info_ptr
INT32 Width
INT32 Height
BOOL Interlace
BOOL Transparent
INT32 BitsPerPixel
INT32 InitCodeSize
LPBYTE DataBuffer
UINT32 WidthOfLine

Detailed Description

Contains functions to write a DIB to a PNG in segments, optionally with compression, optionally converting from one depth to another. To use: Open a CCFile for write. Call StartFile to write out the header. Call WriteBlock to write out each block of the bitmap, starting from low memory. When you're done, call TidyUp. Similar to OutputDIB and OutputGIF but strangely enough writes the data as a PNG instead of a BMP or via the AccusoftFilters.

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/5/96
See also:
OutputDIB; OutputGIF;

Definition at line 131 of file outptpng.h.


Constructor & Destructor Documentation

OutputPNG::OutputPNG  ) 
 

Default constructor for the class. Just sets up the pointers to our buffers that may be used to be null so that the TidyUp function can do its job.

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/5/96
See also:
OutputPNG::TidyUp

OutputDIB;

Definition at line 136 of file outptpng.cpp.

00137 {
00138     OutputFile = NULL;
00139     lpBitmap = NULL;
00140     ExportBuffer = NULL;
00141     DoExportConvert = NULL;
00142     OutputForward = FALSE;
00143 
00144     DestBitmapInfo = NULL;
00145     DestBitmapBytes = NULL;
00146 }


Member Function Documentation

BOOL OutputPNG::CleanUpPngStructures  )  [private]
 

Clean up those bits that may have been claimed by the PNG bits.

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
12/7/96
Parameters:
- [INPUTS]
- [OUTPUTS]
Returns:
TRUE if worked, FALSE if failed (error will be set accordingly but not reported)

Definition at line 773 of file outptpng.cpp.

00774 {
00775     // If our structures are present then clean them out
00776     if (png_ptr)
00777     {
00778         if (info_ptr)
00779         {
00780             // They do not seem to have catered for the palette and transparency structures
00781             if (info_ptr->palette)
00782             {
00783                 CCFree(info_ptr->palette);
00784                 info_ptr->palette = NULL;
00785             }
00786             if (info_ptr->trans)
00787             {
00788                 CCFree(info_ptr->trans);
00789                 info_ptr->trans = NULL;
00790             }
00791         }
00792 
00793         // clean up after the write, and free any memory allocated
00794         png_destroy_write_struct(&png_ptr, &info_ptr);
00795         png_ptr = NULL;
00796     }
00797 
00798     return TRUE;
00799 }

LPBYTE OutputPNG::GetDestBitmapBits void   )  [virtual]
 

Access function to DestBitmapBytes.

Author:
Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
Date:
29/6/00
Parameters:
pPalette - Palette information that we want to copy from [INPUTS]
Returns:
A pointer to the bitmap itself.

Reimplemented from OutputDIB.

Definition at line 984 of file outptpng.cpp.

00985 {
00986     return DestBitmapBytes;
00987 }

LPBITMAPINFO OutputPNG::GetDestBitmapInfo void   )  [virtual]
 

Access function to DestBitmapInfo.

Author:
Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
Date:
29/6/00
Parameters:
pPalette - Palette information that we want to copy from [INPUTS]
Returns:
A pointer to the bitmap information structure.

Reimplemented from OutputDIB.

Definition at line 967 of file outptpng.cpp.

00968 {
00969     return DestBitmapInfo;
00970 }

BOOL OutputPNG::OutputPNGBits CCLexFile File,
LPBYTE  pBlockStart,
BOOL  OneBlock = TRUE,
BaseCamelotFilter pFilter = NULL
 

Output the actual bits of a bitmap as compressed PNG data. Assumes that a header has already been output, possibly using OutputPNGHeader. Assumes that all the data is present.

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/5/96
Parameters:
File pointer to file to output to [INPUTS] pBlockStart actual bitmap data to write out OneBlock if TRUE then have all the data so write it out in one go if FALSE then need to compress in strips pFilter is an alternative way of handling the progress bar, assume the progress bar has been start and just call the IncProgressBarCount in BaseCamelotFilter to do the progress bar update. Defaults to NULL i.e. no progress bar.
- [OUTPUTS]
Returns:
TRUE if worked, FALSE if failed (error will be set accordingly but not reported)

Errors: Calls SetError on FALSE returns.

See also:
OutputPNG::OutputPNGHeader; SeeAlo: OutputPNG::StartFile; OutputPNG::WriteBlock; OutputPNG::TidyUp Scope: static

Definition at line 827 of file outptpng.cpp.

00829 {
00830     ERROR2IF(File==NULL,FALSE,"OutputPNG::OutputPNGHeader File pointer is null");
00831     ERROR2IF(pBlockStart==NULL,FALSE,"OutputPNG::OutputPNGHeader BitmapInfo pointer is null");
00832     // Check we have the PNG related items claimed (NOTE: p at end means pointer and hence implied *)
00833     // This would then imply that OutputPNGHeader has been called
00834     ERROR2IF(png_ptr == NULL || info_ptr == NULL,FALSE,"OutputPNG::OutputPNGHeader PNG related items not set up");
00835 
00836     // Note file in our class variable as used by all the low level routines
00837     OutputFile = File;
00838 
00839     // Must set the exception throwing flag to True and force reporting of errors to False.
00840     // This means that the caller must report an error if the function returns False.
00841     // Any calls to CCFile::GotError will now throw a file exception and should fall into
00842     // the catch handler at the end of the function.
00843     // Replaces the goto's that handled this before.
00844     BOOL OldThrowingState = File->SetThrowExceptions( TRUE );
00845     BOOL OldReportingState = File->SetReportErrors( FALSE );
00846 
00847     try
00848     {
00849         // It is now ready to go and put that data onto the disc
00850         // so wait for the bitmap data to be prepared
00851 
00852         // turn on interlace handling if you are not using png_write_image()
00853         INT32 number_passes = 1;
00854         if (Interlace)
00855             number_passes = png_set_interlace_handling(png_ptr);
00856 
00857         // Work out how often we need to update the progress bar
00858         INT32 UpdateEvery = 1;
00859         if (pFilter == NULL)
00860         {
00861             if (number_passes > 1)
00862                 UpdateEvery = (Height/(100*number_passes) + 1);
00863             else
00864                 UpdateEvery = (Height/100 + 1);
00865         }
00866         INT32 LastProgressUpdate = 0;
00867         // Work out the word/byte rounded line width rather than the pixel width
00868         INT32 WidthOfLine = DIBUtil::ScanlineSize( Width, BitsPerPixel );
00869         // The pointer to the actual bitmap data
00870         LPBYTE pBitsData = pBlockStart;
00871         LPBYTE pData = pBitsData;
00872         BOOL JobState = TRUE;
00873 
00874         // Of course being DIBs we need to write the data out upside down! i.e. bottom to top
00875         for (INT32 pass = 0; pass < number_passes; pass++)
00876         {
00877             pBitsData = pBlockStart;
00878             LastProgressUpdate = 0;
00879             for (INT32 ypos = 0; ypos < Height; ypos++)
00880             {
00881                 // Read in from bottom upwards
00882                 pData = pBitsData + ((Height - 1 - ypos)  * WidthOfLine);
00883                 
00884                 // Write that row out to file
00885                 png_write_row(png_ptr, pData);
00886                 
00887                 // Update the progress count, if required
00888                 if (ypos > (LastProgressUpdate + UpdateEvery))
00889                 {
00890                     // Note the update point so that we know the next one  
00891                     LastProgressUpdate = ypos;
00892 
00893                     // Now update the progress display, started with 100, but only if pFilter is NULL
00894                     if (pFilter == NULL)
00895                         ContinueSlowJob( (INT32)(100 * ypos/Height * (pass + 1)/number_passes) );
00896                     else
00897                     {
00898                         // Ask the pFilter to update the progress bar for us
00899                         JobState = TRUE;
00900                         pFilter->IncProgressBarCount(1);
00901                     }
00902 
00903                     // If JobState is False then the user has probably pressed escape and we should
00904                     // immediately stop what we are doing. 
00905                     if (!JobState)
00906                     {
00907                         File->GotError(_R(IDW_CANCELEXPORT));   // Expects error set on cancel
00908                         return FALSE;
00909                     }
00910                 }
00911             }
00912         }
00913 
00914         // write the rest of the file
00915         png_write_end(png_ptr, info_ptr);
00916 
00917         // Call up function to clean up the png structures
00918         CleanUpPngStructures();
00919 
00920         // Must set the exception throwing and reporting flags back to their entry states
00921         File->SetThrowExceptions( OldThrowingState );
00922         File->SetReportErrors( OldReportingState );
00923 
00924         // We have finished so reset the PNG exception handling
00925         PNGUtil::SetCCFilePointer(NULL);
00926 
00927         TRACEUSER( "Jonathan", _T("PNG write: Finished\n"));
00928 
00929         // er, we seem to have finished OK so say so
00930         return TRUE;
00931     }
00932 
00933 //  CATCH( CFileException, e)
00934     catch (...)
00935     {
00936         // catch our form of a file exception
00937         TRACE( _T("OutputPNG::OutputPNGBits CC catch handler\n"));
00938 
00939         // Call up function to clean up the png structures
00940         CleanUpPngStructures();
00941 
00942         // Must set the exception throwing and reporting flags back to their entry states
00943         File->SetThrowExceptions( OldThrowingState );
00944         File->SetReportErrors( OldReportingState );
00945 
00946         // We have finished so reset the PNG exception handling
00947         PNGUtil::SetCCFilePointer(NULL);
00948 
00949         return FALSE;
00950     }
00951 
00952     ERROR2( FALSE, "Escaped exception clause somehow" );
00953 }   

BOOL OutputPNG::OutputPNGHeader CCLexFile File,
LPBITMAPINFOHEADER  pInfo,
BOOL  InterlaceState,
INT32  TransparentColour,
LPLOGPALETTE  pPalette = NULL,
LPRGBQUAD  pQuadPalette = NULL
 

Output a PNG header for the specified bitmap to the file. If neither palette is specifed then none will be output.

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/5/96
Parameters:
File file to output to [INPUTS] pInfo pointer to the bitmap info header InterlaceState True if want interlacing, False otherwise TransparentColour The transparent colour required pPalette pointer to a palette in LOGPALETTE form (defaults to NULL) OR pQuadPalette pointer to a palette in RGBQUAD form (defaults to NULL)
- [OUTPUTS]
Returns:
TRUE if worked, FALSE if failed (error will be set accordingly but not reported)

Errors: Calls SetError on FALSE returns.

See also:
OutputPNG::StartFile; OutputPNG::WriteBlock; OutputPNG::TidyUp Scope: static

Definition at line 448 of file outptpng.cpp.

00451 {
00452     ERROR2IF(File==NULL,FALSE,"OutputPNG::OutputPNGHeader File pointer is null");
00453     if (pInfo == NULL)
00454         pInfo = &(DestBitmapInfo->bmiHeader);
00455     ERROR2IF(pInfo==NULL,FALSE,"OutputPNG::OutputPNGHeader BitmapInfo pointer is null");
00456     //ERROR2IF(pPalette==NULL && pQuadPalette==NULL,FALSE,"OutputPNG::OutputPNGHeader Bitmap palette pointer is null");
00457 
00458     TRACEUSER( "Jonathan", _T("PNG write: Interlace: %s\n"), InterlaceState ? _T("Yes") : _T("No"));
00459 
00460     // Note file in our class variable as used by all the low level routines
00461     OutputFile = File;
00462 
00463     // Note the specified transparency and interlace states in our class variables
00464     Interlace = InterlaceState;
00465     if (TransparentColour != -1)
00466         Transparent = TRUE;
00467     else
00468         Transparent = FALSE;
00469 
00470     // We are just about to start so set the PNG exception handling up with our CCFile pointer
00471     PNGUtil::SetCCFilePointer(File);
00472     
00473     // Must set the exception throwing flag to True and force reporting of errors to False.
00474     // This means that the caller must report an error if the function returns False.
00475     // Any calls to CCFile::GotError will now throw a file exception and should fall into
00476     // the catch handler at the end of the function.
00477     // Replaces the goto's that handled this before.
00478     BOOL OldThrowingState = File->SetThrowExceptions( TRUE );
00479     BOOL OldReportingState = File->SetReportErrors( FALSE );
00480 
00481     // PNG related items (NOTE: p at end means pointer and hence implied *)
00482     png_ptr     = NULL;
00483     info_ptr    = NULL;
00484 
00485     try
00486     {
00487         // Work out the palette size 
00488         INT32 PalSize = pInfo->biClrUsed;       // How many entries in palette
00489 TRACEUSER( "Jonathan", _T("PNG write: PalSize = %d\n"),PalSize);
00490 
00491         // Set up the class variables
00492         // First the width/height of the bitmap
00493         Width = pInfo->biWidth;
00494         Height = pInfo->biHeight;
00495 TRACEUSER( "Jonathan", _T("PNG write: Width = %d Height = %d\n"),Width,Height);
00496 
00497         BitsPerPixel = pInfo->biBitCount;
00498 
00499         // Start up the PNG writing code
00500 
00501         // allocate the necessary structures
00502         // Use the default handlers
00503         png_ptr = png_create_write_struct_2(
00504             PNG_LIBPNG_VER_STRING,  // libpng version
00505             0,                      // Optional pointer to be sent with errors
00506             camelot_png_error,      // Function called in case of error
00507             camelot_png_warning,    // Function called for warnings
00508             0,                      // Optional pointer to be sent with mem ops
00509             camelot_png_malloc,     // Function called to alloc memory
00510             camelot_png_free        // Function called to free memory
00511             );
00512 
00513         if (!png_ptr)
00514             File->GotError( _R(IDS_OUT_OF_MEMORY) );
00515 
00516         info_ptr = png_create_info_struct(png_ptr);
00517         if (!info_ptr)
00518         {
00519             png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
00520             File->GotError( _R(IDS_OUT_OF_MEMORY) );
00521         }
00522 
00523         // set up the input control to the fstream class
00524         // If not a disk file then panic for the present moment
00525         // Could use the memfile functions for reading and writing as they give us what
00526         // we want. Use the io_ptr and 
00527         iostream* pFStream = File->GetIOFile();
00528         if (pFStream == NULL)
00529         {
00530             TRACEUSER( "Jonathan", _T("PNG write: OutputPNG::OutputPNGHeader No access to IOStream!"));
00531             File->GotError( _R(IDS_UNKNOWN_PNG_ERROR) );
00532         }
00533 
00534         // Should use our own function
00535         png_set_write_fn(png_ptr, pFStream, camelot_png_write_data, camelot_png_flush_data);
00536         // png_init_io(png_ptr, pFStream);
00537 
00538         // You now have the option of modifying how the compression library
00539         // will run.  The following functions are mainly for testing, but
00540         // may be useful in certain special cases, like if you need to
00541         // write png files extremely fast and are willing to give up some
00542         // compression, or if you want to get the maximum possible compression
00543         // at the expense of slower writing.  If you have no special needs
00544         // in this area, let the library do what it wants, as it has been
00545         // carefully tuned to deliver the best speed/compression ratio.
00546         // See the compression library for more details.
00547     
00548         // turn on or off filtering (1 or 0)
00549         //png_set_filtering(png_ptr, 1);
00550 
00551         // compression level (0 - none, 6 - default, 9 - maximum)
00552         //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
00553         //png_set_compression_mem_level(png_ptr, 8);
00554         //png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
00555         //png_set_compression_window_bits(png_ptr, 15);
00556         //png_set_compression_method(png_ptr, 8);
00557 
00558         info_ptr->valid = 0;    // - this describes which optional chunks to write to the
00559                                 // file.  Note that if you are writing a
00560                                 // PNG_COLOR_TYPE_PALETTE file, the PLTE chunk is not
00561                                 // optional, but must still be marked for writing.  To
00562                                 // mark chunks for writing, OR valid with the 
00563                                 // appropriate PNG_INFO_<chunk name> define.
00564         // Set the file information here
00565         info_ptr->width = Width;    // - holds the width of the file
00566         info_ptr->height = Height;  // - holds the height of the file
00567         
00568         // resolution of image
00569         info_ptr->valid |= PNG_INFO_pHYs;
00570         info_ptr->x_pixels_per_unit = pInfo->biXPelsPerMeter;
00571         info_ptr->y_pixels_per_unit = pInfo->biYPelsPerMeter;
00572         info_ptr->phys_unit_type = 1;   // meter
00573 TRACEUSER( "Jonathan", _T("PNG write: X,y dpi = %d %d\n"),info_ptr->x_pixels_per_unit, info_ptr->y_pixels_per_unit);
00574         if (InterlaceState)
00575             info_ptr->interlace_type = 1;   // - currently 0 for none, 1 for interlaced
00576         else
00577             info_ptr->interlace_type = 0;   // - currently 0 for none, 1 for interlaced
00578 
00579         BitsPerPixel                = pInfo->biBitCount;
00580 TRACEUSER( "Jonathan", _T("PNG write: Bitdepth = %d\n"),BitsPerPixel);
00581         info_ptr->palette           = NULL;
00582         info_ptr->num_palette       = 0;
00583         //info_ptr->trans_values    = 0;    // - transparent pixel for non-paletted images
00584         info_ptr->trans             = NULL; // - array of transparent entries for paletted images
00585         info_ptr->num_trans         = 0;    // - number of transparent entries
00586 TRACEUSER( "Jonathan", _T("PNG write: TransColour = %d\n"),TransparentColour);
00587         if ( BitsPerPixel <= 8 )
00588         {
00589             info_ptr->bit_depth = BitsPerPixel; // - holds the bit depth of one of the image channels
00590             info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;  // - describes the channels and what they mean
00591                                                 // see the PNG_COLOR_TYPE_ defines for more information
00592             // set the palette if there is one
00593             info_ptr->valid |= PNG_INFO_PLTE;
00594             INT32 PaletteEntries = pInfo->biClrUsed;
00595             info_ptr->palette = (png_color_struct *)CCMalloc(PaletteEntries * sizeof (png_color));
00596             if (info_ptr->palette == NULL)
00597                 File->GotError( _R(IDS_OUT_OF_MEMORY) );
00598             
00599             info_ptr->num_palette = PaletteEntries;
00600             png_color_struct * pPNGPalette = info_ptr->palette;
00601             // ... set palette colors ...
00602             if (pQuadPalette && PaletteEntries > 0)
00603             {
00604                 // Palette supplied in RGBQUAD form 
00605                 for (INT32 i = 0; i < PaletteEntries; i++)
00606                 {
00607                     pPNGPalette->red    = pQuadPalette->rgbRed;
00608                     pPNGPalette->green  = pQuadPalette->rgbGreen;
00609                     pPNGPalette->blue   = pQuadPalette->rgbBlue;
00610                     // skip to the next palette entry
00611                     pQuadPalette++;
00612                     pPNGPalette++;
00613                 }
00614             }
00615             else if (pPalette && PaletteEntries > 0)
00616             {
00617                 // Palette supplied in LOGPALETTE form 
00618                 for (INT32 i = 0; i < PaletteEntries; i++)
00619                 {
00620                     pPNGPalette->red    = pPalette->palPalEntry[i].peRed;
00621                     pPNGPalette->green  = pPalette->palPalEntry[i].peGreen;
00622                     pPNGPalette->blue   = pPalette->palPalEntry[i].peBlue;
00623                     pPNGPalette++;
00624                 }
00625             }
00626             else
00627                 File->GotError(_R(IDS_PNG_ERR_WRITE_PALETTE));
00628             
00629             // Now check to see if transparency is present or not
00630             if (TransparentColour >= 0 && TransparentColour <= PaletteEntries )
00631             {
00632                 // Create the array of transparent entries for this palette
00633                 // 0 is fully transparent, 255 is fully opaque, regardless of image bit depth
00634                 // We will only create as many as we require, i.e. up to the transparent colour entry
00635                 // rather a full palettes worth
00636                 INT32 NumEntries = TransparentColour + 1;
00637                 info_ptr->trans             = (png_byte *)CCMalloc(NumEntries * sizeof (png_byte)); 
00638                 if (info_ptr->trans)
00639                 {
00640                     // Set the number of transparent entries
00641                     info_ptr->num_trans         = NumEntries;
00642                     png_byte * pTransEntry      = info_ptr->trans;
00643                     info_ptr->valid |= PNG_INFO_tRNS;
00644                     for (INT32 i = 0; i < TransparentColour; i++)
00645                     {
00646                         *pTransEntry = 255; // set it fully opaque
00647                         pTransEntry++;
00648                     }
00649                     // We should now be at the transparent entry so set it fully transparent
00650                     *pTransEntry = 0;
00651                 }
00652             }
00653         }
00654         else if (BitsPerPixel == 24) 
00655         {
00656             // We must be 24 bpp
00657             info_ptr->bit_depth = BitsPerPixel/3;   // - holds the bit depth of one of the image channels
00658             info_ptr->color_type = PNG_COLOR_TYPE_RGB;  // - describes the channels and what they mean
00659             // optional significant bit chunk
00660             //info_ptr->valid |= PNG_INFO_sBIT;
00661             // otherwise, if we are dealing with a color image then
00662             //info_ptr->sig_bit.red = BitsPerPixel/3;
00663             //info_ptr->sig_bit.green = BitsPerPixel/3;
00664             //info_ptr->sig_bit.blue = BitsPerPixel/3;
00665             //info_ptr->sig_bit.gray = 0;
00666             //info_ptr->sig_bit.alpha = 0;
00667         }
00668         else if (BitsPerPixel == 32) 
00669         {
00670             // We must be a 32 bpp
00671             info_ptr->bit_depth = BitsPerPixel/4;   // - holds the bit depth of one of the image channels
00672             info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;    // - describes the channels and what they mean
00673             // optional significant bit chunk
00674             //info_ptr->valid |= PNG_INFO_sBIT;
00675             // otherwise, if we are dealing with a color image then
00676             //info_ptr->sig_bit.red = BitsPerPixel/4;
00677             //info_ptr->sig_bit.green = BitsPerPixel/4;
00678             //info_ptr->sig_bit.blue = BitsPerPixel/4;
00679             // if the image has an alpha channel then
00680             //info_ptr->sig_bit.alpha = BitsPerPixel/4;
00681             //info_ptr->sig_bit.gray = 0;
00682             
00683             // get rid of filler bytes, pack rgb into 3 bytes.  The filler number is not used.
00684             // Only required if stripping 32bpp down to 24bpp
00685             //png_set_filler(png_ptr, 0xFF, PNG_FILLER_BEFORE);
00686         }
00687         else
00688             ERROR2(FALSE,"OutputPNG::OutputPNGHeader Unknown bit depth");
00689 
00690 TRACEUSER( "Jonathan", _T("PNG write: bit_depth = %d color_type = %d\n"),info_ptr->bit_depth,info_ptr->color_type);
00691 
00692         // Could use:-
00693         // if we are dealing with a grayscale image then
00694         //info_ptr->sig_bit.gray = true_bit_depth;
00695 
00696         // gamma        - the gamma the file is written at
00697         info_ptr->hist          = NULL; // - histogram of palette
00698         info_ptr->text          = NULL; // - text comments in the file.
00699         info_ptr->num_text      = 0;    // - number of comments
00700 
00701         // optional gamma chunk is strongly suggested if you have any guess
00702         // as to the correct gamma of the image
00703         //info_ptr->valid |= PNG_INFO_gAMA;
00704         //info_ptr->gamma = gamma;
00705 
00706         // other optional chunks
00707 
00708         // write the file information
00709         png_write_info(png_ptr, info_ptr);
00710 
00711 TRACEUSER( "Jonathan", _T("PNG write: pixel_depth %d channels %d\n"),png_ptr->pixel_depth, png_ptr->channels);
00712 TRACEUSER( "Jonathan", _T("PNG write: rowbytes %d color_type %d\n"),png_ptr->rowbytes, png_ptr->color_type);
00713         // Set up the transformations you want.
00714         // Note: that these are all optional.  Only call them if you want them
00715 
00716         // invert monocrome pixels
00717         //png_set_invert(png_ptr);
00718 
00719         // shift the pixels up to a legal bit depth and fill in as appropriate
00720         // to correctly scale the image
00721         //png_set_shift(png_ptr, &(info_ptr->sig_bit));
00722 
00723         // pack pixels into bytes
00724         //png_set_packing(png_ptr);
00725 
00726         png_set_bgr(png_ptr);
00727 
00728         // swap bytes of 16 bit files to most significant bit first
00729         png_set_swap(png_ptr);
00730 
00731         // Must set the exception throwing and reporting flags back to their entry states
00732         File->SetThrowExceptions( OldThrowingState );
00733         File->SetReportErrors( OldReportingState );
00734 
00735         // er, we seem to have finished OK so say so
00736         return TRUE;
00737     }
00738     
00739     catch (...)
00740     {
00741         // catch our form of a file exception
00742         TRACE( _T("OutputPNG::OutputPNGHeader CC catch handler\n"));
00743 
00744         // Call up function to clean up the png structures
00745         CleanUpPngStructures();
00746 
00747         // Must set the exception throwing and reporting flags back to their entry states
00748         File->SetThrowExceptions( OldThrowingState );
00749         File->SetReportErrors( OldReportingState );
00750 
00751         // We have finished so reset the PNG exception handling
00752         PNGUtil::SetCCFilePointer(NULL);
00753 
00754         return FALSE;
00755     }
00756 
00757     ERROR2( FALSE, "Escaped exception clause somehow" );
00758 }   

BOOL OutputPNG::OutputPNGHeader CCLexFile File,
INT32  TransColour,
BOOL  InterlaceState = 0
 

Writes out the file header for the cached bitmap within this class.

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
10/7/96
Parameters:
File - output file object [INPUTS] TransColour - the index of the transparent colour (-1 for no transparency)
- [OUTPUTS]
Returns:
TRUE if worked, FALSE if failed
See also:
OutputPNG::OutputPNGHeader

OutputGIF::OutputGifFileHeader (both ones)

Definition at line 418 of file outptpng.cpp.

00419 {
00420     return OutputPNGHeader(File, &(DestBitmapInfo->bmiHeader), InterlaceState, TransColour, OutputPalette);
00421 }

BOOL OutputPNG::ReStartFile LOGPALETTE pNewPal  )  [virtual]
 

Called to reset output before outputing another in a run of multiple images.

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
11/7/96
Parameters:
pNewPal - New (optimised) palette to use [INPUTS]
Returns:
TRUE if worked, FALSE if failed
See also:
OutputPNG::StartFile; OutputGIF::ReStartFile;

Definition at line 273 of file outptpng.cpp.

00274 {
00275     // Reset member variables
00276     IsFirstStrip = TRUE;
00277     HeightWritten = 0;
00278     pNextStrip = DestBitmapBytes;   
00279 
00280     if (pNewPal!=NULL)
00281     {
00282         ERROR2IF(OutputPalette==NULL, FALSE, "No output palette");
00283         ERROR3IF(pNewPal->palNumEntries != OutputPalette->palNumEntries, "Different sized palettes");
00284 
00285         const size_t PalSize = sizeof(PALETTEENTRY) * pNewPal->palNumEntries-1;
00286         memcpy( OutputPalette->palPalEntry, pNewPal->palPalEntry, PalSize );
00287     }
00288     
00289     return TRUE;
00290 }

BOOL OutputPNG::SetUpInfoHeader const LPBITMAPINFOHEADER  lpHeader,
const UINT32  OutputDepth,
const DWORD  CompressionType,
const UINT32  LineWidth,
const UINT32  FinalHeight,
INT32 *  pPalSize
[virtual]
 

Set up the information header for the DIB.

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/5/96
Parameters:
lpHeader contains width & DPI of source & dest. biHeight & depth ignored. [INPUTS] OutputDepth depth of bitmap required on disk CompressionType BI_RGB only supported (or CC_BMPTYPE for 32-bit with trans) LineWidth destination line width FinalHeight output of entire bitmap on disk
pPalSize pointer to an integer PalSize variable which is the palette size [OUTPUTS]
Returns:
TRUE if worked, FALSE if failed (error will be set accordingly but not reported)

Errors: Calls SetError on FALSE returns.

See also:
OutputPNG::StartFile; OutputPNG::WriteBlock; OutputPNG::TidyUp Scope: Public

Definition at line 316 of file outptpng.cpp.

00320 {
00321     ERROR2IF(pPalSize == NULL,FALSE,"OutputPNG::SetUpInfoHeader Null pPalSize");
00322 
00323     SourceBitmapDepth = lpHeader->biBitCount;
00324     BitmapInfo.biBitCount = OutputDepth;
00325 
00326     const WORD DestDepth = BitmapInfo.biBitCount;
00327 
00328     // source bitmap not necessarily same as required file depth
00329     // make sure we can handle conversion
00330     BOOL FormatOK = FALSE;
00331     *pPalSize = 0;
00332 
00333     switch (SourceBitmapDepth)
00334     {
00335         case 32:
00336             {
00337                 switch (DestDepth)
00338                 {
00339                     case 32:
00340                         {
00341                             // 32->32 might use our special type CC_BMPTYPE
00342                             FormatOK = TRUE;
00343                         }
00344                         break;
00345                     case 24:
00346                         {
00347                             // 32->24 bit is fine
00348                             FormatOK = TRUE;
00349                         }
00350                         break;
00351                     case 8:
00352                         {
00353                             // 32->8 is OK
00354                             FormatOK = TRUE;
00355                             *pPalSize = 256;
00356                         }
00357                         break;
00358                     case 4:
00359                         {
00360                             // 32->4 is OK
00361                             FormatOK = TRUE;
00362                             *pPalSize = 16;
00363                         }
00364                         break;
00365                     case 1:
00366                         {
00367                             // 32->1 is OK
00368                             FormatOK = TRUE;
00369                             *pPalSize = 2;
00370                         }
00371                         break;
00372                     default:
00373                         // other source formats here
00374                         break;
00375                 }
00376                 
00377             }
00378             break;
00379         case 8:
00380             if (DestDepth==8)
00381             {
00382                 // 8->8 is OK
00383                 FormatOK = TRUE;
00384                 *pPalSize = 256;
00385             }
00386             break;
00387         default:
00388             // other source formats here
00389             break;
00390     }
00391 
00392     if (!FormatOK)
00393     {
00394         Error::SetError( _R(IDE_FORMATNOTSUPPORTED) );
00395         return FALSE;
00396     }
00397 
00398     BitmapInfo.biSizeImage = LineWidth * FinalHeight;
00399 
00400     return TRUE;
00401 }

BOOL OutputPNG::StartFile LPBITMAPINFOHEADER  lpHeader,
LPLOGPALETTE  Palette,
UINT32  OutputDepth,
DWORD  CompressionType,
UINT32  FinalHeight,
INT32  ExportSize,
UINT32  DitherType
[virtual]
 

Get ready to write a PNG to disk, maybe in chunks. In the DIB case we go out to disk, in this case we store the bitmap for possible later use in applying a transparency mask to it.

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/5/96
Parameters:
lpHeader contains width & DPI of source & dest. biHeight & depth ignored. [INPUTS] Palette pointer to bmiColor struct, or NULL if not used (can be temporary) OutputDepth depth of bitmap required on disk CompressionType in this case is used to pass in the transparency and interlace information as PNGs are always compressed. Passed in as a number between 0 .. 3 which maps onto the TI_PNG filter types. FinalHeight output of entire bitmap on disk ExportSize The set progress bar size DitherType The type of dithering being used
Returns:
TRUE if worked, FALSE if failed (error will be set accordingly but not reported)

Errors: Calls SetError on FALSE returns.

See also:
OutputPNG::WriteBlock;OutputPNG::TidyUp Scope: Public

Reimplemented from OutputDIB.

Definition at line 176 of file outptpng.cpp.

00179 {
00180     TRACEUSER( "Jonathan", _T("PNG write: Start\n"));
00181     ERROR2IF( lpHeader==NULL , FALSE, "OutputPNG::StartFile NULL lpHeader");
00182 
00183     // Set up memory pointers to NULL
00184     if (DestBitmapInfo && DestBitmapBytes)
00185     {
00186         FreeDIB( DestBitmapInfo, DestBitmapBytes );
00187         DestBitmapInfo = NULL;
00188         DestBitmapBytes = NULL; 
00189     }
00190 //  DestBitmapInfo = NULL;
00191 //  DestBitmapBytes = NULL;
00192     if (OutputPalette)
00193     {
00194         CCFree(OutputPalette);
00195         OutputPalette = NULL;
00196     }
00197 //  OutputPalette = NULL;
00198     IsFirstStrip = TRUE;
00199     HeightWritten = 0;
00200 
00201     // remember input args
00202     BitmapInfo = *lpHeader;                             // take a copy of user's header
00203     CurrentExportSize = ExportSize;                     // size set up for the progress bar
00204     HeightWanted = FinalHeight;                         // the actual height of the export required
00205     Dither = DitherType;
00206 
00207     // We will need to have the entire image present before writing out so that we can
00208     // cope with interlacing and transparency, so create that DIB
00209     // Set up the information header for the dib which we hold during export
00210     UINT32 LineWidth = DIBUtil::ScanlineSize( BitmapInfo.biWidth, OutputDepth );
00211     INT32 PalSize = 0;          
00212     BOOL ok = SetUpInfoHeader(lpHeader, OutputDepth, CompressionType, LineWidth, FinalHeight, &PalSize);
00213 
00214     // Claim memory for the bitmap
00215     if (ok)
00216     {
00217         DestBitmapInfo = AllocDIB( BitmapInfo.biWidth, FinalHeight, OutputDepth, &DestBitmapBytes );
00218         ok = (DestBitmapInfo != NULL) && (DestBitmapBytes != NULL);
00219     }
00220 
00221     // Transfer across the required other bits of info
00222     if (ok)
00223     {
00224         DestBitmapInfo->bmiHeader.biXPelsPerMeter = BitmapInfo.biXPelsPerMeter;
00225         DestBitmapInfo->bmiHeader.biYPelsPerMeter = BitmapInfo.biYPelsPerMeter;
00226         DestBitmapInfo->bmiHeader.biClrUsed = PalSize;
00227     }
00228 
00229     // Point the place to put the next strip of data at the start ready for the first strip
00230     pNextStrip = DestBitmapBytes;   
00231     
00232     // Take a copy of the palette
00233     if (ok && PalSize && Palette)
00234     {
00235         const size_t TotalPal = sizeof(LOGPALETTE) + ( sizeof(PALETTEENTRY) * PalSize );
00236         OutputPalette = (LPLOGPALETTE)CCMalloc( TotalPal );
00237         if (OutputPalette != NULL)
00238             memcpy( OutputPalette, Palette, TotalPal );
00239         else
00240             ok = FALSE;
00241     }
00242 
00243     // Clean up if an error happened
00244     if (!ok)
00245     {
00246         // Free up the DIB that we have just created
00247         FreeDIB( DestBitmapInfo, DestBitmapBytes );
00248         DestBitmapInfo = NULL;
00249         DestBitmapBytes = NULL; 
00250         if (OutputPalette != NULL)
00251         {
00252             CCFree(OutputPalette);
00253             OutputPalette = NULL;
00254         }
00255     }
00256 
00257     return ok;
00258 }

BOOL OutputPNG::TidyUp  )  [virtual]
 

When everything has been done via WriteBlock, call this to update the header etc. The caller is responsible for closing the file. The class CANNOT be used for further output until StartFile is called again.

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/5/96
Returns:
TRUE if worked, FALSE if failed (error will be set accordingly but not reported)

Errors: Calls SetError on FALSE returns. Scope: Public

Reimplemented from OutputDIB.

Definition at line 1180 of file outptpng.cpp.

01181 {
01182     // Just in case we have any png related bits left around
01183     // Call up function to clean up the png structures
01184     CleanUpPngStructures();
01185 
01186     // Free up the DIB that we have just created
01187     if (DestBitmapInfo && DestBitmapBytes)
01188     {
01189         FreeDIB( DestBitmapInfo, DestBitmapBytes );
01190         DestBitmapInfo = NULL;
01191         DestBitmapBytes = NULL; 
01192     }
01193 
01194     // Call the baseclass version to do its stuff
01195     const BOOL ok = OutputDIB::TidyUp();
01196 
01197     return ok;
01198 }

BOOL OutputPNG::WriteBlock UINT32  YPos,
UINT32  Height,
LPBYTE  BlockStart,
UINT32  InputBPP = 32,
INT32  ProgressOffset = 0
[virtual]
 

Writes a chunk of bitmap data to the device. Assumes a progress hourglass is required and the caller has started an hourglass with a size of 100 and will end it. Notes: Originally this routine assumed that it was being given a 32bpp bmp, but using the InputBPP param it will now handle 8bpp bmps as well...

Author:
Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
Date:
14/5/96
Parameters:
YPos pixel co-ord of the chunk of DIB we are about to write out (0=bottom, [INPUTS] increasing as it goes up). Height height in pixels of this chunk BlockStart the start address of the bytes of this chunk (optional) InputBPP BPP of the input image (assumed 32 by default - 8 also works) ProgressOffset value to add to value passed to ContinueSlowJob (default 0).
Returns:
TRUE if worked, FALSE if failed (error will be set accordingly but not reported)

Errors: Calls SetError on FALSE returns. Scope: Public

Reimplemented from OutputDIB.

Definition at line 1013 of file outptpng.cpp.

01015 {
01016     ERROR2IF(DestBitmapInfo == NULL, FALSE,"OutputPNG::WriteBlock destination bitmap info null");
01017     ERROR2IF(DestBitmapBytes == NULL, FALSE,"OutputPNG::WriteBlock destination bitmap bits null");
01018     ERROR2IF(pNextStrip == NULL, FALSE,"OutputPNG::WriteBlock next strip pointer is null");
01019     
01020     FNPTR_SCANLINE ConvertFn = NULL;
01021     LPBYTE Buffer = NULL;
01022     size_t BufSize = 0L;
01023     size_t ChunkHeight = 1;
01024     DIBConvert *DoConvert = NULL;
01025 
01026     // Set up the size and other information for the dib block that we require. This is
01027     // dependent on the export depth or bpp required.
01028     if ( !SetUpBlock( &BufSize, &ChunkHeight, &DoConvert, &ConvertFn ) )
01029         return FALSE;           // Error details already set up
01030 
01031     if (BufSize)
01032     {
01033         Buffer = (LPBYTE)CCMalloc( BufSize );
01034         if (Buffer==NULL)
01035             return FALSE;
01036     }
01037 
01038     if ( DoConvert )
01039     {
01040         // use new classes to do it
01041         // 8bpp, 4bpp and 1bpp conversion
01042         INT32 h = Height;
01043         INT32 count = 0;
01044         LPBYTE Data = BlockStart;
01045         const size_t SourceWidth = DIBUtil::ScanlineSize( BitmapInfo.biWidth, InputBPP ) * ChunkHeight;
01046         const size_t DestWidth   = DIBUtil::ScanlineSize( BitmapInfo.biWidth, BitmapInfo.biBitCount );
01047 
01048         while (h)
01049         {
01050             ENSURE(h >= 0, "bad looping");
01051 
01052             const size_t ThisBit = min( h, (INT32)ChunkHeight );
01053             if (!DoConvert->Convert( Data, Buffer, ThisBit, IsFirstStrip ))
01054                 break;                              // stop if conversion failed
01055 
01056             IsFirstStrip = FALSE;
01057 
01058             // Copy this block to our destination bitmap
01059             // pNextStrip should be pointing at the next place to copy the data to
01060             memcpy(pNextStrip, Buffer, ThisBit * DestWidth);
01061 
01062             Data += SourceWidth;
01063             h -= ThisBit;
01064             pNextStrip += ThisBit * DestWidth;
01065             
01066             // now update the progress display, started with CurrentExportSize
01067             // CurrentExport size is now the point to go from in the export
01068             count++;
01069             ContinueSlowJob( (INT32)(ProgressOffset + count) );
01070             //ContinueSlowJob( (INT32)(100*count/(Height)) );
01071         }
01072     }
01073     else if ( ConvertFn && Buffer )
01074     {
01075         // Write via conversion function
01076         // 24 bpp convert
01077         UINT32 h = Height;
01078         INT32 count = 0;
01079         LPBYTE Data = BlockStart;
01080         const size_t SourceWidth = DIBUtil::ScanlineSize( BitmapInfo.biWidth, InputBPP );
01081 
01082         while (h)
01083         {
01084             ConvertFn( BitmapInfo.biWidth, Data, Buffer );
01085             
01086             // Copy this block to our destination bitmap
01087             // pNextStrip should be pointing at the next place to copy the data to
01088             memcpy(pNextStrip, Buffer, BufSize);
01089 
01090             Data += SourceWidth;
01091             h -= ChunkHeight;
01092             pNextStrip += BufSize;
01093 
01094             // now update the progress display, started with CurrentExportSize
01095             // ProgressOffset size is now the point to go from in the export
01096             count++;
01097             ContinueSlowJob( (INT32)( ProgressOffset + count ));
01098             //ContinueSlowJob( (INT32)((CurrentExportSize * count)/Height) );
01099         }
01100     }
01101     else
01102     {
01103         // Write the actual bytes out to file. Used to do it in one go but we really
01104         // require some progress bar indication so we will do it in chunks.
01105         DWORD BitsSize = BitmapInfo.biSizeImage; 
01106         if (BitsSize > 0)
01107         {
01108             if (BitsSize < 1024)
01109             {
01110                 // File very small or no progress bar required, so load in one go
01111                 // Copy this block to our destination bitmap
01112                 // pNextStrip should be pointing at the next place to copy the data to
01113                 memcpy(pNextStrip, BlockStart, BitsSize);
01114                 pNextStrip += BitsSize;
01115             }
01116             else
01117             {
01118                 // Load in chunks, for present split into 100 chunks
01119                 DWORD ChunkSize = BitsSize/100;
01120                 DWORD Position = 0;
01121                 LPBYTE pBitInfo = BlockStart;
01122                 
01123                 while (Position < BitsSize)
01124                 {
01125                     if ( (BitsSize - Position) > ChunkSize)
01126                     {
01127                         // Copy this block to our destination bitmap
01128                         // pNextStrip should be pointing at the next place to copy the data to
01129                         memcpy(pNextStrip, pBitInfo, ChunkSize);
01130                     }
01131                     else
01132                     {
01133                         ChunkSize = BitsSize - Position;
01134                         // Copy this block to our destination bitmap
01135                         // pNextStrip should be pointing at the next place to copy the data to
01136                         memcpy(pNextStrip, pBitInfo, ChunkSize);
01137                     }
01138                             
01139                     // Increment our counters/pointers
01140                     Position+=ChunkSize;
01141                     pBitInfo+=ChunkSize;
01142                     pNextStrip += ChunkSize;
01143                     // Progress bar started with height of bitmap
01144                     ContinueSlowJob( (INT32)(ProgressOffset + (Height * Position)/BitsSize) );
01145                     //ContinueSlowJob( (INT32)((CurrentExportSize * Position)/BitsSize) );
01146                 }
01147             }
01148         }
01149     }
01150 
01151     // If present, get rid of our export function
01152     if (DoConvert)
01153     {
01154         delete DoConvert;
01155         DoConvert = NULL;
01156     }
01157 
01158     CCFree( Buffer );
01159 
01160     HeightWritten += Height;                        // remember we wrote this lot
01161 
01162     return TRUE;
01163 }


Member Data Documentation

INT32 OutputPNG::BitsPerPixel [private]
 

Definition at line 178 of file outptpng.h.

LPBYTE OutputPNG::DataBuffer [private]
 

Definition at line 181 of file outptpng.h.

LPBYTE OutputPNG::DestBitmapBytes [private]
 

Definition at line 162 of file outptpng.h.

LPBITMAPINFO OutputPNG::DestBitmapInfo [private]
 

Definition at line 161 of file outptpng.h.

INT32 OutputPNG::Height [private]
 

Definition at line 173 of file outptpng.h.

png_infop OutputPNG::info_ptr [private]
 

Definition at line 167 of file outptpng.h.

INT32 OutputPNG::InitCodeSize [private]
 

Definition at line 179 of file outptpng.h.

BOOL OutputPNG::Interlace [private]
 

Definition at line 175 of file outptpng.h.

LPBYTE OutputPNG::pNextStrip [private]
 

Definition at line 163 of file outptpng.h.

png_structp OutputPNG::png_ptr [private]
 

Definition at line 166 of file outptpng.h.

BOOL OutputPNG::Transparent [private]
 

Definition at line 176 of file outptpng.h.

INT32 OutputPNG::Width [private]
 

Definition at line 172 of file outptpng.h.

UINT32 OutputPNG::WidthOfLine [private]
 

Definition at line 183 of file outptpng.h.


The documentation for this class was generated from the following files:
Generated on Sat Nov 10 03:59:20 2007 for Camelot by  doxygen 1.4.4