00001 // $Id: ai_bmp.cpp 1313 2006-06-13 16:55:22Z alex $ 00002 // ai_bmp.cpp: implementation of the AIBitmapProcessor class. 00003 // 00005 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00006 ================================XARAHEADERSTART=========================== 00007 00008 Xara LX, a vector drawing and manipulation program. 00009 Copyright (C) 1993-2006 Xara Group Ltd. 00010 Copyright on certain contributions may be held in joint with their 00011 respective authors. See AUTHORS file for details. 00012 00013 LICENSE TO USE AND MODIFY SOFTWARE 00014 ---------------------------------- 00015 00016 This file is part of Xara LX. 00017 00018 Xara LX is free software; you can redistribute it and/or modify it 00019 under the terms of the GNU General Public License version 2 as published 00020 by the Free Software Foundation. 00021 00022 Xara LX and its component source files are distributed in the hope 00023 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00024 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00025 See the GNU General Public License for more details. 00026 00027 You should have received a copy of the GNU General Public License along 00028 with Xara LX (see the file GPL in the root directory of the 00029 distribution); if not, write to the Free Software Foundation, Inc., 51 00030 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00031 00032 00033 ADDITIONAL RIGHTS 00034 ----------------- 00035 00036 Conditional upon your continuing compliance with the GNU General Public 00037 License described above, Xara Group Ltd grants to you certain additional 00038 rights. 00039 00040 The additional rights are to use, modify, and distribute the software 00041 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00042 library and any other such library that any version of Xara LX relased 00043 by Xara Group Ltd requires in order to compile and execute, including 00044 the static linking of that library to XaraLX. In the case of the 00045 "CDraw" library, you may satisfy obligation under the GNU General Public 00046 License to provide source code by providing a binary copy of the library 00047 concerned and a copy of the license accompanying it. 00048 00049 Nothing in this section restricts any of the rights you have under 00050 the GNU General Public License. 00051 00052 00053 SCOPE OF LICENSE 00054 ---------------- 00055 00056 This license applies to this program (XaraLX) and its constituent source 00057 files only, and does not necessarily apply to other Xara products which may 00058 in part share the same code base, and are subject to their own licensing 00059 terms. 00060 00061 This license does not apply to files in the wxXtra directory, which 00062 are built into a separate library, and are subject to the wxWindows 00063 license contained within that directory in the file "WXXTRA-LICENSE". 00064 00065 This license does not apply to the binary libraries (if any) within 00066 the "libs" directory, which are subject to a separate license contained 00067 within that directory in the file "LIBS-LICENSE". 00068 00069 00070 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00071 ---------------------------------------------- 00072 00073 Subject to the terms of the GNU Public License (see above), you are 00074 free to do whatever you like with your modifications. However, you may 00075 (at your option) wish contribute them to Xara's source tree. You can 00076 find details of how to do this at: 00077 http://www.xaraxtreme.org/developers/ 00078 00079 Prior to contributing your modifications, you will need to complete our 00080 contributor agreement. This can be found at: 00081 http://www.xaraxtreme.org/developers/contribute/ 00082 00083 Please note that Xara will not accept modifications which modify any of 00084 the text between the start and end of this header (marked 00085 XARAHEADERSTART and XARAHEADEREND). 00086 00087 00088 MARKS 00089 ----- 00090 00091 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00092 designs are registered or unregistered trademarks, design-marks, and/or 00093 service marks of Xara Group Ltd. All rights in these marks are reserved. 00094 00095 00096 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00097 http://www.xara.com/ 00098 00099 =================================XARAHEADEREND============================ 00100 */ 00101 00102 #include "camtypes.h" 00103 #include "ai_bmp.h" 00104 00105 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00106 #include "page.h" 00107 00108 #include "ai5_eps.h" 00109 #include "progress.h" 00110 //#include "tim.h" 00111 00112 #include "nodebmp.h" 00113 00114 DECLARE_SOURCE("$Revision"); 00115 00116 #define new CAM_DEBUG_NEW 00117 00118 00120 // Construction/Destruction 00122 00123 AIBitmapProcessor::AIBitmapProcessor() : 00124 mpNewBitmap(0), 00125 mLastIndex(0) 00126 { 00127 00128 } 00129 00130 AIBitmapProcessor::~AIBitmapProcessor() 00131 { 00132 delete mpNewBitmap; 00133 mpNewBitmap = 0; 00134 } 00135 00136 /******************************************************************************************** 00137 00138 > BOOL AIBitmapProcessor::BeginRaster() 00139 00140 Author: Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com> 00141 Created: 23/03/00 00142 00143 Purpose: Allows the bitmap process to intialize itself for a new bitmap 00144 signalled by the %BeginRaster comment. 00145 00146 Returns: TRUE if the definition was processed, 00147 FALSE if not used by this filter.. 00148 00149 ********************************************************************************************/ 00150 BOOL AIBitmapProcessor::BeginRaster() 00151 { 00152 ENSURE(mpNewBitmap == NULL, "mpNewBitmap is not NULL"); 00153 00154 return TRUE; 00155 } 00156 00157 00158 /******************************************************************************************** 00159 00160 > BOOL AIBitmapProcessor::DecodeXI( AI5EPSFilter& filter ) 00161 00162 Author: Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com> 00163 Created: 23/03/00 00164 Returns: TRUE if the definition was processed, 00165 FALSE if not used by this filter.. 00166 Purpose: Decodes the EPS XI, bitmap definition in an Illustrator 5 file 00167 00168 The format of the operator is: 00169 00170 [ a b c d tx ty ] llx lly urx ury h w bits ImageType AlphaChannelCount reserved bin-ascii ImageMask XI 00171 00172 ********************************************************************************************/ 00173 BOOL AIBitmapProcessor::DecodeXI( AI5EPSFilter& filter ) 00174 { 00175 // Graeme (18/4/00) - This code isn't very pretty, but it's necessary because of the way 00176 // in which the bitmap is stored. If I try a GetCoordPair () to get the bitmap positions, 00177 // the image will be misrendered because the transformation should take place due to the 00178 // tx and ty components of the matrix. Note also that the bitmap's position in Adobe 00179 // Illustrator is taken from the top left corner, whilst we use the bottom left. 00180 00182 // Get the page origin. 00184 00185 // Graeme (18/4/00) - Declare variables to get the origin of the page within Camelot's 00186 // co-ordinate space. 00187 Document *pDocument = filter.GetDocument (); 00188 Spread *pSpread = pDocument->FindFirstSpread (); 00189 Page *pPage = pSpread->FindFirstPageInSpread (); 00190 DocCoord Origin = pPage->GetPageRect ().lo; 00191 00193 // decode the bitmap parameters 00195 00196 Matrix ImageMatrix; 00197 DocCoord Translation; 00198 00199 INT32 h, w, bits, ImageType, AlphaChannelCount, reserved, bin_ascii, ImageMask; 00200 INT32 llx, lly, urx, ury; 00201 00202 INT32 nLength = 0; 00203 INT32 nLineLength = 0; 00204 INT32 nMaxLineOffset = 0; 00205 00206 INT32 nChannels = 0; 00207 00208 NodeBitmap* pNodeBitmap = NULL; 00209 DocCoord p; 00210 00211 // Graeme (18/4/00) - I've replaced the Pop with PopCoordPair for extracting the 00212 // bounding co-ordinates of the bitmap. This means that they will be scaled up 00213 // into the Xara co-ordinate space. I've also reversed the popping of h and w 00214 // from the stack - their order is incorrect in the AI documentation. 00215 if ( !filter.GetStack().Pop(&ImageMask) || 00216 !filter.GetStack().Pop(&bin_ascii) || 00217 !filter.GetStack().Pop(&reserved) || 00218 !filter.GetStack().Pop(&AlphaChannelCount) || 00219 !filter.GetStack().Pop(&ImageType) || 00220 !filter.GetStack().Pop(&bits) || 00221 !filter.GetStack().Pop(&h) || 00222 !filter.GetStack().Pop(&w) || 00223 !filter.GetStack().PopCoord(&ury) || 00224 !filter.GetStack().PopCoord(&urx) || 00225 !filter.GetStack().PopCoord(&lly) || 00226 !filter.GetStack().PopCoord(&llx) || 00227 !filter.GetStack().Pop( &ImageMatrix, TRUE ) 00228 ) 00229 goto EPSError; 00230 00232 // create space for the tentative bitmap 00234 00236 // ImageType gives the number of channels per pixel 00237 // bits is the bits per channel 00238 // However we will convert CMYK bitmaps to RGB 00240 00241 switch ( ImageType ) 00242 { 00243 case 1: // greyscale 00244 nChannels = 1; 00245 break; 00246 case 3: // rgb 00247 nChannels = 3; 00248 break; 00249 case 4: // CMYK 00250 nChannels = 3; 00251 break; 00252 default: // unknown 00253 goto EPSError; 00254 } 00255 00256 mpNewBitmap = new KernelBitmap( w, h, bits * nChannels, 96 ); 00257 if ( !mpNewBitmap ) 00258 goto EPSError; 00259 00261 // We can import greyscale bitmaps as well 00263 00264 if ( ImageType == 1 ) 00265 mpNewBitmap->SetAsGreyscale(); 00266 00267 00269 // get the binary data 00271 00272 nLength = mpNewBitmap->GetActualBitmap()->GetBitmapSize(); 00273 nLineLength = mpNewBitmap->GetActualBitmap()->GetScanlineSize(); 00274 nMaxLineOffset = (( w * mpNewBitmap->GetActualBitmap()->GetBPP() ) / 8) - 1; 00275 00276 if ( !ReadImageData( filter, ImageType, mpNewBitmap->GetBitmapBits(), nLength, nLineLength, nMaxLineOffset ) ) 00277 goto EPSError; 00278 00280 // insert the image into the document 00282 00283 // Get a new NodeBitmap object to import into. Don't know what the 12,12 bit does 00284 pNodeBitmap = new NodeBitmap; 00285 00286 if ( !pNodeBitmap || !pNodeBitmap->SetUpPath(12,12) ) 00287 goto EPSError; 00288 00289 pNodeBitmap->GetBitmapRef()->Attach( mpNewBitmap, filter.GetDocument() ); 00290 00292 // set up the bounds of the shape containing the bitmap 00294 00295 // Graeme (18/4/00) - Adjust the values of lly and ury before they're transformed. 00296 lly -= h * EPSScaleFactor; 00297 ury -= h * EPSScaleFactor; 00298 00299 // Graeme (18/4/00) - Modify the matrix to place the bitmap in the correct place. 00300 ImageMatrix.GetTranslation ( Translation ); // Extract the translation component. 00301 Translation += Origin; // Add the page origin to it. 00302 ImageMatrix.SetTranslation ( Translation ); // And reset the value in the matrix. 00303 00304 // Graeme (17/4/00) - Colin overlooked setting up the bounding parallelogram when he 00305 // wrote this code, and I've just added this. 00306 p.x = llx; 00307 p.y = ury; 00308 ImageMatrix.transform( &p ); 00309 pNodeBitmap->InkPath.InsertMoveTo( p ); 00310 pNodeBitmap->Parallel [0] = p; 00311 00312 p.x = urx; 00313 p.y = ury; 00314 ImageMatrix.transform( &p ); 00315 pNodeBitmap->InkPath.InsertLineTo( p ); 00316 pNodeBitmap->Parallel [1] = p; 00317 00318 p.x = urx; 00319 p.y = lly; 00320 ImageMatrix.transform( &p ); 00321 pNodeBitmap->InkPath.InsertLineTo( p ); 00322 pNodeBitmap->Parallel [2] = p; 00323 00324 p.x = llx; 00325 p.y = lly; 00326 ImageMatrix.transform( &p ); 00327 pNodeBitmap->InkPath.InsertLineTo( p ); 00328 pNodeBitmap->Parallel [3] = p; 00329 00330 p.x = llx; 00331 p.y = ury; 00332 ImageMatrix.transform( &p ); 00333 pNodeBitmap->InkPath.InsertLineTo( p ); 00334 00335 pNodeBitmap->InkPath.CloseSubPath(); 00336 00337 // Graeme (18/4/00) - It is necessary to set the default attributes up for a 00338 // new node bitmap before inserting it into the tree. Otherwise it's rendered 00339 // as a greyscale image, even if it is colour, because there's a start colour 00340 // value set. 00341 pNodeBitmap->ApplyDefaultBitmapAttrs ( NULL ); 00342 00343 filter.AddNewNode( pNodeBitmap ); 00344 00345 return TRUE; 00346 00347 EPSError: 00348 if ( mpNewBitmap ) 00349 { 00350 delete mpNewBitmap; 00351 mpNewBitmap = 0; 00352 } 00353 00354 return FALSE; 00355 } 00356 00357 /******************************************************************************************** 00358 00359 > BOOL AIBitmapProcessor::EndRaster() 00360 00361 Author: Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com> 00362 Created: 23/03/00 00363 00364 Purpose: Allows the bitmap processor to complete the bitmap 00365 signalled by the %EndRaster comment. 00366 00367 Returns: TRUE if the definition was processed, 00368 FALSE if not used by this filter.. 00369 00370 ********************************************************************************************/ 00371 BOOL AIBitmapProcessor::EndRaster() 00372 { 00373 ENSURE(mpNewBitmap != NULL, "mpNewBitmap is NULL"); 00374 00376 // add bitmap to tentative bitmap list, giving an index number 00378 00379 mBitmaps.AddBitmap( mpNewBitmap, mLastIndex ); 00380 00381 // up the index number 00382 ++mLastIndex; 00383 00384 // We're done with this bitmap. 00385 mpNewBitmap = NULL; 00386 00387 return TRUE; 00388 } 00389 00390 00391 00392 00393 00394 00395 00397 00398 /******************************************************************************************** 00399 00400 > BOOL AIBitmapProcessor::ReadImageData( AI5EPSFilter* const pFilter, const INT32 ImageType, ADDR pData, INT32 nLength ) const 00401 00402 Author: Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com> 00403 Created: 23/03/00 00404 Returns: TRUE if the image was read correctly 00405 FALSE if the data length differed from the expected given in nLength 00406 in,out: pData: A pointer to an allocated block of memory to hold the decoded 00407 hexadecimal data. 00408 in: nLength: The expected number of bytes decoded from the stream 00409 ImageType: The AI ImageType given in the XI definition 00410 00411 Purpose: Decodes the hex string style data following an image (XI) operator 00412 placing it in the given buffer. This allows the bitmap data to be read into 00413 a bitmap. 00414 00415 Each line begins %XXXX where XXXX are hex numbers. 00416 00417 Assumes that the first % token has not yet been read. 00418 00419 ********************************************************************************************/ 00420 BOOL AIBitmapProcessor::ReadImageData( AI5EPSFilter& filter, const INT32 ImageType, ADDR pDataStart, INT32 nLength, INT32 nLineLength, INT32 nMaxLineOffset ) 00421 { 00423 // ignore the whitespace (EOL) 00425 00426 filter.GetEPSFile()->GetToken(); 00427 00429 // read the first % line 00431 filter.GetEPSFile()->GetToken(); 00432 00434 // We need some running values 00436 BYTE ColourVal[4] = {0,0,0,0}; 00437 UINT32 nShift = 0; // which colour component is being read 00438 00440 // start with last line 00442 00443 ADDR pCurrentLine = pDataStart + nLength - nLineLength; 00444 INT32 nLineOffset = 0; 00445 00446 while ( pCurrentLine >= pDataStart && !filter.GetEPSFile()->eof() ) 00447 { 00448 // the data ends with a comment 00449 if ( camStrncmp( filter.GetTokenBuf(), _T("%%EndData"), 9 ) == 0 ) 00450 break; 00451 00453 // update progress 00455 const INT32 nCharsRead = filter.GetEPSFile()->GetCharsRead(); 00456 if ( nCharsRead > (filter.GetLastProgressUpdate() + 2048) ) 00457 { 00458 if ( !ContinueSlowJob( nCharsRead ) ) 00459 { 00460 // Abort operation - make sure nodes are deleted and not added to the tree. 00461 ERROR(_R(IDT_IMPORT_USERABORT), FALSE); 00462 } 00463 else 00464 { 00465 filter.GetLastProgressUpdate() = nCharsRead; 00466 } 00467 } 00468 00470 // Decode the token into hex data (starting after the %) 00472 00473 INT32 nBytes = 0; 00474 00475 switch ( ImageType ) 00476 { 00477 case 1: // greyscale 00478 nBytes = filter.DecodeHexString( pCurrentLine, nLength, 1 ); 00479 break; 00480 00481 case 3: // rgb 00482 nBytes = DecodeHexStringAsRGB( filter, pCurrentLine, nLineOffset, nLineLength, nMaxLineOffset, 1, ColourVal, nShift ); 00483 break; 00484 00485 case 4: // CMYK 00486 nBytes = DecodeHexStringAsCMYK( filter, pCurrentLine, nLineOffset, nLineLength, nMaxLineOffset, 1, ColourVal, nShift ); 00487 break; 00488 } 00489 00490 if ( nBytes == -1 ) 00491 { 00492 // Error 00493 TRACE( _T("Error in AI5 image data\n") ); 00494 break; 00495 } 00496 00498 // get the next token 00500 filter.GetEPSFile()->GetToken(); 00501 } 00502 00503 return ( pDataStart - pCurrentLine == nLineLength ) ? TRUE : FALSE; 00504 } 00505 00506 00507 /******************************************************************************************** 00508 00509 > bool inline CharToHex( const char& cDigit, BYTE& lNum ) 00510 00511 Author: Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com> 00512 Created: 23/03/00 00513 00514 Purpose: Converts a hex character to a numeric byte. 00515 00516 Inputs: cDigit - the hex character (0-9,A-F) 00517 Outputs: nNum the original value with the hex character ORred into it 00518 00519 Returns: true if the character were valid 00520 false otherwise 00521 00522 ********************************************************************************************/ 00523 bool inline CharToHex( const char& cDigit, BYTE& nNum ) 00524 { 00525 char ch = camToupper(cDigit); 00526 00527 if ( (ch >= '0') && (ch <= '9') ) 00528 { 00529 nNum |= (BYTE) (ch - '0'); 00530 } 00531 else if ((ch >= 'A') && (ch <= 'F')) 00532 { 00533 nNum |= (BYTE) (ch - 'A') + 10; 00534 } 00535 else 00536 { 00537 // Error in hex data 00538 return false; 00539 } 00540 return true; 00541 } 00542 00543 /******************************************************************************************** 00544 00545 > BYTE ColourValueToByte(const double& Value) 00546 00547 Author: Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com> 00548 Created: 23/03/00 00549 00550 00551 Inputs: Value - The colour value, as a double. 00552 Returns: BYTE - The colour value, as a byte. 00553 00554 Purpose: Converts a colour value from a double to a BYTE. 00555 00556 ********************************************************************************************/ 00557 00558 BYTE ColourValueToByte(const double& Value) 00559 { 00560 return BYTE(floor(Value * double(255) + 0.5)); 00561 } 00562 00563 /******************************************************************************************** 00564 00565 > INT32 AIBitmapProcessor::DecodeHexStringAsCMYK( AI5EPSFilter& filter, ADDR& pCurrentLine, 00566 INT32& nLineOffset, INT32 nLineLength, INT32 nMaxLineOffset, UINT32 nStart, BYTE CMYKval[], UINT32& nShift ) 00567 00568 Author: Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com> 00569 Created: 23/03/00 00570 00571 Purpose: Treat the current token as a hex string, and decode it into a BGR bitmap. 00572 00573 Inputs: filter the filter doing the import 00574 nLineLength the maximum number of bytes to read from the hex string. 00575 nMaxLineOffset the width of the bitmap - 1 00576 nStart where in TokenBuf (the member that contains the semantic value of 00577 the token) to start the decoding 00578 00579 in,out: pCurrentLine the line in the bitmap to place the binary data into 00580 nLineOffset the offset into the current line that will be read next 00581 CMYKval the accumulated CMYK value 00582 nShift the index into CMYKVal giving the next value to read 00583 00584 Returns: If an error occurs (i.e. invalid hex data) then -1 is returned. 00585 00586 This is way too complicated but I copied the code from the base class and 00587 worked from there. 00588 How about read the bitmap line by line getting an RGB value from the appropriate 00589 "BitmapParser", say. 00590 00591 ********************************************************************************************/ 00592 INT32 AIBitmapProcessor::DecodeHexStringAsCMYK( AI5EPSFilter& filter, ADDR& pCurrentLine, INT32& nLineOffset, INT32 nLineLength, INT32 nMaxLineOffset, UINT32 nStart, BYTE CMYKval[], UINT32& nShift ) 00593 { 00594 UINT32 nTokenLen = camStrlen(filter.GetTokenBuf() + nStart); 00595 00596 // Assume hex strings are even-numbered in length for the moment 00597 if ( (nTokenLen & 1) != 0 ) 00598 { 00599 TRACE( _T("Bad hex string length in DecodeHexString\n") ); 00600 return -1; 00601 } 00602 00604 // Decode the string two characters at a time keeping a running CMYK value 00606 00607 double dRed, dGreen, dBlue; 00608 double dKey; 00609 00610 UINT32 i; 00611 for ( i = nStart; i < nTokenLen; i += 2 ) 00612 { 00614 // read in the CMYK value one component at at time 00615 // first clear the next value 00617 CMYKval[nShift] = 0; 00618 00619 if ( !CharToHex( filter.GetTokenBuf()[i], CMYKval[nShift] ) ) 00620 return -1; 00621 00622 CMYKval[nShift] <<= 4; 00623 00624 if ( !CharToHex( filter.GetTokenBuf()[i + 1], CMYKval[nShift] ) ) 00625 return -1; 00626 00627 ++nShift; 00628 00630 // once we have a complete CMYK value, stick it in the bitmap 00632 if ( nShift > 3 ) 00633 { 00635 // Convert the colour into an RGB format. 00637 00638 dKey = double(CMYKval[3]) / 255.0; 00639 00640 dRed = 1.0 - (min(1.0, (double(CMYKval[0]) / 255.0 + dKey ))); 00641 dGreen = 1.0 - (min(1.0, (double(CMYKval[1]) / 255.0 + dKey ))); 00642 dBlue = 1.0 - (min(1.0, (double(CMYKval[2]) / 255.0 + dKey ))); 00643 00645 // Set the value for the current pixel in the bitmap. 00647 00648 pCurrentLine[nLineOffset++] = ColourValueToByte( dBlue ); 00649 pCurrentLine[nLineOffset++] = ColourValueToByte( dGreen ); 00650 pCurrentLine[nLineOffset++] = ColourValueToByte( dRed ); 00651 00652 if ( nLineOffset > nMaxLineOffset ) 00653 { 00654 pCurrentLine -= nLineLength; 00655 nLineOffset = 0; 00656 } 00657 00659 // start the next CMYK value 00661 00662 nShift = 0; 00663 } 00664 } 00665 00666 // How much data did we read? 00667 return i; 00668 } 00669 00670 00671 /******************************************************************************************** 00672 00673 > INT32 AIBitmapProcessor::DecodeHexStringAsRGB( AI5EPSFilter& filter, ADDR& pCurrentLine, 00674 INT32& nLineOffset, INT32 nLineLength, INT32 nMaxLineOffset, UINT32 nStart, BYTE RGBVal[], UINT32& nShift ) 00675 00676 Author: Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com> 00677 Created: 23/03/00 00678 00679 Purpose: Treat the current token as a hex string, and decode it into a BGR bitmap. 00680 00681 Inputs: filter the filter doing the import 00682 nLineLength the maximum number of bytes to read from the hex string. 00683 nMaxLineOffset the width of the bitmap - 1 00684 nStart where in TokenBuf (the member that contains the semantic value of 00685 the token) to start the decoding 00686 00687 in,out: pCurrentLine the line in the bitmap to place the binary data into 00688 nLineOffset the offset into the current line that will be read next 00689 RGBVal the accumulated RGB value 00690 nShift the index into RGBVal giving the next value to read 00691 00692 Returns: If an error occurs (i.e. invalid hex data) then -1 is returned. 00693 00694 This is way too complicated but I copied the code from the base class and 00695 worked from there. 00696 How about read the bitmap line by line getting an RGB value from the appropriate 00697 "BitmapParser", say. 00698 00699 ********************************************************************************************/ 00700 INT32 AIBitmapProcessor::DecodeHexStringAsRGB( AI5EPSFilter& filter, ADDR& pCurrentLine, INT32& nLineOffset, INT32 nLineLength, INT32 nMaxLineOffset, UINT32 nStart, BYTE RGBVal[], UINT32& nShift ) 00701 { 00702 UINT32 nTokenLen = camStrlen(filter.GetTokenBuf() + nStart); 00703 00704 // Assume hex strings are even-numbered in length for the moment 00705 if ( (nTokenLen & 1) != 0 ) 00706 { 00707 TRACE( _T("Bad hex string length in DecodeHexString\n") ); 00708 return -1; 00709 } 00710 00712 // Decode the string two characters at a time 00714 00715 UINT32 i; 00716 for ( i = nStart; i < nTokenLen; i += 2 ) 00717 { 00718 RGBVal[nShift] = 0; 00719 00720 if ( !CharToHex( filter.GetTokenBuf()[i], RGBVal[nShift] ) ) 00721 return -1; 00722 00723 RGBVal[nShift] <<= 4; 00724 00725 if ( !CharToHex( filter.GetTokenBuf()[i + 1], RGBVal[nShift] ) ) 00726 return -1; 00727 00728 ++nShift; 00729 00731 // once we have a complete RGB value, stick it in the bitmap 00732 // reversing it to BGR 00734 00735 if ( nShift > 2 ) 00736 { 00737 pCurrentLine[nLineOffset++] = RGBVal[2]; 00738 pCurrentLine[nLineOffset++] = RGBVal[1]; 00739 pCurrentLine[nLineOffset++] = RGBVal[0]; 00740 00741 if ( nLineOffset > nMaxLineOffset ) 00742 { 00743 pCurrentLine -= nLineLength; 00744 nLineOffset = 0; 00745 } 00746 00747 nShift = 0; 00748 } 00749 } 00750 00751 // How much data did we read? 00752 return i; 00753 }