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