00001 // $Id: ppmfiltr.cpp 1460 2006-07-17 19:00:12Z 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 // A PPM import/export filter 00100 00101 #include "camtypes.h" 00102 #include "ppmfiltr.h" 00103 //#include "andy.h" 00104 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00105 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00106 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00107 #include "grndbmp.h" 00108 #include "nodebmp.h" 00109 //#include "bmpfiltr.h" 00110 #include "progress.h" 00111 #include "oilbitmap.h" // Windows specific bitmap information 00112 //#include "docview.h" // DocView - in camtypes.h [AUTOMATICALLY REMOVED] 00113 //#include "bitmap.h" // kernel bitmap 00114 //#include "bmpres.h" // general bitmap filter based resources 00115 //#include "resource.h" // _R(IDS_OUTOFMEMORY) 00116 //#include "resource.h" // Inform Warning _R(IDS_OK) 00117 00118 CC_IMPLEMENT_DYNAMIC(BasePMFilter, BaseBitmapFilter) 00119 CC_IMPLEMENT_DYNAMIC(PPMFilter, BasePMFilter) 00120 CC_IMPLEMENT_DYNAMIC(PGMFilter, BasePMFilter) 00121 CC_IMPLEMENT_DYNAMIC(PBMFilter, BasePMFilter) 00122 00123 #define new CAM_DEBUG_NEW 00124 00125 // General statics which we use 00126 //OutputPPM PPMFilter::DestPPM; 00127 00128 enum PpmTokenIndex 00129 { 00130 PpmTOKEN_NONE = -1, 00131 TOKEN_PPM_ASCII, 00132 TOKEN_PPM_BINARY, 00133 TOKEN_PGM_ASCII, 00134 TOKEN_PGM_BINARY, 00135 TOKEN_PBM_ASCII, 00136 TOKEN_PBM_BINARY, 00137 // Add new token indexs BEFORE NUM_TOKENS 00138 PpmNUM_TOKENS 00139 }; 00140 00141 static struct 00142 { 00143 TCHAR* Token; 00144 } TokenTable[] = 00145 { 00146 {_T("P3")}, 00147 {_T("P6")}, 00148 {_T("P2")}, 00149 {_T("P5")}, 00150 {_T("P1")}, 00151 {_T("P4")}, 00152 }; 00153 00154 static PpmTokenIndex FindToken(const TCHAR* Token) 00155 { 00156 for (INT32 i = 0; i < PpmNUM_TOKENS; i++) 00157 if (camStrcmp(TokenTable[i].Token,Token) == 0) return (PpmTokenIndex) i; 00158 00159 return PpmTOKEN_NONE; 00160 } 00161 00162 /******************************************************************************************** 00163 ***** PPMFilter ***** 00164 ********************************************************************************************/ 00165 00166 00167 /******************************************************************************************** 00168 00169 > PPMOILFilter::PPMOILFilter() 00170 00171 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00172 Created: 28/11/95 00173 Purpose: Sets up the list of filename extensions that this filter understands. 00174 00175 ********************************************************************************************/ 00176 00177 PPMOILFilter::PPMOILFilter(Filter *pFilter) : OILFilter(pFilter) 00178 { 00179 FilterName.Load(_R(IDN_FILTERNAME_PPM)); 00180 FilterExt.Load(_R(IDN_FILTEREXT_PPM)); 00181 } 00182 00183 /******************************************************************************************** 00184 00185 > PPMFilter::PPMFilter() 00186 00187 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00188 Created: 30/11/95 00189 Purpose: Constructor for an PPMFilter object. The object should be initialised 00190 before use. 00191 SeeAlso: PPMFilter::Init 00192 00193 ********************************************************************************************/ 00194 00195 PPMFilter::PPMFilter() : BasePMFilter() 00196 { 00197 ImportMsgID = _R(IDN_IMPORTMSG_PPM); 00198 Flags.CanImport = TRUE; 00199 Flags.CanExport = FALSE; 00200 FilterID = FILTERID_PPM; 00201 00202 ExportRegion = NULL; 00203 ExportMsgID = _R(IDN_EXPORTMSG_PPM); // "Preparing PPM file..." 00204 00205 ExportingMsgID = _R(IDN_EXPORTINGMSG_PPM); // "Exporting PPM file..." 00206 00207 // CurrentSelection = DRAWING; 00208 } 00209 00210 /******************************************************************************************** 00211 00212 > BOOL PPMFilter::Init() 00213 00214 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00215 Created: 30/11/95 00216 Returns: TRUE if the filter was initialised ok, FALSE otherwise. 00217 Purpose: Initialise an PPMFilter object. 00218 Errors: Will fail if not enough memory to initialise. 00219 SeeAlso: EPSStack 00220 00221 ********************************************************************************************/ 00222 00223 BOOL PPMFilter::Init() 00224 { 00225 // Get the OILFilter object 00226 pOILFilter = new PPMOILFilter(this); 00227 if (pOILFilter==NULL) 00228 return FALSE; 00229 00230 // Load the description strings 00231 FilterName.Load(_R(IDN_PPM_FILTERNAME)); 00232 FilterInfo.Load(_R(IDN_PPM_FILTERINFO)); 00233 00234 // All ok 00235 return TRUE; 00236 } 00237 00238 /******************************************************************************************** 00239 00240 > BOOL PPMFilter::CheckString(TCHAR * pHeader) 00241 00242 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00243 Created: 30/11/95 00244 Returns: TRUE if the filter reckonises the string, FALSE otherwise. 00245 Purpose: To see if the header of a PPM file is correct or not. 00246 SeeAlso: BasePMFilter::HowCompatible; 00247 00248 ********************************************************************************************/ 00249 00250 BOOL PPMFilter::CheckString(TCHAR * pHeader) 00251 { 00252 if ( 00253 (camStrncmp(pHeader, _T("P3"), 2) == 0) || // ASCII PPM 00254 (camStrncmp(pHeader, _T("P6"), 2) == 0) // BINARY PPM 00255 ) 00256 { 00257 // finding PBM should be good enough to determine that there is 00258 // a high chance that this is the right file. 00259 00260 return TRUE; 00261 } 00262 00263 return FALSE; 00264 } 00265 00266 00267 /******************************************************************************************** 00268 ***** PGMFilter ***** 00269 ********************************************************************************************/ 00270 00271 00272 00273 /******************************************************************************************** 00274 00275 > PGMOILFilter::PGMOILFilter() 00276 00277 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00278 Created: 28/11/95 00279 Purpose: Sets up the list of filename extensions that this filter understands. 00280 00281 ********************************************************************************************/ 00282 00283 PGMOILFilter::PGMOILFilter(Filter *pFilter) : OILFilter(pFilter) 00284 { 00285 FilterName.Load(_R(IDN_FILTERNAME_PGM)); 00286 FilterExt.Load(_R(IDN_FILTEREXT_PGM)); 00287 } 00288 00289 /******************************************************************************************** 00290 00291 > PGMFilter::PGMFilter() 00292 00293 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00294 Created: 30/11/95 00295 Purpose: Constructor for an PGMFilter object. The object should be initialised 00296 before use. 00297 SeeAlso: PGMFilter::Init 00298 00299 ********************************************************************************************/ 00300 00301 PGMFilter::PGMFilter() : BasePMFilter() 00302 { 00303 ImportMsgID = _R(IDN_IMPORTMSG_PGM); 00304 Flags.CanImport = TRUE; 00305 Flags.CanExport = FALSE; 00306 FilterID = FILTERID_PGM; 00307 00308 ExportRegion = NULL; 00309 ExportMsgID = _R(IDN_EXPORTMSG_PGM); // "Preparing PGM file..." 00310 00311 ExportingMsgID = _R(IDN_EXPORTINGMSG_PGM); // "Exporting PGM file..." 00312 00313 // CurrentSelection = DRAWING; 00314 } 00315 00316 /******************************************************************************************** 00317 00318 > BOOL PGMFilter::Init() 00319 00320 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00321 Created: 30/11/95 00322 Returns: TRUE if the filter was initialised ok, FALSE otherwise. 00323 Purpose: Initialise an PPMFilter object. 00324 Errors: Will fail if not enough memory to initialise. 00325 SeeAlso: EPSStack 00326 00327 ********************************************************************************************/ 00328 00329 BOOL PGMFilter::Init() 00330 { 00331 // Get the OILFilter object 00332 pOILFilter = new PGMOILFilter(this); 00333 if (pOILFilter==NULL) 00334 return FALSE; 00335 00336 // Load the description strings 00337 FilterName.Load(_R(IDN_PGM_FILTERNAME)); 00338 FilterInfo.Load(_R(IDN_PGM_FILTERINFO)); 00339 00340 // All ok 00341 return TRUE; 00342 } 00343 00344 /******************************************************************************************** 00345 00346 > BOOL PGMFilter::CheckString(TCHAR * pHeader) 00347 00348 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00349 Created: 30/11/95 00350 Returns: TRUE if the filter reckonises the string, FALSE otherwise. 00351 Purpose: To see if the header of a PBM file is correct or not. 00352 SeeAlso: BasePMFilter::HowCompatible; 00353 00354 ********************************************************************************************/ 00355 00356 BOOL PGMFilter::CheckString(TCHAR * pHeader) 00357 { 00358 if ( 00359 (camStrncmp(pHeader, _T("P2"), 2) == 0) || // ASCII PGM 00360 (camStrncmp(pHeader, _T("P5"), 2) == 0) // BINARY PGM 00361 ) 00362 { 00363 // finding PBM should be good enough to determine that there is 00364 // a high chance that this is the right file. 00365 00366 return TRUE; 00367 } 00368 00369 return FALSE; 00370 } 00371 00372 00373 00374 /******************************************************************************************** 00375 ***** PBMFilter ***** 00376 ********************************************************************************************/ 00377 00378 00379 00380 /******************************************************************************************** 00381 00382 > PBMOILFilter::PBMOILFilter() 00383 00384 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00385 Created: 28/11/95 00386 Purpose: Sets up the list of filename extensions that this filter understands. 00387 00388 ********************************************************************************************/ 00389 00390 PBMOILFilter::PBMOILFilter(Filter *pFilter) : OILFilter(pFilter) 00391 { 00392 FilterName.Load(_R(IDN_FILTERNAME_PBM)); 00393 FilterExt.Load(_R(IDN_FILTEREXT_PBM)); 00394 } 00395 00396 /******************************************************************************************** 00397 00398 > PBMFilter::PBMFilter() 00399 00400 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00401 Created: 30/11/95 00402 Purpose: Constructor for an PBMFilter object. The object should be initialised 00403 before use. 00404 SeeAlso: PBMFilter::Init 00405 00406 ********************************************************************************************/ 00407 00408 PBMFilter::PBMFilter() : BasePMFilter() 00409 { 00410 ImportMsgID = _R(IDN_IMPORTMSG_PBM); 00411 Flags.CanImport = TRUE; 00412 Flags.CanExport = FALSE; 00413 FilterID = FILTERID_PBM; 00414 00415 ExportRegion = NULL; 00416 ExportMsgID = _R(IDN_EXPORTMSG_PBM); // "Preparing PBM file..." 00417 00418 ExportingMsgID = _R(IDN_EXPORTINGMSG_PBM); // "Exporting PBM file..." 00419 00420 // CurrentSelection = DRAWING; 00421 } 00422 00423 /******************************************************************************************** 00424 00425 > BOOL PBMFilter::Init() 00426 00427 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00428 Created: 30/11/95 00429 Returns: TRUE if the filter was initialised ok, FALSE otherwise. 00430 Purpose: Initialise an PBMFilter object. 00431 Errors: Will fail if not enough memory to initialise. 00432 SeeAlso: EPSStack 00433 00434 ********************************************************************************************/ 00435 00436 BOOL PBMFilter::Init() 00437 { 00438 // Get the OILFilter object 00439 pOILFilter = new PBMOILFilter(this); 00440 if (pOILFilter==NULL) 00441 return FALSE; 00442 00443 // Load the description strings 00444 FilterName.Load(_R(IDN_PBM_FILTERNAME)); 00445 FilterInfo.Load(_R(IDN_PBM_FILTERINFO)); 00446 00447 // All ok 00448 return TRUE; 00449 } 00450 00451 00452 /******************************************************************************************** 00453 00454 > BOOL PBMFilter::CheckString(TCHAR * pHeader) 00455 00456 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00457 Created: 30/11/95 00458 Returns: TRUE if the filter reckonises the string, FALSE otherwise. 00459 Purpose: To see if the header of a PBM file is correct or not. 00460 SeeAlso: BasePMFilter::HowCompatible; 00461 00462 ********************************************************************************************/ 00463 00464 BOOL PBMFilter::CheckString(TCHAR * pHeader) 00465 { 00466 if ( 00467 (camStrncmp(pHeader, _T("P1"), 2) == 0) || // ASCII PBM 00468 (camStrncmp(pHeader, _T("P4"), 2) == 0) // BINARY PBM 00469 ) 00470 { 00471 // finding PBM should be good enough to determine that there is 00472 // a high chance that this is the right file. 00473 00474 return TRUE; 00475 } 00476 00477 return FALSE; 00478 } 00479 00480 00481 /******************************************************************************************** 00482 ***** BasePMFilter ***** 00483 ********************************************************************************************/ 00484 00485 /******************************************************************************************** 00486 00487 > BasePMFilter::BasePMFilter() 00488 00489 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00490 Created: 30/11/95 00491 Purpose: Constructor for an BasePMFilter object. The object should be initialised 00492 before use. 00493 SeeAlso: BasePMFilter::Init 00494 00495 ********************************************************************************************/ 00496 00497 BasePMFilter::BasePMFilter() : BaseBitmapFilter() 00498 { 00499 // Make ourselves look like a PPM filter, even though we shouldn't be seen 00500 ImportMsgID = _R(IDN_IMPORTMSG_PPM); 00501 Flags.CanImport = FALSE; 00502 Flags.CanExport = FALSE; 00503 FilterID = FILTERID_PPM; 00504 00505 ExportRegion = NULL; 00506 ExportMsgID = _R(IDN_EXPORTMSG_PPM); // "Preparing PPM file..." 00507 00508 ExportingMsgID = _R(IDN_EXPORTINGMSG_PPM); // "Exporting PPM file..." 00509 00510 // CurrentSelection = DRAWING; 00511 } 00512 00513 /******************************************************************************************** 00514 00515 > BOOL BasePMFilter::Init() 00516 00517 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00518 Created: 30/11/95 00519 Returns: TRUE if the filter was initialised ok, FALSE otherwise. 00520 Purpose: Initialise an BasePMFilter object. 00521 Errors: Will fail if not enough memory to initialise. 00522 SeeAlso: EPSStack 00523 00524 ********************************************************************************************/ 00525 00526 BOOL BasePMFilter::Init() 00527 { 00528 // Make ourselves look like a PPM filter, even though we shouldn't be seen 00529 00530 // Get the OILFilter object 00531 pOILFilter = new PPMOILFilter(this); 00532 if (pOILFilter==NULL) 00533 return FALSE; 00534 00535 // Load the description strings 00536 FilterName.Load(_R(IDN_PPM_FILTERNAME)); 00537 FilterInfo.Load(_R(IDN_PPM_FILTERINFO)); 00538 00539 // All ok 00540 return TRUE; 00541 } 00542 00543 /******************************************************************************************** 00544 00545 > BOOL BasePMFilter::CheckString(TCHAR * pHeader) 00546 00547 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00548 Created: 30/11/95 00549 Returns: TRUE if the filter reckonises the string, FALSE otherwise. 00550 Purpose: To see if the header of a PBM file is correct or not. 00551 Baseclass version so should not be used. 00552 SeeAlso: BasePMFilter::HowCompatible; 00553 00554 ********************************************************************************************/ 00555 00556 BOOL BasePMFilter::CheckString(TCHAR * pHeader) 00557 { 00558 ERROR2(FALSE,"BasePMFilter::ReadDataIntoBitmap calling baseclass version!"); 00559 return FALSE; 00560 } 00561 00562 /******************************************************************************************** 00563 00564 > INT32 BasePMFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, UINT32 HeaderSize, 00565 UINT32 FileSize) 00566 00567 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00568 Created: 30/11/95 00569 Inputs: Filename - name of the file. 00570 HeaderStart - Address of the first few bytes of the file. 00571 HeaderSize - the number of bytes in the header pointed to by FileStart. 00572 FileSize - the size of the whole file, in bytes. 00573 Returns: 0 => Not a PPM file. 00574 10 => It is a PPM file. 00575 Purpose: Determine if this filter can load the specified file. 00576 00577 ********************************************************************************************/ 00578 00579 00580 00581 INT32 BasePMFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, UINT32 HeaderSize, 00582 UINT32 FileSize) 00583 { 00584 TRACEUSER( "Neville", _T("BasePMFilter::HowCompatible")); 00585 // We need to remember what we thought of this file in our class variable. 00586 // So, set it to a nice default value at the start. 00587 PPMHowCompatible = 0; 00588 00589 // Check that we've got enough data to do our check 00590 if (HeaderSize < 4) 00591 { 00592 // Not enough data - ignore this file. 00593 return 0; 00594 } 00595 00596 // copy four chars in to make TCHARs 00597 TCHAR pHeader[4]; 00598 INT32 i; 00599 for (i=0; i<4 ; i++) 00600 pHeader[i]=(TCHAR)(((char *) HeaderStart)[i]); 00601 00602 if ( CheckString(pHeader) ) 00603 { 00604 // finding PPM, PGM or PBM should be good enough to determine that there is 00605 // a high chance that this is the right file. 00606 00607 // Remember what we thought in our class variable. 00608 PPMHowCompatible = 10; 00609 } 00610 else 00611 { 00612 // No PPM signature - we don't want this file. 00613 PPMHowCompatible = 0; 00614 } 00615 00616 TRACEUSER( "Neville", _T("BasePMFilter::HowCompatible returning = %d\n"),PPMHowCompatible); 00617 // Return the found value to the caller. 00618 return PPMHowCompatible; 00619 } 00620 00621 /******************************************************************************************** 00622 00623 > INT32 BasePMFilter::GetPPMCompatibility() 00624 00625 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00626 Created: 30/11/95 00627 Inputs: - 00628 Returns: The value we found in the HowCompatible call. 00629 0 => Not a PPM file. 00630 10 => It is a PPM file. 00631 Purpose: Determine if this filter can load the specified file. 00632 00633 ********************************************************************************************/ 00634 00635 //INT32 BasePMFilter::GetPPMCompatibility() 00636 //{ 00637 // return PPMHowCompatible; 00638 //} 00639 00640 /******************************************************************************************** 00641 00642 > BOOL BasePMFilter::ReadFromFile(OILBitmap* pOilBitmap) 00643 00644 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00645 Created: 30/11/95 00646 Inputs: pOilBitmap pointer to the oil bitmap data to be filled in 00647 Outputs: Will have filled in BMInfo pointer to the bitmap header to fill in 00648 BMBytes pointer to the bitmap data to fill in 00649 Purpose: Actually does the process of reading a bitmap from a file. 00650 Inherited classes override this to read in different file formats. 00651 00652 Returns: TRUE if worked, FALSE if failed. 00653 00654 ********************************************************************************************/ 00655 00656 BOOL BasePMFilter::ReadFromFile(OILBitmap* pOilBitmap) 00657 { 00658 ERROR2IF(pOilBitmap == NULL,FALSE,"BasePMFilter::ReadFromFile null OilBitmap pointer"); 00659 00660 // Try to import the bitmap as a PPM file. 00661 00662 CCLexFile *pImportFile = GetImportFile(); 00663 ERROR2IF(pImportFile==NULL,FALSE,"BasePMFilter::ReadFromFile - No import file"); 00664 00665 UINT32 ImportMsgId = GetImportMsgID(); 00666 String_64 ProgressString(ImportMsgId); 00667 ProgressString = GetImportProgressString(pImportFile, ImportMsgId); 00668 00669 CWxBitmap* pWBitmap = (CWxBitmap*)pOilBitmap; 00670 00671 LPBITMAPINFO *pInfo = &(pWBitmap->BMInfo); 00672 LPBYTE *pBytes = &(pWBitmap->BMBytes); 00673 00674 // The PPM filter liked it very much and so use it, showing progress bar 00675 BOOL ok = ReadFromFile(pImportFile, pInfo, pBytes, &ProgressString); 00676 00677 SetLastBitmap(); // can only import one bitmap at the moment 00678 return ok; 00679 } 00680 00681 00682 /******************************************************************************************** 00683 00684 > BOOL PPMFilter::ReadFromFile( CCLexFile* pLexFile, LPBITMAPINFO* Info, LPBYTE* Bits, 00685 String_64* ProgressString ) 00686 00687 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00688 Created: 30/11/95 00689 Inputs: A opened CCFile that can be read from. It should be positioned at the 00690 start. Caller is responsible for closing it. The file needs to be in 00691 Binary mode. 00692 ProgressString allows the user to specify whether they require a progress 00693 hourglass or not. If NULL then none is shown, otherwise an progress bar is shown 00694 using the text supplied. Defaults to NULL i.e. no progress bar. 00695 Outputs: Info points to a new LPBITMAPINFO struct and Bits points to the bytes. 00696 These can be freed up with FreeDIB. 00697 Returns: TRUE if worked, FALSE if failed (error will be set accordingly but not reported) 00698 Purpose: Reads a ppm, pgm or pbm file into memory decompressing it as it goes. 00699 ***Errors on 16-bit builds*** 00700 A progress hourglass can be shown if required. 00701 Errors: Calls SetError on FALSE returns. 00702 Scope: Public 00703 SeeAlso: BasePMFilter::ReadFromFile; DIBUtil::ReadFromFile; AccusoftFilters::ReadFromFile; 00704 00705 ********************************************************************************************/ 00706 00707 BOOL BasePMFilter::ReadFromFile( CCLexFile* pLexFile, LPBITMAPINFO* Info, LPBYTE* Bits, 00708 String_64* ProgressString ) 00709 { 00710 ERROR2IF(pLexFile == NULL,FALSE,"BasePMFilter::ReadFromFile bad file pointer"); 00711 ERROR2IF(Info == NULL,FALSE,"BasePMFilter::ReadFromFile bad bitmap info pointer"); 00712 ERROR2IF(Bits == NULL,FALSE,"BasePMFilter::ReadFromFile bad bitmap data pointer"); 00713 00714 *Info = NULL; // in case of early exit 00715 *Bits = NULL; 00716 00717 // place to store the global palette, if present, for later use 00718 // LPRGBQUAD lpGlobalPalette = NULL; // pointer to temporary palette store 00719 // INT32 GlobalPaletteSize = 0; // size of the global palette found 00720 /* 00721 // See if we are capable of parsing this, must be at least a LexFile. 00722 // Check for DiskFile as derived off LexFile and required for binary reads 00723 if (!File->IS_KIND_OF(CCDiskFile)) return FALSE; 00724 CCLexFile* pLexFile = (CCLexFile*) File; 00725 */ 00726 // Must set the exception throwing flag to True and force reporting of errors to False. 00727 // This means that the caller must report an error if the function returns False. 00728 // Any calls to CCFile::GotError will now throw a file exception and should fall into 00729 // the catch handler at the end of the function. 00730 BOOL OldThrowingState = pLexFile->SetThrowExceptions( TRUE ); 00731 BOOL OldReportingState = pLexFile->SetReportErrors( FALSE ); 00732 00733 // If the caller has specified a string then assume they require a progress bar 00734 // Start it up. 00735 if (ProgressString != NULL) BeginSlowJob(100, FALSE, ProgressString); 00736 00737 try 00738 { 00739 // A ppm file consists of:- 00740 // - A "magic number" for identifying the file type. A ppm file's magic 00741 // number is the two characters "P3". 00742 // 00743 // - Whitespace (blanks, TABs, CRs, LFs). 00744 // 00745 // - A width, formatted as ASCII characters in decimal. 00746 // 00747 // - Whitespace. 00748 // 00749 // - A height, again in ASCII decimal. 00750 // 00751 // - Whitespace. 00752 // 00753 // - The maximum color-component value, again in ASCII decimal. 00754 // 00755 // - Whitespace. 00756 // 00757 // - Width * height pixels, each three ASCII decimal values between 0 and 00758 // the specified maximum value, starting at the top-left corner of the 00759 // pixmap, proceeding in normal English reading order. The three values 00760 // for each pixel represent red, green, and blue, respectively; a value of 00761 // 0 means that color is off, and the maximum value means that color is 00762 // maxxed out. 00763 // 00764 // - Characters from a "#" to the next end-of-line are ignored (comments). 00765 // 00766 // - No line should be longer than 70 characters. 00767 // 00768 // Here is an example of a small pixmap in this format: 00769 // P3 00770 // # feep.ppm 00771 // 4 4 00772 // 15 00773 // 0 0 0 0 0 0 0 0 0 15 0 15 00774 // 0 0 0 0 15 7 0 0 0 0 0 0 00775 // 0 0 0 0 0 0 0 15 7 0 0 0 00776 // 15 0 15 0 0 0 0 0 0 0 0 0 00777 00778 // Alternatively, P6 means binary data follow the header 00779 // PGM and PBM are just variations on this theme with different unique numbers and 00780 // the numbers are intepreted differently. 00781 BOOL finished = FALSE; 00782 BOOL ok = TRUE; 00783 00784 // Set the type to an illegal state until we recognise the file 00785 TypeOfPPM = PPM_BAD; 00786 00787 // Initialise lexing routines, and aspects of the lexer 00788 ok = pLexFile->InitLexer(); 00789 pLexFile->SetDelimiters("\r\n"); // Set token delimiting characters 00790 pLexFile->SetCommentMarker('#'); // Set comment marker char 00791 pLexFile->SetWhitespace(" \t"); // Set whitespace chars 00792 pLexFile->SetStringDelimiters("\"\""); // Set string delimiters 00793 00794 // Token buffer remains constant until lexer deinitialisation 00795 const TCHAR* TokenBuf = pLexFile->GetTokenBuf(); 00796 00797 INT32 Width = 0; // Width of bitmap 00798 INT32 Height = 0; // Height of bitmap 00799 INT32 BitsPerPixel = 0; // ColorResolution; // Colour depth required 00800 INT32 BitsPerRGB = 0; // Number of bits present per RGB component 00801 INT32 ColoursPerRGB = 0; // For PGM number of colours present in the image per RGB component 00802 // For PGM will be for number of greyscales 00803 // For PBM is not present 00804 INT32 NumberOfColours = 0; // Number of colours present, 3 for PPM, 1 for PBM and PGM 00805 INT32 MaxCount = 3; // Number of items in the header, usually three 00806 00807 // default to 1 pixel per number read 00808 PixelCounter = 1; 00809 00810 // Grab a token 00811 ok = pLexFile->GetSimpleToken(); 00812 00813 // Should be P3 or P6 00814 PpmTokenIndex Token; 00815 00816 if (ok) 00817 { 00818 // Find out the type of the token 00819 // Look the token up in our table 00820 Token = FindToken(TokenBuf); 00821 00822 switch (Token) 00823 { 00824 case TOKEN_PPM_ASCII: 00825 // Correct file header found so note the type 00826 TypeOfPPM = PPM_ASCII; 00827 NumberOfColours = 3; // RGB 00828 break; 00829 00830 case TOKEN_PPM_BINARY: 00831 // Correct file header found so note the type 00832 TypeOfPPM = PPM_BINARY; 00833 NumberOfColours = 3; // RGB 00834 break; 00835 00836 case TOKEN_PGM_ASCII: 00837 // Correct file header found so note the type 00838 TypeOfPPM = PGM_ASCII; 00839 NumberOfColours = 1; // greyscale 00840 break; 00841 00842 case TOKEN_PGM_BINARY: 00843 // Correct file header found so note the type 00844 TypeOfPPM = PGM_BINARY; 00845 NumberOfColours = 1; // greyscale 00846 break; 00847 00848 case TOKEN_PBM_ASCII: 00849 // Correct file header found so note the type 00850 TypeOfPPM = PBM_ASCII; 00851 MaxCount = 2; 00852 ColoursPerRGB = 1; 00853 NumberOfColours = 1; // B & W 00854 break; 00855 00856 case TOKEN_PBM_BINARY: 00857 // Correct file header found so note the type 00858 TypeOfPPM = PBM_BINARY; 00859 MaxCount = 2; 00860 ColoursPerRGB = 1; 00861 NumberOfColours = 1; // B & W 00862 // if in binary mode we get 8 pixels per number read 00863 PixelCounter = 8; 00864 break; 00865 00866 default: 00867 TRACEUSER( "Neville", _T("BasePMFilter: Unexpected token - %s\n"),TokenBuf); 00868 ok = FALSE; 00869 break; 00870 } 00871 } 00872 else 00873 pLexFile->GotError( _R(IDE_BADFORMAT) ); 00874 00875 // read in the rest of the header data 00876 00877 INT32 Count = 0; 00878 00879 while (ok && !finished && Count < MaxCount) 00880 { 00881 // Grab a token 00882 ok = pLexFile->GetSimpleToken(); 00883 00884 //if (!ok) 00885 // File->GotError( _R(IDE_BADFORMAT) ); 00886 00887 LexTokenType TokenType = pLexFile->GetTokenType(); 00888 00889 switch (TokenType) 00890 { 00891 case TOKEN_NORMAL: 00892 { 00893 Token = FindToken(TokenBuf); 00894 switch (Token) 00895 { 00896 case TOKEN_NONE: 00897 { 00898 // Must be one of the header numbers 00899 INT32 Number; 00900 ok = (camSscanf(TokenBuf,_T("%d"),&Number) == 1); 00901 00902 // Now work out what to do with this 00903 switch (Count) 00904 { 00905 case 0: 00906 Width = Number; 00907 break; 00908 00909 case 1: 00910 Height = Number; 00911 break; 00912 00913 case 2: 00914 ColoursPerRGB = Number; 00915 break; 00916 00917 default: 00918 // Flag a bad token so that we stop parsing this line 00919 ok = FALSE; 00920 TRACEUSER( "Neville", _T("BasePMFilter: Didn't expect to get this number ('%s')\n"), TokenBuf); 00921 break; 00922 } 00923 00924 // Increment our count and see if we have enough info yet 00925 Count++; 00926 if (Count == MaxCount) 00927 finished = TRUE; 00928 } 00929 break; 00930 00931 default: 00932 // Flag a bad token so that we stop parsing this line 00933 ok = FALSE; 00934 TRACEUSER( "Neville", _T("BasePMFilter: Didn't expect to get this token ('%s')\n"),TokenBuf); 00935 break; 00936 } 00937 } 00938 break; 00939 00940 default: 00941 // bad token so stop parsing this line 00942 TRACEUSER( "Neville", _T("BasePMFilter: Unexpected token - %s\n"),TokenBuf); 00943 ok = FALSE; 00944 break; 00945 } 00946 } 00947 00948 TRACEUSER( "Neville", _T("Width = %d Height = %d\n"), Width, Height); 00949 TRACEUSER( "Neville", _T("ColoursPerRGB = %d\n"), ColoursPerRGB); 00950 00951 if (Width > 0 && Height > 0 && ColoursPerRGB > 0) 00952 { 00953 // Allocate the space that we require for this bitmap 00954 // Sanity checks on the file that we have been asked to load. 00955 00956 // Now work out what to do with this 00957 switch (NumberOfColours) 00958 { 00959 case 3: 00960 // RGB 00961 // Bits per pixel = 3 * ColoursPerRGB. 00962 // So 1bpp is impossible with PPM files, use pbm instead 00963 if (ColoursPerRGB > 2 && ColoursPerRGB <= 255) 00964 { 00965 BitsPerPixel = 24; 00966 BitsPerRGB = 8; 00967 } 00968 00969 if (ColoursPerRGB > 1 && ColoursPerRGB <= 2) 00970 { 00971 BitsPerPixel = 8; 00972 BitsPerRGB = 2; 00973 } 00974 00975 if (ColoursPerRGB > 0 && ColoursPerRGB <= 1) 00976 { 00977 BitsPerPixel = 4; 00978 BitsPerRGB = 1; 00979 } 00980 break; 00981 00982 case 1: 00983 // Greyscale or B & W 00984 if (ColoursPerRGB > 15 && ColoursPerRGB <= 255) 00985 { 00986 BitsPerPixel = 8; 00987 BitsPerRGB = 8; 00988 } 00989 00990 if (ColoursPerRGB > 1 && ColoursPerRGB <= 15) 00991 { 00992 BitsPerPixel = 4; 00993 BitsPerRGB = 4; 00994 } 00995 00996 if (ColoursPerRGB > 0 && ColoursPerRGB <= 1) 00997 { 00998 BitsPerPixel = 1; 00999 BitsPerRGB = 1; 01000 } 01001 break; 01002 01003 default: 01004 // Stop parsing as something bad has gone wrong 01005 TRACEUSER( "Neville", _T("BasePMFilter::ReadFromFile bad NumberOfColours %d\n"),NumberOfColours); 01006 pLexFile->GotError( _R(IDE_BADFORMAT) ); 01007 break; 01008 } 01009 01010 TRACEUSER( "Neville", _T("BitsPerPixel = %d\n"), BitsPerPixel); 01011 01012 if ( 01013 (BitsPerPixel != 24) && (BitsPerPixel != 8) && 01014 (BitsPerPixel != 4) && (BitsPerPixel != 1) 01015 ) 01016 pLexFile->GotError( _R(IDE_FORMATNOTSUPPORTED) ); 01017 01018 // we know what sort of bitmap we are - lets allocate a new LPBITMAPINFO and some bytes 01019 *Info = AllocDIB( Width, Height, BitsPerPixel, Bits, NULL ); 01020 01021 if (*Info == NULL || *Bits == NULL) 01022 pLexFile->GotError( _R(IDS_OUT_OF_MEMORY) ); 01023 01024 // If necessary, poke in a correct palette 01025 switch (BitsPerPixel) 01026 { 01027 case 8: 01028 // Make them all greyscale for now as we should only encounter this 01029 // on PGMs 01030 MakeGreyScalePalette((*Info)->bmiColors); 01031 break; 01032 case 4: 01033 Make16GreyScalePalette((*Info)->bmiColors); 01034 break; 01035 case 1: 01036 MakeBlackAndWhitePalette((*Info)->bmiColors); 01037 break; 01038 } 01039 01040 01041 // Work out the word/byte rounded line width rather than the pixel width 01042 INT32 WidthOfLine = DIBUtil::ScanlineSize( Width, BitsPerPixel ); 01043 01044 switch (TypeOfPPM) 01045 { 01046 case PPM_ASCII: 01047 case PGM_ASCII: 01048 case PBM_ASCII: 01049 { 01050 // Read in the ASCII form of the bitmap data 01051 // Pass in the lex file form of the file pointer 01052 ok = ReadASCIIFromFile(pLexFile, *Bits, Width, Height, 01053 ColoursPerRGB, BitsPerRGB, WidthOfLine, 01054 ProgressString, FALSE); 01055 } 01056 break; 01057 01058 case PPM_BINARY: 01059 case PGM_BINARY: 01060 case PBM_BINARY: 01061 { 01062 // First, as we want to read in in binary mode, turn the lexer off 01063 pLexFile->DeinitLexer(); 01064 01065 // If first byte in binary data is &FF then eof() will have been set 01066 // and so a random exception will be thrown. Hence, force all bits to 01067 // be set good. 01068 // Nuke any existing open error states that might exist 01069 // This can cause a random error as when if the first binary byte 01070 // is an 0xFF, then the eof() bit is more than likely set. This will 01071 // then throw a random, file does not exist, error on the next read. 01072 // If we do this we force it into a known state. 01073 pLexFile->SetGoodState(); 01074 01075 // Read in the ASCII form of the bitmap data. 01076 ok = ReadBinaryFromFile(pLexFile, *Bits, Width, Height, 01077 ColoursPerRGB, BitsPerRGB, WidthOfLine, 01078 ProgressString, FALSE); 01079 } 01080 01081 break; 01082 01083 default: 01084 TRACEUSER( "Neville", _T("BasePMFilter: Bad PPM format\n")); 01085 pLexFile->GotError( _R(IDE_BADFORMAT) ); 01086 break; 01087 } 01088 } 01089 01090 01091 // If we reach here and the bitmap allocations are still null then no valid image 01092 // was found and so we should error now. 01093 // Might have just been a GIF file with extension tags in and no images! 01094 if (*Info == NULL || *Bits == NULL) pLexFile->GotError( _R(IDE_BADFORMAT) ); 01095 01096 // We are now finished with the lexer 01097 pLexFile->DeinitLexer(); 01098 01099 // If started, then stop then progress bar 01100 if (ProgressString != NULL) EndSlowJob(); 01101 01102 // Must set the exception throwing and reporting flags back to their entry states 01103 pLexFile->SetThrowExceptions( OldThrowingState ); 01104 pLexFile->SetReportErrors( OldReportingState ); 01105 01106 // er, we seem to have finished OK so say so 01107 return TRUE; 01108 } 01109 01110 catch( CFileException ) 01111 { 01112 // catch our form of a file exception 01113 TRACEUSER( "Neville", _T("PPMFilter::ReadFromFile CC catch handler\n")); 01114 01115 FreeDIB( *Info, *Bits ); // free any alloced memory 01116 *Info = NULL; // and NULL the pointers 01117 *Bits = NULL; 01118 01119 // We are now finished with the lexer 01120 pLexFile->DeinitLexer(); 01121 01122 // If started, then stop then progress bar 01123 if (ProgressString != NULL) EndSlowJob(); 01124 01125 // Must set the exception throwing and reporting flags back to their entry states 01126 pLexFile->SetThrowExceptions( OldThrowingState ); 01127 pLexFile->SetReportErrors( OldReportingState ); 01128 return FALSE; 01129 } 01130 01131 01132 ERROR2( FALSE, "Escaped exception clause somehow" ); 01133 } 01134 01135 /******************************************************************************************** 01136 01137 > void BasePMFilter::PokePaletteEntry(LPRGBQUAD Palette, BYTE red, BYTE green, BYTE blue) 01138 01139 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01140 Created: 30/11/95 01141 Inputs: Palette palette to write to. 01142 red red value to enter into palette entry 01143 green green value to enter into palette entry 01144 blue blue value to enter into palette entry 01145 Outputs: index incremented by one 01146 Returns: - 01147 Purpose: Puts the required value of rgb into the specified palette entry. 01148 SeeAlso: BasePMFilter::MakeGreyScalePalette; 01149 SeeAlso: BasePMFilter::MakeBlackAndWhitePalette; 01150 01151 ********************************************************************************************/ 01152 void BasePMFilter::PokePaletteEntry(LPRGBQUAD *Palette, BYTE red, BYTE green, BYTE blue) 01153 { 01154 if (Palette && (*Palette)) 01155 { 01156 (*Palette)->rgbRed = red; 01157 (*Palette)->rgbGreen = green; 01158 (*Palette)->rgbBlue = blue; 01159 // increment the counter and return it 01160 (*Palette) ++; 01161 } 01162 } 01163 01164 /******************************************************************************************** 01165 01166 > void BasePMFilter::MakeGreyScalePalette(LPRGBQUAD Palette) 01167 01168 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01169 Created: 30/11/95 01170 Inputs: Palette palette to write to. 01171 Outputs: - 01172 Returns: - 01173 Purpose: Makes up a greyscale palette for the specified palette. 01174 01175 ********************************************************************************************/ 01176 void BasePMFilter::MakeGreyScalePalette(LPRGBQUAD Palette) 01177 { 01178 if (Palette) 01179 { 01180 LPRGBQUAD Pal = Palette; 01181 01182 // Poke a greyscale palette into the specified palette 01183 for (INT32 i = 0; i < 256 ; i++) 01184 { 01185 PokePaletteEntry(&Pal, i, i, i); 01186 } 01187 } 01188 } 01189 01190 /******************************************************************************************** 01191 01192 > void BasePMFilter::Make16GreyScalePalette(LPRGBQUAD Palette) 01193 01194 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01195 Created: 30/11/95 01196 Inputs: Palette palette to write to. 01197 Outputs: - 01198 Returns: - 01199 Purpose: Makes up a greyscale palette for the specified palette. 01200 01201 ********************************************************************************************/ 01202 void BasePMFilter::Make16GreyScalePalette(LPRGBQUAD Palette) 01203 { 01204 if (Palette) 01205 { 01206 INT32 Value = 0; 01207 LPRGBQUAD Pal = Palette; 01208 01209 // Poke a greyscale palette into the specified palette 01210 for (INT32 i = 0; i < 16 ; i++) 01211 { 01212 Value = (i * 256)/16; 01213 PokePaletteEntry(&Pal, Value, Value, Value); 01214 } 01215 } 01216 } 01217 01218 /******************************************************************************************** 01219 01220 > void BasePMFilter::MakeBlackAndWhitePalette(LPRGBQUAD Palette) 01221 01222 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01223 Created: 30/11/95 01224 Inputs: Palette palette to write to. 01225 Outputs: - 01226 Returns: - 01227 Purpose: Corrects the first two palette entries to be a correct Gavin black and white 01228 palette. 01229 SeeAlso: OutputDIB::StartFile; OutputDIB::StartExport; 01230 01231 ********************************************************************************************/ 01232 void BasePMFilter::MakeBlackAndWhitePalette(LPRGBQUAD Palette) 01233 { 01234 if (Palette) 01235 { 01236 LPRGBQUAD Pal = Palette; 01237 01238 PokePaletteEntry(&Pal, 0xff, 0xff, 0xff); 01239 PokePaletteEntry(&Pal, 0x00, 0x00, 0x00); 01240 } 01241 } 01242 01243 /******************************************************************************************** 01244 01245 > BOOL BasePMFilter::ReadASCIIFromFile( CCLexFile *pLexFile, LPBYTE pBits, 01246 INT32 Width, INT32 Height, INT32 ColoursPerRGB, INT32 BitsPerRGB, 01247 INT32 WidthOfLine, 01248 String_64 *ProgressString = NULL, BOOL Forwards = FALSE) 01249 01250 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01251 Created: 30/11/95 01252 Inputs: pLexFile An opened CCLexFile that can be read from, already set up to 01253 be lexed and at the position to read in the first item of 01254 ascii data defining the bitmap bits. 01255 pBits Pointer to where to put the bytes of data 01256 Width Read in width of the bitmap 01257 Height Read in height of the bitmap 01258 (together define size of data to read in) 01259 ColoursPerRGB Read in number of colours per RGB component 01260 BitsPerRGB Calculated number of bits per RGB component 01261 WidthOfLine Is the actual rounded width of the line in pixels 01262 ProgressString Allows the user to specify whether they require a progress 01263 hourglass or not. If NULL then none is shown, otherwise an 01264 progress bar is shown using the text supplied. Defaults to 01265 NULL i.e. no progress bar. 01266 Forwards True if want data placed in bitmap top to bottom, otherwise 01267 put it in from bottom to top. 01268 Returns: TRUE if worked, FALSE if failed (error will be set accordingly but not reported) 01269 Purpose: Reads a bitmap data for the ppm, pgm or pbm file into memory. Assumes data 01270 is in ascii format. 01271 A progress hourglass can be shown if required. 01272 Errors: Calls SetError on FALSE returns. 01273 Scope: Static, Public 01274 SeeAlso: BasePMFilter::ReadFromFile; 01275 01276 ********************************************************************************************/ 01277 01278 BOOL BasePMFilter::ReadASCIIFromFile( CCLexFile *pLexFile, LPBYTE pBits, 01279 INT32 Width, INT32 Height, INT32 ColoursPerRGB, INT32 BitsPerRGB, 01280 INT32 WidthOfLine, 01281 String_64 *ProgressString, BOOL Forwards) 01282 { 01283 ERROR2IF(pLexFile == NULL,FALSE,"PPMFilter::ReadASCIIFromFile bad file pointer"); 01284 ERROR2IF(pBits == NULL,FALSE,"PPMFilter::ReadASCIIFromFile bad bitmap data pointer"); 01285 ERROR2IF(Width == 0,FALSE,"PPMFilter::ReadASCIIFromFile bad Width"); 01286 ERROR2IF(Height == 0,FALSE,"PPMFilter::ReadASCIIFromFile bad Height"); 01287 ERROR2IF(ColoursPerRGB == 0,FALSE,"PPMFilter::ReadASCIIFromFile bad ColoursPerRGB"); 01288 ERROR2IF(BitsPerRGB == 0,FALSE,"PPMFilter::ReadASCIIFromFile bad BitsPerRGB"); 01289 01290 // read in the rest of the header data 01291 BOOL finished = FALSE; 01292 BOOL ok = TRUE; 01293 01294 // Token buffer remains constant until lexer deinitialisation 01295 const TCHAR* TokenBuf = pLexFile->GetTokenBuf(); 01296 PpmTokenIndex Token; 01297 01298 // number of bits already written to byte (only relevant for <8bpp images) 01299 INT32 Count = 0; 01300 01301 Red = 0; 01302 Green = 0; 01303 Blue = 0; 01304 Bits = 0; 01305 01306 x = 0; 01307 // (ChrisG 24/01/01) start at the last line if we're going backwards, otherwise start 01308 // at the beginning. 01309 if (Forwards) 01310 y = 0; 01311 else 01312 y = Height - 1; 01313 01314 TotalWidth = Width; 01315 TotalHeight = Height; 01316 TotalWidthOfLine = WidthOfLine; 01317 RGBColours = ColoursPerRGB; 01318 RGBBits = BitsPerRGB; 01319 01320 INT32 Number = 0; 01321 01322 LPBYTE pData; 01323 // BYTE value = 0; 01324 01325 BOOL NextPixel = TRUE; 01326 01327 // (ChrisG 24/01/01) Start at the beginning if going forwards, or the end if going 01328 // backwards, 01329 if (Forwards) 01330 pData = pBits; 01331 else 01332 pData = pBits + (y * WidthOfLine); 01333 01334 while (ok && !finished) 01335 { 01336 // Grab a token 01337 ok = pLexFile->GetSimpleToken(); 01338 01339 LexTokenType TokenType = pLexFile->GetTokenType(); 01340 01341 switch (TokenType) 01342 { 01343 case TOKEN_NORMAL: 01344 { 01345 Token = FindToken(TokenBuf); 01346 01347 switch (Token) 01348 { 01349 case TOKEN_NONE: 01350 { 01351 // Must be one of the header numbers 01352 ok = (camSscanf(TokenBuf,_T("%d"),&Number) == 1); 01353 01354 // Call the correct filters function to put the data into the bitmap itself 01355 // in its own unique way, so long as we haven't failed already. 01356 ok = ok && ReadDataIntoBitmap(Number, &Count, &pData, &NextPixel); 01357 01358 // As a read might be part of a pixel or not, e.g. the R of a 24 bit pixel, 01359 // the recipient of the function call is allowed to say when we are at the next pixel 01360 if (NextPixel) 01361 { 01362 // Increment the required byte number, if at end of line 01363 // go to the start of the next 01364 x++; 01365 if (x >= Width) 01366 { 01367 x = 0; 01368 01369 if (Forwards) 01370 { 01371 // Increment the current line number, if at end of lines 01372 // then we have supposedly read in all the data 01373 y++; 01374 if (y >= Height) 01375 finished = TRUE; 01376 01377 // Update the progress system, if required 01378 if (ProgressString != NULL) 01379 ContinueSlowJob((INT32)(100*y/Height)); 01380 } 01381 else 01382 { 01383 // Decrement the current line number, if past first line 01384 // then we have supposedly read in all the data 01385 y--; 01386 if (y < 0) 01387 finished = TRUE; 01388 01389 // Update the progress system, if required 01390 if (ProgressString != NULL) 01391 ContinueSlowJob((INT32)(100*(Height - y)/Height)); 01392 } 01393 01394 // (ChrisG 24/01/01) if we're halfway through a byte, pad the 01395 // remainder with zeroes before writing it out. 01396 while ((Count != 0) && (ok == TRUE)) 01397 { 01398 ok = ok && ReadDataIntoBitmap(0, &Count, &pData, &NextPixel); 01399 } 01400 01401 // realign the data pointer to the line start to 01402 // account for word aligning of line starts. 01403 pData = pBits + (y * WidthOfLine); 01404 } 01405 } 01406 } 01407 break; 01408 01409 default: 01410 // Flag a bad token so that we stop parsing this line 01411 ok = FALSE; 01412 TRACEUSER( "Neville", _T("PPM: Didn't expect to get this token ('%s')\n"),TokenBuf); 01413 break; 01414 } 01415 } 01416 break; 01417 01418 default: 01419 // bad token so stop parsing this line 01420 TRACEUSER( "Neville", _T("PPM: Unexpected token - %s\n"),TokenBuf); 01421 ok = FALSE; 01422 break; 01423 } 01424 } 01425 01426 return TRUE; 01427 } 01428 01429 /******************************************************************************************** 01430 01431 > BOOL BasePMFilter::ReadBinaryFromFile( CCLexFile *pFile, LPBYTE pBits, 01432 INT32 Width, INT32 Height, INT32 ColoursPerRGB, INT32 BitsPerRGB, 01433 INT32 WidthOfLine, 01434 String_64 *ProgressString = NULL, BOOL Forwards = FALSE ) 01435 01436 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01437 Created: 30/11/95 01438 Inputs: pFile An opened CCFile that can be read from, already set up to 01439 the position to read in the first item of binary data. 01440 pBits Pointer to where to put the bytes of data 01441 Width Read in width of the bitmap 01442 Height Read in height of the bitmap 01443 (together define size of data to read in) 01444 ColoursPerRGB Read in number of colours per RGB component 01445 BitsPerRGB Calculated number of bits per RGB component 01446 WidthOfLine Is the actual rounded width of the line in pixels 01447 ProgressString Allows the user to specify whether they require a progress 01448 hourglass or not. If NULL then none is shown, otherwise an 01449 progress bar is shown using the text supplied. Defaults to 01450 NULL i.e. no progress bar. 01451 Forwards True if want data placed in bitmap top to bottom, otherwise 01452 put it in from bottom to top. 01453 Returns: TRUE if worked, FALSE if failed (error will be set accordingly but not reported) 01454 Purpose: Reads a bitmap data for the ppm, pgm or pbm file into memory. Assumes data 01455 is in binary format. 01456 A progress hourglass can be shown if required. 01457 Errors: Calls SetError on FALSE returns. 01458 Scope: Static, Public 01459 SeeAlso: BasePMFilter::ReadFromFile; 01460 01461 ********************************************************************************************/ 01462 01463 BOOL BasePMFilter::ReadBinaryFromFile( CCLexFile *pFile, LPBYTE pBits, 01464 INT32 Width, INT32 Height, INT32 ColoursPerRGB, INT32 BitsPerRGB, 01465 INT32 WidthOfLine, 01466 String_64 *ProgressString, BOOL Forwards) 01467 { 01468 ERROR2IF(pFile == NULL,FALSE,"PPMFilter::ReadBinaryFromFile bad file pointer"); 01469 ERROR2IF(pBits == NULL,FALSE,"PPMFilter::ReadBinaryFromFile bad bitmap data pointer"); 01470 ERROR2IF(Width == 0,FALSE,"PPMFilter::ReadBinaryFromFile bad Width"); 01471 ERROR2IF(Height == 0,FALSE,"PPMFilter::ReadBinaryFromFile bad Height"); 01472 ERROR2IF(ColoursPerRGB == 0,FALSE,"PPMFilter::ReadBinaryFromFile bad ColoursPerRGB"); 01473 ERROR2IF(BitsPerRGB == 0,FALSE,"PPMFilter::ReadBinaryFromFile bad BitsPerRGB"); 01474 01475 // read in the rest of the bitmap data 01476 BOOL finished = FALSE; 01477 BOOL ok = TRUE; 01478 01479 INT32 Count = 0; 01480 01481 Red = 0; 01482 Green = 0; 01483 Blue = 0; 01484 Bits = 0; 01485 01486 x = 0; 01487 y = 0; 01488 if (!Forwards) 01489 y = Height; 01490 01491 TotalWidth = Width; 01492 TotalHeight = Height; 01493 TotalWidthOfLine = WidthOfLine; 01494 RGBColours = ColoursPerRGB; 01495 RGBBits = BitsPerRGB; 01496 01497 INT32 Number = 0; 01498 TCHAR chr; 01499 01500 BOOL NextPixel = TRUE; 01501 01502 LPBYTE pData = pBits; 01503 01504 while (ok && !finished) 01505 { 01506 // Grab a token 01507 pFile->read(&chr); 01508 01509 Number = (INT32)chr; 01510 01511 // Call the correct filters function to put the data into the bitmap itself 01512 // in its own unique way 01513 ok = ReadDataIntoBitmap((INT32)Number, &Count, &pData, &NextPixel); 01514 01515 // As a read might be part of a pixel or not, e.g. the R of a 24 bit pixel, 01516 // the recipient of the function call is allowed to say when we are at the next pixel 01517 if (NextPixel) 01518 { 01519 // Increment the required byte number, if at end of line 01520 // go to the start of the next 01521 x = x + PixelCounter; 01522 if (x >= Width) 01523 { 01524 x = 0; 01525 01526 if (Forwards) 01527 { 01528 // Increment the current line number, if at end of lines 01529 // then we have supposedly read in all the data 01530 y++; 01531 if (y >= Height) 01532 finished = TRUE; 01533 01534 // Update the progress system, if required 01535 if (ProgressString != NULL) 01536 ContinueSlowJob((INT32)(100*y/Height)); 01537 } 01538 else 01539 { 01540 // Decrement the current line number, if at first line 01541 // then we have supposedly read in all the data 01542 y--; 01543 if (y <= 0) 01544 finished = TRUE; 01545 01546 // Update the progress system, if required 01547 if (ProgressString != NULL) 01548 ContinueSlowJob((INT32)(100*(Height - y)/Height)); 01549 } 01550 01551 // realign the data pointer to the line start to 01552 // account for word aligning of line starts 01553 pData = pBits + y * WidthOfLine; 01554 } 01555 } 01556 } 01557 01558 return TRUE; 01559 } 01560 01561 01562 /******************************************************************************************** 01563 01564 > virtual BOOL BasePMFilter::ReadDataIntoBitmap(INT32 Number, INT32 * Count, LPBYTE * pData, 01565 BOOL * NextPixel) 01566 01567 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01568 Created: 30/11/95 01569 Inputs: Number value read in; 01570 Outputs: Count can be used to distinquish between R, G and B data (can be incremented) 01571 pData place to store the data (can be incremented) 01572 Returns: TRUE if everything went ok, FALSE otherwise. 01573 Purpose: Place the number read in into the specified place in the bitmap. 01574 Baseclass version, should not be called. 01575 SeeAlso: BasePMFilter::ReadBinaryFromFile; BasePMFilterReadASCIIFromFile; 01576 01577 ********************************************************************************************/ 01578 01579 BOOL BasePMFilter::ReadDataIntoBitmap(INT32 Number, INT32 * Count, LPBYTE * pData, BOOL * NextPixel) 01580 { 01581 ERROR2(FALSE,"BasePMFilter::ReadDataIntoBitmap calling baseclass version!"); 01582 return FALSE; 01583 } 01584 01585 01586 /******************************************************************************************** 01587 01588 > virtual BOOL PPMFilter::ReadDataIntoBitmap(INT32 Number, INT32 * Count, LPBYTE * pData) 01589 01590 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01591 Created: 30/11/95 01592 Inputs: Number value read in; 01593 Outputs: Count can be used to distinquish between R, G and B data (can be incremented) 01594 pData place to store the data (can be incremented) 01595 Returns: TRUE if everything went ok, FALSE otherwise. 01596 Purpose: Place the number read in into the specified place in the bitmap. 01597 SeeAlso: BasePMFilter::ReadBinaryFromFile; BasePMFilterReadASCIIFromFile; 01598 01599 ********************************************************************************************/ 01600 01601 BOOL PPMFilter::ReadDataIntoBitmap(INT32 Number, INT32 * Count, LPBYTE * pData, BOOL * NextPixel) 01602 { 01603 // By default, do not move onto the next pixel 01604 *NextPixel = FALSE; 01605 01606 BOOL ok = TRUE; 01607 01608 BYTE value = 0; 01609 01610 // Now work out what to do with this 01611 switch (*Count) 01612 { 01613 case 0: 01614 Red = Number; 01615 break; 01616 01617 case 1: 01618 Green = Number; 01619 break; 01620 01621 case 2: 01622 Blue = Number; 01623 break; 01624 01625 default: 01626 // Flag a bad token so that we stop parsing this line 01627 ok = FALSE; 01628 TRACEUSER( "Neville", _T("PPM: Didn't expect to get this number ('%d')\n"), Number); 01629 break; 01630 } 01631 01632 // Increment our count and see if we have enough info yet 01633 (*Count)++; 01634 01635 if ((*Count) == 3) 01636 { 01637 // We have read in the three colour components so stuff 01638 // them in the required byte 01639 // Now work out what to do with this 01640 switch (RGBBits) 01641 { 01642 case 8: 01643 // Poke those RGB bytes into the next three bytes in memory 01644 *((*pData)++) = Blue & RGBColours; 01645 *((*pData)++) = Green & RGBColours; 01646 *((*pData)++) = Red & RGBColours; 01647 break; 01648 01649 case 2: 01650 value = (Red & RGBColours); 01651 value = (value << RGBBits) + (Green & RGBColours); 01652 value = (value << RGBBits) + (Blue & RGBColours); 01653 *((*pData)++) = value; 01654 break; 01655 01656 default: 01657 // Shouldn't get here so error 2 01658 ERROR2(FALSE, "PPMFilter::ReadDataIntoBitmap bad ColoursPerRGB"); 01659 break; 01660 } 01661 01662 // reset the count 01663 *Count = 0; 01664 01665 // Say we want to move onto the next pixel 01666 *NextPixel = TRUE; 01667 } 01668 01669 return ok; 01670 } 01671 01672 /******************************************************************************************** 01673 01674 > virtual BOOL PGMFilter::ReadDataIntoBitmap(INT32 Number, INT32 * Count, LPBYTE * pData, 01675 BOOL * NextPixel) 01676 01677 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01678 Created: 30/11/95 01679 Inputs: Number value read in; 01680 Outputs: Count can be used to distinquish between R, G and B data 01681 pData place to store the data (can be incremented) 01682 Returns: TRUE if everything went ok, FALSE otherwise. 01683 Purpose: Place the number read in into the specified place in the bitmap. 01684 SeeAlso: BasePMFilter::ReadBinaryFromFile; BasePMFilterReadASCIIFromFile; 01685 01686 ********************************************************************************************/ 01687 01688 BOOL PGMFilter::ReadDataIntoBitmap(INT32 Number, INT32 * Count, LPBYTE * pData, BOOL * NextPixel) 01689 { 01690 // By default, do not move onto the next pixel 01691 *NextPixel = FALSE; 01692 01693 // Work out what to do with the data 01694 switch (RGBBits) 01695 { 01696 case 8: 01697 // Poke those RGB bytes into the next three bytes in memory 01698 *((*pData)++) = Number & RGBColours; 01699 // Always move onto the next pixel 01700 *NextPixel = TRUE; 01701 break; 01702 01703 case 4: 01704 // 4bpp so we must put the data into either the high or low nibble. 01705 // This will be dependent on whether we are on an odd or even pixel. 01706 // So test the LSBit of the curx, if set we will be odd. 01707 // Only move onto next byte every other pixel hence curx/2. 01708 // Get whole present byte 01709 if (x & 1) 01710 { 01711 **(pData) = ((**(pData)) & 0xF0) | (Number & 0x0F); // add into low nibble 01712 *NextPixel = FALSE; 01713 } 01714 else 01715 { 01716 **(pData) = ((**(pData)) & 0x0F) | ((Number << 4) & 0xF0); // add into top nibble 01717 (*pData)++; 01718 *NextPixel = TRUE; 01719 } 01720 break; 01721 01722 default: 01723 // Shouldn't get here so error 2 01724 ERROR2(FALSE, "PGMFilter::ReadDataIntoBitmap bad ColoursPerRGB"); 01725 break; 01726 } 01727 01728 return TRUE; 01729 } 01730 01731 /******************************************************************************************** 01732 01733 > virtual BOOL PBMFilter::ReadDataIntoBitmap(INT32 Number, INT32 * Count, LPBYTE * pData, 01734 BOOL * NextPixel) 01735 01736 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01737 Created: 30/11/95 01738 Inputs: Number value read in; 01739 Outputs: Count number of bytes already read in 01740 pData place to store the data (can be incremented) 01741 NextPixel whether this pixel is finished or not 01742 Returns: TRUE if everything went ok, FALSE otherwise. 01743 Purpose: Place the number read in into the specified place in the bitmap. 01744 SeeAlso: BasePMFilter::ReadBinaryFromFile; BasePMFilterReadASCIIFromFile; 01745 01746 ********************************************************************************************/ 01747 01748 BOOL PBMFilter::ReadDataIntoBitmap(INT32 Number, INT32 * Count, LPBYTE * pData, BOOL * NextPixel) 01749 { 01750 // (ChrisG 24/01/01) NextPixel should never be set to false for single component images, 01751 // as it is supposed to show whether we're halfway through a pixel (e.g. we've written 01752 // the R and G parts of an RGB pixel, but still have to write the B part), NOT halfway 01753 // through a byte. That's what the Count variable is for. 01754 *NextPixel = TRUE; 01755 01756 if (TypeOfPPM == PBM_BINARY) 01757 { 01758 // The bits are stored eight per byte, high bit first low bit last. 01759 // Work out what to do with the data 01760 switch (RGBBits) 01761 { 01762 case 1: 01763 // Poke this monochrome byte into the next byte in memory 01764 *((*pData)++) = Number; 01765 break; 01766 01767 default: 01768 // Shouldn't get here so error 2 01769 ERROR2(FALSE, "PBMFilter::ReadDataIntoBitmap bad ColoursPerRGB"); 01770 break; 01771 } 01772 01773 // Reset the count 01774 *Count = 0; 01775 } 01776 else 01777 { 01778 // Must be 1 bpp 01779 Bits = (Bits << 1) | (Number & RGBBits); 01780 01781 // Increment our count and see if we have enough info yet 01782 (*Count)++; 01783 01784 if (*Count == 8) 01785 { 01786 // Work out what to do with the data 01787 switch (RGBBits) 01788 { 01789 case 1: 01790 // Poke those RGB bytes into the next three bytes in memory 01791 *((*pData)++) = Bits; 01792 break; 01793 01794 default: 01795 // Shouldn't get here so error 2 01796 ERROR2(FALSE, "PBMFilter::ReadDataIntoBitmap bad ColoursPerRGB"); 01797 break; 01798 } 01799 01800 // Reset the count 01801 *Count = 0; 01802 01803 // Reset the bits accumulator 01804 Bits = 0; 01805 } 01806 } 01807 01808 return TRUE; 01809 } 01810 01811 01812 01813 01814 01815 /******************************************************************************************** 01816 01817 > virtual BOOL BasePMFilter::IsThisBppOk(UINT32 Bpp) 01818 01819 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01820 Created: 30/11/95 01821 Inputs: Bpp or Colour depth. 01822 Returns: TRUE if this filter can cope with this colour depth, FALSE otherwise. 01823 Purpose: Check if this Bitmap filter can cope with saving at this Bpp/Colour depth. 01824 SeeAlso: OpMenuExport::DoWithParam; 01825 01826 ********************************************************************************************/ 01827 01828 BOOL BasePMFilter::IsThisBppOk(UINT32 Bpp) 01829 { 01830 return (Bpp == 1 || Bpp == 4 || Bpp == 8 || Bpp == 24); 01831 } 01832