ppmfiltr.cpp

Go to the documentation of this file.
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 

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