outptpng.cpp

Go to the documentation of this file.
00001 // $Id: outptpng.cpp 1372 2006-06-27 11:23:21Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 #include "camtypes.h"
00100 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00101 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00102 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00103 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00104 //#include "andy.h"
00105 //#include "dibconv.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 #include "progress.h"       // For hourglass stuff
00107 
00108 //#include "resource.h"     // _R(IDS_OUT_OF_MEMORY)
00109 //#include "filtrres.h"     // _R(IDS_UNKNOWN_PNG_ERROR)
00110 //#include "nev.h"          // _R(IDW_CANCELEXPORT)
00111 
00112 #include "outptpng.h"
00113 #include "pngutil.h"
00114 #include "png.h"
00115 
00116 // Replacements for some libpng functions
00117 #include "pngfuncs.h"
00118 
00119 //#include "camfiltr.h" // BaseCamelotFilter - in camtypes.h [AUTOMATICALLY REMOVED]
00120 
00121 #define new CAM_DEBUG_NEW
00122 
00123 /********************************************************************************************
00124 
00125 >   OutputPNG::OutputPNG()
00126 
00127     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00128     Created:    14/5/96
00129     Purpose:    Default constructor for the class. Just sets up the pointers to our buffers
00130                 that may be used to be null so that the TidyUp function can do its job.
00131     SeeAlso:    OutputPNG::TidyUp
00132     SeeAlso:    OutputDIB;
00133 
00134 ********************************************************************************************/
00135 
00136 OutputPNG::OutputPNG()
00137 {
00138     OutputFile = NULL;
00139     lpBitmap = NULL;
00140     ExportBuffer = NULL;
00141     DoExportConvert = NULL;
00142     OutputForward = FALSE;
00143 
00144     DestBitmapInfo = NULL;
00145     DestBitmapBytes = NULL;
00146 }
00147 
00148 
00149 /********************************************************************************************
00150 
00151 >   BOOL OutputPNG::StartFile( CCLexFile *File, LPBITMAPINFOHEADER lpHeader, LPRGBQUAD Palette,
00152                                UINT32 OutputDepth, DWORD CompressionType, UINT32 FinalHeight,
00153                                UINT32 FinalHeight, INT32 ExportSize, UINT32 DitherType )
00154 
00155     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00156     Created:    14/5/96
00157     Inputs:     lpHeader    contains width & DPI of source & dest. biHeight & depth ignored.
00158                 Palette     pointer to bmiColor struct, or NULL if not used (can be temporary)
00159                 OutputDepth depth of bitmap required on disk
00160                 CompressionType in this case is used to pass in the transparency and interlace
00161                             information as PNGs are always compressed. Passed in as a number between
00162                             0 .. 3 which maps onto the TI_PNG filter types.
00163                 FinalHeight output of entire bitmap on disk
00164                 ExportSize      The set progress bar size 
00165                 DitherType      The type of dithering being used
00166     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
00167     Purpose:    Get ready to write a PNG to disk, maybe in chunks. In the DIB case we go out
00168                 to disk, in this case we store the bitmap for possible later use in applying a
00169                 transparency mask to it.
00170     Errors:     Calls SetError on FALSE returns.
00171     SeeAlso:    OutputPNG::WriteBlock;OutputPNG::TidyUp
00172     Scope:      Public
00173 
00174 ********************************************************************************************/
00175 
00176 BOOL OutputPNG::StartFile( LPBITMAPINFOHEADER lpHeader, LPLOGPALETTE Palette,
00177                            UINT32 OutputDepth, DWORD CompressionType,
00178                            UINT32 FinalHeight, INT32 ExportSize, UINT32 DitherType )
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 }
00259 
00260 /********************************************************************************************
00261 
00262 >   BOOL OutputPNG::ReStartFile(LOGPALETTE* pNewPal)
00263 
00264     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00265     Created:    11/7/96
00266     Inputs:     pNewPal - New (optimised) palette to use
00267     Returns:    TRUE if worked, FALSE if failed
00268     Purpose:    Called to reset output before outputing another in a run of multiple images
00269     SeeAlso:    OutputPNG::StartFile; OutputGIF::ReStartFile;
00270 
00271 ********************************************************************************************/
00272 
00273 BOOL OutputPNG::ReStartFile(LOGPALETTE* pNewPal)
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 }
00291 
00292 
00293 /********************************************************************************************
00294 
00295 >   BOOL OutputPNG::SetUpInfoHeader(const LPBITMAPINFOHEADER lpHeader, const UINT32 OutputDepth,
00296                                     const DWORD CompressionType,
00297                                     const UINT32 LineWidth, const UINT32 FinalHeight,
00298                                     INT32 * pPalSize)
00299 
00300     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00301     Created:    14/5/96
00302     Inputs:     lpHeader    contains width & DPI of source & dest. biHeight & depth ignored.
00303                 OutputDepth depth of bitmap required on disk
00304                 CompressionType BI_RGB only supported (or CC_BMPTYPE for 32-bit with trans)
00305                 LineWidth   destination line width
00306                 FinalHeight output of entire bitmap on disk
00307     Outputs:    pPalSize    pointer to an integer PalSize variable which is the palette size
00308     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
00309     Purpose:    Set up the information header for the DIB.
00310     Errors:     Calls SetError on FALSE returns.
00311     SeeAlso:    OutputPNG::StartFile; OutputPNG::WriteBlock; OutputPNG::TidyUp
00312     Scope:      Public
00313 
00314 ********************************************************************************************/
00315 
00316 BOOL OutputPNG::SetUpInfoHeader(const LPBITMAPINFOHEADER lpHeader, const UINT32 OutputDepth,
00317                                 const DWORD CompressionType,
00318                                 const UINT32 LineWidth, const UINT32 FinalHeight,
00319                                 INT32 * pPalSize)
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 }
00402 
00403 /********************************************************************************************
00404 
00405 
00406     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00407     Created:    10/7/96
00408     Inputs:     File - output file object
00409                 TransColour - the index of the transparent colour (-1 for no transparency)
00410     Outputs:    -
00411     Returns:    TRUE if worked, FALSE if failed
00412     Purpose:    Writes out the file header for the cached bitmap within this class
00413     SeeAlso:    OutputPNG::OutputPNGHeader 
00414     SeeAlso:    OutputGIF::OutputGifFileHeader (both ones)
00415 
00416 ********************************************************************************************/
00417 
00418 BOOL OutputPNG::OutputPNGHeader(CCLexFile *File, INT32 TransColour, BOOL InterlaceState)
00419 {
00420     return OutputPNGHeader(File, &(DestBitmapInfo->bmiHeader), InterlaceState, TransColour, OutputPalette);
00421 }
00422 
00423 /********************************************************************************************
00424 
00425 >   BOOL OutputPNG::OutputPNGHeader(CCLexFile *, LPBITMAPINFOHEADER,
00426                                     BOOL Interlace, INT32 Transparent,
00427                                     LPLOGPALETTE = NULL, LPRGBQUAD pQuadPalette = NULL)
00428 
00429     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00430     Created:    14/5/96
00431     Inputs:     File            file to output to
00432                 pInfo           pointer to the bitmap info header
00433                 InterlaceState  True if want interlacing, False otherwise
00434                 TransparentColour   The transparent colour required
00435                 pPalette        pointer to a palette in LOGPALETTE form (defaults to NULL)
00436                 OR
00437                 pQuadPalette    pointer to a palette in RGBQUAD form (defaults to NULL) 
00438     Outputs:    -
00439     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
00440     Purpose:    Output a PNG header for the specified bitmap to the file.
00441                 If neither palette is specifed then none will be output.
00442     Errors:     Calls SetError on FALSE returns.
00443     SeeAlso:    OutputPNG::StartFile; OutputPNG::WriteBlock; OutputPNG::TidyUp
00444     Scope:      static
00445 
00446 ********************************************************************************************/
00447 
00448 BOOL OutputPNG::OutputPNGHeader(CCLexFile *File, LPBITMAPINFOHEADER pInfo,
00449                                 BOOL InterlaceState, INT32 TransparentColour,
00450                                 LPLOGPALETTE pPalette, LPRGBQUAD pQuadPalette)
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 }   
00759 
00760 /********************************************************************************************
00761 
00762 >   BOOL OutputPNG::CleanUpPngStructures()
00763 
00764     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00765     Created:    12/7/96
00766     Inputs:     -
00767     Outputs:    -
00768     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
00769     Purpose:    Clean up those bits that may have been claimed by the PNG bits.
00770 
00771 ********************************************************************************************/
00772 
00773 BOOL OutputPNG::CleanUpPngStructures()
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 }
00800 
00801 /********************************************************************************************
00802 
00803 >   BOOL OutputPNG::OutputPNGBits(CCLexFile *File, LPBYTE pBlockStart, BOOL OneBlock = TRUE,
00804                                   BaseCamelotFilter *pFilter = NULL)
00805 
00806     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00807     Created:    14/5/96
00808     Inputs:     File        pointer to file to output to
00809                 pBlockStart actual bitmap data to write out
00810                 OneBlock    if TRUE then have all the data so write it out in one go
00811                             if FALSE then need to compress in strips
00812                 pFilter     is an alternative way of handling the progress bar, assume the
00813                             progress bar has been start and just call the IncProgressBarCount in BaseCamelotFilter
00814                             to do the progress bar update. Defaults to NULL i.e. no progress bar.
00815     Outputs:    -
00816     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
00817     Purpose:    Output the actual bits of a bitmap as compressed PNG data. Assumes that a
00818                 header has already been output, possibly using OutputPNGHeader. Assumes that
00819                 all the data is present.
00820     Errors:     Calls SetError on FALSE returns.
00821     SeeAlso:    OutputPNG::OutputPNGHeader; 
00822     SeeAlo:     OutputPNG::StartFile; OutputPNG::WriteBlock; OutputPNG::TidyUp
00823     Scope:      static
00824 
00825 ********************************************************************************************/
00826 
00827 BOOL OutputPNG::OutputPNGBits(CCLexFile *File, LPBYTE pBlockStart, BOOL OneBlock,
00828                               BaseCamelotFilter *pFilter)
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 }   
00954 
00955 /******************************************************************************************
00956 
00957 >   LPBITMAPINFO OutputPNG::GetDestBitmapInfo ( void )
00958 
00959     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00960     Created:    29/6/00
00961     Inputs:     pPalette - Palette information that we want to copy from
00962     Returns:    A pointer to the bitmap information structure.
00963     Purpose:    Access function to DestBitmapInfo.
00964 
00965 ******************************************************************************************/
00966 
00967 LPBITMAPINFO OutputPNG::GetDestBitmapInfo ( void )
00968 {
00969     return DestBitmapInfo;
00970 }
00971 
00972 /******************************************************************************************
00973 
00974 >   LPBYTE OutputPNG::GetDestBitmapBits ( void )
00975 
00976     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00977     Created:    29/6/00
00978     Inputs:     pPalette - Palette information that we want to copy from
00979     Returns:    A pointer to the bitmap itself.
00980     Purpose:    Access function to DestBitmapBytes.
00981 
00982 ******************************************************************************************/
00983 
00984 LPBYTE OutputPNG::GetDestBitmapBits ( void )
00985 {
00986     return DestBitmapBytes;
00987 }
00988 
00989 /********************************************************************************************
00990 
00991 >   BOOL OutputPNG::WriteBlock( UINT32 YPos, UINT32 Height, LPBYTE BlockStart, UINT32 InputBPP = 32,
00992                                 INT32 ProgressOffset = 0)
00993 
00994     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00995     Created:    14/5/96
00996     Inputs:     YPos        pixel co-ord of the chunk of DIB we are about to write out (0=bottom,
00997                             increasing as it goes up).
00998                 Height      height in pixels of this chunk
00999                 BlockStart  the start address of the bytes of this chunk
01000     (optional)  InputBPP    BPP of the input image (assumed 32 by default - 8 also works)
01001                 ProgressOffset  value to add to value passed to ContinueSlowJob (default 0).
01002     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
01003     Purpose:    Writes a chunk of bitmap data to the device.
01004                 Assumes a progress hourglass is required and the caller has started an hourglass
01005                 with a size of 100 and will end it.
01006     Notes:      Originally this routine assumed that it was being given a 32bpp bmp, but using
01007                 the InputBPP param it will now handle 8bpp bmps as well...
01008     Errors:     Calls SetError on FALSE returns.
01009     Scope:      Public
01010 
01011 ********************************************************************************************/
01012 
01013 BOOL OutputPNG::WriteBlock( UINT32 YPos, UINT32 Height, LPBYTE BlockStart, UINT32 InputBPP,
01014                             INT32 ProgressOffset)
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 }
01164 
01165 /********************************************************************************************
01166 
01167 >   BOOL OutputDIB::TidyUp()
01168 
01169     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01170     Created:    14/5/96
01171     Returns:    TRUE if worked, FALSE if failed (error will be set accordingly but not reported)
01172     Purpose:    When everything has been done via WriteBlock, call this to update the header
01173                 etc. The caller is responsible for closing the file. The class CANNOT be used
01174                 for further output until StartFile is called again.
01175     Errors:     Calls SetError on FALSE returns.
01176     Scope:      Public
01177 
01178 ********************************************************************************************/
01179 
01180 BOOL OutputPNG::TidyUp()
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 }
01199 
01200 

Generated on Sat Nov 10 03:48:46 2007 for Camelot by  doxygen 1.4.4