00001 // $Id: ai_eps.cpp 1314 2006-06-14 08:58:56Z builder1 $ 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 // Implementation of Adobe Illustrator EPS filter. 00100 00101 #include "camtypes.h" 00102 00103 #include "ai_eps.h" 00104 #include "ai_epsrr.h" 00105 #include <sstream> 00106 #include <stdio.h> 00107 00108 #include "nodepath.h" 00109 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 //#include "tim.h" 00111 //#include "nev.h" 00112 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00113 #include "ccdc.h" 00114 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00115 #include "page.h" 00116 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00117 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00118 #include "layer.h" 00119 #include "opbevel.h" 00120 #include "progress.h" 00121 #include "ai_grad.h" 00122 #include "ai_bmp.h" 00123 #include "ai_layer.h" 00124 #include "swffiltr.h" 00125 00126 //#include "filtrres.h" // for PhotoShop EPS strings. 00127 00128 DECLARE_SOURCE("$Revision"); 00129 00130 #define new CAM_DEBUG_NEW 00131 00132 CC_IMPLEMENT_DYNAMIC(AIEPSFilter, EPSFilter) 00133 00134 static EPSCommand DeferredToken = 0; 00135 00136 // This is the array of AI EPS command/keyword names. 00137 CommandMap AIEPSFilter::AICommands[] = 00138 { 00139 // Text handling 00140 { EPSC_z, _T("z")}, 00141 { EPSC_e, _T("e")}, 00142 { EPSC_T, _T("T")}, 00143 { EPSC_t, _T("t")}, 00144 00145 // Sentinel 00146 { EPSC_Invalid, _T("Invalid") } 00147 }; 00148 00149 /******************************************************************************************** 00150 00151 > AIEPSFilter::AIEPSFilter() 00152 00153 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00154 Created: 28/10/93 00155 Purpose: Constructor for an AIEPSFilter object. The object should be 00156 initialised before use. 00157 SeeAlso: EPSFilter::Init 00158 00159 ********************************************************************************************/ 00160 00161 AIEPSFilter::AIEPSFilter() 00162 { 00163 // Set up filter descriptions. 00164 FilterNameID = _R(IDT_AIEPS_FILTERNAME); 00165 FilterInfoID = _R(IDT_AIEPS_FILTERINFO); 00166 ImportMsgID = _R(IDT_IMPORTMSG_AI); 00167 00168 FilterID = FILTERID_AIEPS; 00169 00170 #ifndef STANDALONE 00171 Flags.CanImport = TRUE; 00172 //WEBSTER-Martin-27/01/97 00173 #ifdef WEBSTER 00174 Flags.CanExport = FALSE; 00175 #else 00176 Flags.CanExport = TRUE; 00177 #endif //WEBSTER 00178 #else 00179 Flags.CanImport = TRUE; 00180 Flags.CanExport = FALSE; 00181 #endif 00182 00183 AdjustOrigin = FALSE; // Illustrator gets it right... 00184 00185 bDoClip = FALSE; 00186 } 00187 00188 /******************************************************************************************** 00189 00190 > BOOL AIEPSFilter::Init() 00191 00192 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00193 Created: 28/02/94 00194 Returns: TRUE if the filter was initialised ok, FALSE otherwise. 00195 Purpose: Initialise an AIEPSFilter object. 00196 Errors: Will fail if not enough memory to initialise the EPS stack. 00197 SeeAlso: EPSStack 00198 00199 ********************************************************************************************/ 00200 00201 BOOL AIEPSFilter::Init() 00202 { 00203 // Get the OILFilter object 00204 pOILFilter = new AIEPSOILFilter(this); 00205 if (pOILFilter == NULL) 00206 return FALSE; 00207 00208 // Load the description strings 00209 FilterName.Load(FilterNameID); 00210 FilterInfo.Load(FilterInfoID); 00211 00212 bDoClip = FALSE; 00213 00214 // All ok 00215 return TRUE; 00216 } 00217 00218 /******************************************************************************************** 00219 00220 > INT32 AIEPSFilter::EPSHeaderIsOk(ADDR pFileHeader, UINT32 HeaderSize) 00221 00222 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00223 Created: 28/02/94 00224 Returns: TRUE if the header is ok and import should proceed, FALSE if not. 00225 Purpose: Checks to see if the EPS comment headers specify that this is an AI 00226 generated EPS file, as required. 00227 00228 ********************************************************************************************/ 00229 00230 INT32 AIEPSFilter::EPSHeaderIsOk(ADDR pFileHeader, UINT32 HeaderSize) 00231 { 00232 UINT32 Lines = 0; 00233 TCHAR *Buffer = NULL; 00234 00235 // !PS-Adobe line is ok - check creator line... 00236 CCMemTextFile HeaderFile ( reinterpret_cast<char *> ( pFileHeader ), HeaderSize ); 00237 00238 if( HeaderFile.IsMemFileInited () == FALSE || HeaderFile.InitLexer () == FALSE ) 00239 { 00240 HeaderFile.close(); 00241 return 0; 00242 } 00243 00244 // Graeme (28/6/00) - Adobe have changed their file format, and so the first line can 00245 // now be a %PDF directive. Therefore look for this directive in the first twenty 00246 // lines. 00247 while ( ( Lines < 100 ) && !HeaderFile.eof () ) 00248 { 00249 // Get the current line from the file. 00250 HeaderFile.GetLineToken(); 00251 Buffer = const_cast<TCHAR *> ( HeaderFile.GetTokenBuf () ); 00252 00253 // Ensure that it's OK. 00254 ERROR2IF(Buffer == 0, 0, "Returned buffer from lex file == 0"); 00255 00256 // Increment the line counter. 00257 Lines++; 00258 00259 if (camStrncmp(Buffer, _T("%!PS-Adobe"), 10) == 0) 00260 { 00261 // Now find the %%Creator string. 00262 while ((Lines < 100) && !HeaderFile.eof()) 00263 { 00264 HeaderFile.GetLineToken(); 00265 Buffer = const_cast<TCHAR *> ( HeaderFile.GetTokenBuf() ); 00266 ERROR2IF(Buffer == 0, 0, "Returned buffer from lex file == 0"); 00267 Lines++; 00268 00269 // Return TRUE if this file was created by Illustrator, or has been exported 00270 // in Illustrator format. 00271 if (camStrncmp(Buffer, _T("%%Creator: Adobe Illustrator"), 28) == 0) 00272 { 00273 // We definitely want this. 00274 HeaderFile.close(); 00275 return 9; 00276 } 00277 00278 // Another variation on the Illustrator theme 00279 if (camStrncmp(Buffer, _T("%%Creator: AI"), 13) == 0) 00280 { 00281 // We definitely want this. 00282 HeaderFile.close(); 00283 return 9; 00284 } 00285 00286 // yet another variation (see cru_logo.eps for this one) 00287 if (camStrncmp(Buffer, _T("%%Creator: ps2ai.ps"), 19) == 0) 00288 { 00289 HeaderFile.close (); 00290 return 9; 00291 } 00292 00293 // If there is a creator field, see if it mentions Illustrator 00294 // NOTE: this test must be the last one of the "Creator:" tests. 00295 if (camStrncmp(Buffer, _T("%%Creator:"), 10) == 0) 00296 { 00297 // Found the creator line - does it contain the word Illustrator? 00298 if (camStrstr( (const TCHAR*)Buffer, _T("Illustrator")) != NULL) 00299 { 00300 HeaderFile.close(); 00301 return 9; 00302 } 00303 else 00304 break; 00305 } 00306 00307 // If we find the compression token then stop the search as we don't want to 00308 // start looking in the compressed data! 00309 if (camStrncmp(Buffer, _T("%%Compression:"), 14)==0) 00310 break; 00311 } 00312 00313 // Remember to close the file before returning. 00314 HeaderFile.close(); 00315 00316 // Didn't find a suitable Creator line, but the EPS line was ok, so return 00317 // that we're interested, but not sure. 00318 return 5; 00319 } 00320 00321 // If we find the compression token then stop the search as we don't want to start 00322 // looking in the compressed data! 00323 if (camStrncmp(Buffer, _T("%%Compression:"), 14)==0) 00324 break; 00325 } 00326 00327 // Remember to close the file before returning. 00328 HeaderFile.close(); 00329 00330 // This file type isn't suitable. 00331 return 0; 00332 } 00333 00334 /******************************************************************************************** 00335 00336 > BOOL AIEPSFilter::PrepareToExport(CCLexFile* pFile, Spread *pSpread) 00337 00338 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00339 Created: 15/04/94 00340 Inputs: pFile - The file that we are to Export to 00341 pSpread - The spread to export 00342 Returns: TRUE if succeeded, FALSE if not (e.g. no memory for EPS stack) 00343 Purpose: Prepare to import EPS data using this filter. This sets up the filter 00344 to a sensible state for reading. 00345 Errors: Out of memory. 00346 SeeAlso: EPSFilter::DoImport; EPSFilter::CleanUpAfterImport 00347 Scope: Private 00348 00349 ********************************************************************************************/ 00350 00351 BOOL AIEPSFilter::PrepareToExport(CCLexFile* pFile, Spread *pSpread) 00352 { 00353 // Use base class to do most of it 00354 if (!EPSFilter::PrepareToExport(pFile, pSpread)) 00355 return FALSE; 00356 00357 // Create a new render region to export to: 00358 00359 // Don't care about clip regions when exporting - create a null region. 00360 DocRect NullClipRect; 00361 NullClipRect.MakeEmpty(); 00362 00363 // Don't use rendering matrix when exporting EPS as it uses fractional coordinates. 00364 Matrix Identity; 00365 00366 // Don't use view scale; set to 1 00367 FIXED16 Scale(1); 00368 00369 // Create the region specific to our filter. 00370 ExportRegion = new AIEPSRenderRegion(NullClipRect, Identity, Scale); 00371 if (ExportRegion == NULL) 00372 return FALSE; 00373 00374 // Attach to the right device. 00375 ExportRegion->AttachDevice(DocView::GetSelected(), ExportDCPtr->GetDC(), pSpread); 00376 00377 // All ok 00378 return TRUE; 00379 }; 00380 00381 /******************************************************************************************** 00382 00383 > void AIEPSFilter::LookUpToken() 00384 00385 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00386 Created: 25/02/94 00387 Returns: TRUE if the token is an AI EPS token; FALSE if not. 00388 Purpose: Compare the current token against the AI keywords to see if it is 00389 one of them. 00390 SeeAlso: EPSFilter::LookUpToken; EPSFilter::DecodeToken 00391 00392 ********************************************************************************************/ 00393 00394 void AIEPSFilter::LookUpToken() 00395 { 00396 // Not interested in comments 00397 if (Token == EPSC_Comment) 00398 return; 00399 00400 // Check to see if it is a keyword - cycle through the array of keyword names and 00401 // compare against our token (could use a hash table?) 00402 INT32 i = 0; 00403 while (AICommands[i].Cmd != EPSC_Invalid) 00404 { 00405 if (camStrcmp(TokenBuf, AICommands[i].CmdStr) == 0) 00406 { 00407 // Found the token - set the token variable and return success 00408 Token = AICommands[i].Cmd; 00409 return; 00410 } 00411 // Try next command 00412 i++; 00413 } 00414 00415 // Did not find this token - pass on to base class. 00416 EPSFilter::LookUpToken(); 00417 } 00418 00419 /******************************************************************************************** 00420 00421 > BOOL AIEPSFilter::ProcessToken() 00422 00423 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00424 Created: 25/02/94 00425 Returns: TRUE if token understood and processed ok, FALSE if not. 00426 Purpose: Processes EPS tokens that are not part of the standard Illustrator set, or 00427 which need to be handled differently to the standard Illustrator meanings. 00428 i.e. this is the function that handles all the AI EPS operators. 00429 Errors: Syntax error in EPS, Out of memory. 00430 SeeAlso: EPSFilter::ProcessToken 00431 00432 ********************************************************************************************/ 00433 00434 BOOL AIEPSFilter::ProcessToken() 00435 { 00436 // Decode the command, and execute it... 00437 switch (Token) 00438 { 00439 // 00440 // Various random text stuff - ignore it for now. 00441 // 00442 00443 case EPSC_z: 00444 if (!Stack.Discard(5)) 00445 goto EPSError; 00446 break; 00447 00448 case EPSC_e: 00449 if (!Stack.DiscardArray()) 00450 goto EPSError; 00451 break; 00452 00453 case EPSC_t: 00454 if (!Stack.Discard()) 00455 goto EPSError; 00456 break; 00457 00458 case EPSC_T: 00459 break; 00460 00461 // These are the new implementations of the appropriate illustrator tokens. 00462 // In order to work properly and handle complex paths properly, the 00463 // stroking and filling commands have to do something different if they're 00464 // in the middle of some kind of complex path or other 00465 00466 /* 00467 /N % - N - 00468 { 00469 _pola 0 eq 00470 { 00471 _doClip 1 eq {clip /_doClip 0 ddef} if 00472 newpath 00473 } 00474 { 00475 /CRender {N} ddef 00476 }ifelse 00477 } def 00478 00479 */ 00480 case EPSC_N: 00481 case EPSC_n: 00482 if (EPSFlags.ComplexPath == 0) 00483 { 00484 if (bDoClip) 00485 { 00486 // cannot continue as there's no path 00487 if (pInkPath == NULL) 00488 goto EPSError; 00489 00490 if (!ClipRegion.AddNewClippingPath(pInkPath)) 00491 // Error! 00492 return FALSE; 00493 00494 bDoClip = FALSE; 00495 pInkPath->ClearPath(); 00496 delete pPath; 00497 pPath = NULL; 00498 pInkPath = NULL; 00499 } 00500 else 00501 { 00502 // Graeme (14/4/00) - Catch NULL pointers. 00503 if ( pInkPath != NULL ) 00504 { 00505 // Deleting pInkPath throws access violations, which basically break 00506 // the import proceedure. Do not add a delete pInkPath line here! 00507 pInkPath->ClearPath (); 00508 pInkPath = NULL; 00509 } 00510 00511 // Delete isn't worried about NULL pointers. 00512 delete pPath; 00513 pPath = NULL; 00514 } 00515 } 00516 else 00517 { 00518 // We have a deferred render situation. Simply remember the token 00519 DeferredToken = Token; 00520 } 00521 break; 00522 00523 /* 00524 /W % - W - 00525 { 00526 /_doClip 1 ddef 00527 } def 00528 */ 00529 00530 case EPSC_W: 00531 bDoClip = TRUE; 00532 break; 00533 00534 /*u % - *u - 00535 { 00536 _pola 1 add /_pola exch ddef 00537 } def 00538 */ 00539 case EPSC__u: 00540 EPSFlags.ComplexPath++; 00541 break; 00542 00543 /*U % - *U - 00544 { 00545 _pola 1 sub /_pola exch ddef 00546 _pola 0 eq {CRender} if 00547 } def 00548 */ 00549 case EPSC__U: 00550 EPSFlags.ComplexPath--; 00551 if (EPSFlags.ComplexPath <0) 00552 return FALSE; 00553 if (EPSFlags.ComplexPath == 0) 00554 { 00555 EPSCommand oldToken = Token; 00556 Token = DeferredToken; 00557 if (!ProcessToken()) 00558 return FALSE; 00559 Token = oldToken; 00560 } 00561 break; 00562 00563 00564 // Now come the actualy path rendering primitives 00565 // These basically amount to either stroking or 00566 // filling the path, or both. However, if the 00567 // ComplexPath flag is not zero, they will do nothing 00568 // and merely record their token as the deferred token 00569 // Allowing the *U operator to render them at the end 00570 // of the complex group. 00571 // Clipping is equally complicated - if bDoClip is set 00572 // when ComplexPath is zero, it adds the current path 00573 // to the clipping region (i.e. clips to the clipping 00574 // region). 00575 // if bDoClip is zero (FALSE) then it goes ahead and 00576 // renders the path as it normally would 00577 /* 00578 /N % - N - 00579 { 00580 _pola 0 eq 00581 { 00582 _doClip 1 eq {clip /_doClip 0 ddef} if 00583 newpath 00584 } 00585 { 00586 /CRender {N} ddef 00587 }ifelse 00588 } def 00589 /n % - n - 00590 {N} def 00591 /F % - F - 00592 { 00593 _pola 0 eq 00594 { 00595 _doClip 1 eq 00596 { 00597 gsave _pf grestore clip newpath /_lp /none ddef _fc 00598 /_doClip 0 ddef 00599 } 00600 { 00601 _pf 00602 }ifelse 00603 } 00604 { 00605 /CRender {F} ddef 00606 }ifelse 00607 } def 00608 /f % - f - 00609 { 00610 closepath 00611 F 00612 } def 00613 /S % - S - 00614 { 00615 _pola 0 eq 00616 { 00617 _doClip 1 eq 00618 { 00619 gsave _ps grestore clip newpath /_lp /none ddef _sc 00620 /_doClip 0 ddef 00621 } 00622 { 00623 _ps 00624 }ifelse 00625 } 00626 { 00627 /CRender {S} ddef 00628 }ifelse 00629 } def 00630 /s % - s - 00631 { 00632 closepath 00633 S 00634 } def 00635 /B % - B - 00636 { 00637 _pola 0 eq 00638 { 00639 _doClip 1 eq % F clears _doClip 00640 gsave F grestore 00641 { 00642 gsave S grestore clip newpath /_lp /none ddef _sc 00643 /_doClip 0 ddef 00644 } 00645 { 00646 S 00647 }ifelse 00648 } 00649 { 00650 /CRender {B} ddef 00651 }ifelse 00652 } def 00653 /b % - b - 00654 { 00655 closepath 00656 B 00657 } def 00658 */ 00659 case EPSC_S: 00660 case EPSC_b: 00661 case EPSC_B: 00662 case EPSC_f: 00663 case EPSC_F: 00664 case EPSC_s: 00665 if (EPSFlags.ComplexPath > 0) 00666 { 00667 DeferredToken = Token; 00668 break; 00669 } 00670 00671 if (bDoClip) 00672 { 00673 // cannot continue as there's no path 00674 if (pInkPath == NULL) 00675 goto EPSError; 00676 00677 if (!ClipRegion.AddNewClippingPath(pInkPath)) 00678 // Error! 00679 return FALSE; 00680 00681 bDoClip = FALSE; 00682 pInkPath->ClearPath(); 00683 delete pPath; 00684 pPath = NULL; 00685 pInkPath = NULL; 00686 break; 00687 } 00688 // Since now all we want is for it to do what the default 00689 // filter will do, pass it on. 00690 return EPSFilter::ProcessToken(); 00691 break; 00692 00693 case EPSC_H: 00694 case EPSC_h: 00695 // This operator does nothing in Illustrator. Let's follow suit: 00696 break; 00697 00698 00699 default: 00700 // Token not understood - pass on to base class 00701 return EPSFilter::ProcessToken(); 00702 } 00703 00704 00705 // No errors encountered while parsing this token and its operands. 00706 return TRUE; 00707 00708 00709 // Error handlers: 00710 EPSError: 00711 HandleEPSError(); 00712 return FALSE; 00713 00714 #if 0 00715 NoMemory: 00716 HandleNoMemory(); 00717 return FALSE; 00718 #endif 00719 } 00720 00721 00722 /******************************************************************************************** 00723 00724 > TCHAR *AIEPSFilter::GetEPSCommand(EPSCommand Cmd) 00725 00726 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00727 Created: 28/02/94 00728 Inputs: Cmd - the EPS token, e.g. EPSC_aoa 00729 Returns: Pointer to the string representation of the token, e.g. "aoa" 00730 Purpose: Given an EPS token, return the string representation of it; mainly for 00731 debugging purposes. 00732 00733 ********************************************************************************************/ 00734 00735 TCHAR *AIEPSFilter::GetEPSCommand(EPSCommand Cmd) 00736 { 00737 INT32 i = 0; 00738 while (AICommands[i].Cmd != EPSC_Invalid) 00739 { 00740 if (AICommands[i].Cmd == Cmd) 00741 return AICommands[i].CmdStr; 00742 00743 // Try next command 00744 i++; 00745 } 00746 00747 // Couldn't find it - default to base class method 00748 return EPSFilter::GetEPSCommand(Cmd); 00749 } 00750 00751 /******************************************************************************************** 00752 00753 > virtual BOOL AIEPSFilter::NeedsPrintComponents () 00754 00755 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00756 Created: 23/5/00 00757 Returns: FALSE - AI files don't need print components. 00758 Purpose: Informs the print components code that no data should be written. 00759 00760 ********************************************************************************************/ 00761 00762 BOOL AIEPSFilter::NeedsPrintComponents () 00763 { 00764 // We don't want print components! 00765 return FALSE; 00766 } 00767 00768 /******************************************************************************************** 00769 00770 > virtual BOOL AIEPSFilter::WriteNodes ( RenderRegion *pRegion, 00771 ExportDC *pDC, 00772 BOOL VisibleLayersOnly, 00773 BOOL CheckSelected, 00774 BOOL ShowProgress ) 00775 00776 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> (from Neville's original code) 00777 Created: 12/4/00 00778 Inputs: pRegion - the render region to export to. 00779 pDc - device context to use, can be NULL. 00780 VisibleLayersOnly - use visible layers or not 00781 ShowProgress - TRUE then start up a progress bar or FALSE assume 00782 the caller has done it. 00783 Returns: TRUE if the export process completed successfully, FALSE if an error occured. 00784 Purpose: Exports the nodes from the tree. Unlike the standard export, the layer is 00785 dispatched first, followed by its children in their usual order. 00786 SeeAlso: Filter::ExportRender, Filter::ExportRenderNodes 00787 00788 ********************************************************************************************/ 00789 00790 BOOL AIEPSFilter::WriteNodes ( RenderRegion *pRegion, 00791 ExportDC *pDC, 00792 BOOL VisibleLayersOnly, 00793 BOOL CheckSelected, 00794 BOOL ShowProgress ) 00795 { 00796 BOOL success = FALSE; 00797 00798 #ifdef DO_EXPORT 00799 00800 // Find the first node that we should export from this spread 00801 AIEPSRenderRegion *pAIEPSRR = static_cast<AIEPSRenderRegion*> ( pRegion ); 00802 Spread *pSpread = pRegion->GetRenderSpread (); 00803 Layer *pLayer = static_cast<Layer*> ( pSpread->FindFirstChild 00804 ( CC_RUNTIME_CLASS ( Layer ) ) ); 00805 Node *pBGNode = NULL; 00806 00807 // Set the background colour. 00808 DocColour bg(FlashFilter::GetPageColour ( pSpread, &pBGNode ) ); 00809 pRegion->SetBackgroundColour ( bg ); 00810 00811 // Export the file, but catch any file errors. 00812 try 00813 { 00814 // (ChrisG 5/4/2001) Find the first non-guide layer. 00815 while (pLayer && pLayer->IsGuide ()) 00816 { 00817 pLayer = pLayer->FindNextLayer (); 00818 } 00819 00820 // Export the layer and all the nodes if one is found. 00821 if (pLayer) 00822 { 00823 // Export the layer. 00824 pAIEPSRR->StartLayer ( pLayer ); 00825 00826 // Invoke the base class WriteNodes function. 00827 success = Filter::WriteNodes ( pRegion, pDC, VisibleLayersOnly, CheckSelected, 00828 ShowProgress ); 00829 } 00830 } // TRY 00831 00832 catch ( CFileException) 00833 { 00834 // Didn't work - report failure to caller. 00835 if ( pDC ) 00836 pDC->ExportFile->SetThrowExceptions ( FALSE ); 00837 pRegion->StopRender (); 00838 if ( ShowProgress ) 00839 EndSlowJob (); 00840 success = FALSE; 00841 } 00842 00843 #endif 00844 00845 return success; 00846 } 00847 00848 /******************************************************************************************** 00849 00850 > virtual void AIEPSFilter::ProcessTextMatrix(Matrix* pMatrix) 00851 00852 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00853 Created: 18/8/95 00854 Returns: - 00855 Purpose: Having read a text object position matrix from the file, we may (dependent 00856 on the filter type), need to process it in some way, ie add in the spread 00857 origin. 00858 00859 ********************************************************************************************/ 00860 00861 void AIEPSFilter::ProcessTextMatrix(Matrix* pMatrix) 00862 { 00863 // We need to find the current import spread 00864 // and add in the spread origin to this matrix. 00865 DocCoord pos,result; 00866 pMatrix->GetTranslation(pos); 00867 if (ImportInfo.pSpread->PagesCoordToSpreadCoord(&result,pos)) 00868 pMatrix->SetTranslation(result); 00869 } 00870 00871 /******************************************************************************************** 00872 00873 > virtual void AIEPSFilter::SetLineSpacing(INT32 Type, INT32 EMLSpace, MILLIPOINT MLSpace, Double DLSpace) 00874 00875 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 00876 Created: 2/4/2001 00877 Inputs: see Filter::SetLineSpacing () 00878 Returns: BOOL - whether the call to EPSFilter::SetLineSpacing succeeded. 00879 Purpose: This is simply here to allow Illustrator import to catch attempts to set the 00880 line spacing to zero. 00881 00882 ********************************************************************************************/ 00883 BOOL AIEPSFilter::SetTextLineSpacing (INT32 Type, INT32 EMLSpace, MILLIPOINT MLSpace, double DLSpace) 00884 { 00885 BOOL isZero = FALSE; 00886 BOOL success = FALSE; 00887 00888 // is the line spacing going to be set to zero 00889 switch (Type) 00890 { 00891 case 0: // Em based 00892 if (EMLSpace) 00893 isZero = FALSE; 00894 else 00895 isZero = TRUE; 00896 break; 00897 00898 case 1: // Millipoint based 00899 if (MLSpace) 00900 isZero = FALSE; 00901 else 00902 isZero = TRUE; 00903 break; 00904 00905 case 2: // Proportional 00906 if (DLSpace) 00907 isZero = FALSE; 00908 else 00909 isZero = TRUE; 00910 } 00911 00912 // for some reason, Illustrator assumes that a line spacing of 0 actually 00913 // means 100% and confuses more capable apps by overriding this with 00914 // final-form (i.e. printing only) attributes. 00915 if (isZero) 00916 { 00917 success = EPSFilter::SetTextLineSpacing(2,0,0,1.0); 00918 } 00919 else 00920 { 00921 success = EPSFilter::SetTextLineSpacing(Type, EMLSpace, MLSpace, DLSpace); 00922 } 00923 00924 return success; 00925 } 00926 00927 00928 00929 CC_IMPLEMENT_DYNAMIC(PhotoShopEPSFilter, EPSFilter) 00930 00931 00932 /******************************************************************************************** 00933 00934 > PhotShopEPSFilter::PhotoShopEPSFilter() 00935 00936 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 00937 Created: 9/11/00 00938 Purpose: Constructor for an PhotoShopEPSFilter object. The object should be 00939 initialised before use. 00940 SeeAlso: EPSFilter::Init 00941 00942 ********************************************************************************************/ 00943 00944 PhotoShopEPSFilter::PhotoShopEPSFilter() : EPSFilter () 00945 { 00946 // Set up filter descriptions. 00947 FilterNameID = _R(IDT_PHOTOSHOPEPS_FILTERNAME); 00948 FilterInfoID = _R(IDT_IMPORTMSG_PHOTOSHOPEPS); 00949 ImportMsgID = _R(IDT_IMPORTMSG_PHOTOSHOPEPS); 00950 00951 FilterID = FILTERID_PHOTOSHOPEPS; 00952 00953 Flags.CanImport = TRUE; 00954 Flags.CanExport = FALSE; 00955 } 00956 00957 /******************************************************************************************** 00958 00959 > BOOL PhotoShopEPSFilter::Init() 00960 00961 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 00962 Created: 9/11/00 00963 Returns: TRUE if the filter was initialised ok, FALSE otherwise. 00964 Purpose: Initialise an PhotoShopEPSFilter object. 00965 Errors: will fail if not enough memory. 00966 SeeAlso: EPSFilter::Init 00967 00968 ********************************************************************************************/ 00969 00970 BOOL PhotoShopEPSFilter::Init() 00971 { 00972 // Get the OILFilter object 00973 pOILFilter = new PhotoShopEPSOILFilter(this); 00974 if (pOILFilter == NULL) 00975 return FALSE; 00976 00977 // Load the description strings 00978 FilterName.Load(FilterNameID); 00979 FilterInfo.Load(FilterInfoID); 00980 00981 // All ok 00982 return TRUE; 00983 } 00984 00985 /******************************************************************************************** 00986 00987 > INT32 PhotoShopEPSFilter::EPSHeaderIsOk(ADDR pFileHeader, UINT32 HeaderSize) 00988 00989 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 00990 Created: 9/11/00 00991 Returns: The compatibility in the range (0-10) 00992 0 - It's not a photoshop file, so we ain't interested. 00993 10 - It is, so let's stop it from importing. 00994 Purpose: Checks to see if the EPS comment headers specify that this is an Photoshop 00995 generated EPS file, as required. 00996 00997 ********************************************************************************************/ 00998 00999 INT32 PhotoShopEPSFilter::EPSHeaderIsOk(ADDR pFileHeader, UINT32 HeaderSize) 01000 { 01001 UINT32 Lines = 0; 01002 TCHAR *Buffer = NULL; 01003 01004 // !PS-Adobe line is ok - check creator line... 01005 CCMemTextFile HeaderFile ( reinterpret_cast<char *> ( pFileHeader ), HeaderSize ); 01006 01007 if( HeaderFile.IsMemFileInited () == FALSE || HeaderFile.InitLexer () == FALSE ) 01008 { 01009 HeaderFile.close(); 01010 return 0; 01011 } 01012 01013 // Graeme (28/6/00) - Adobe have changed their file format, and so the first line can 01014 // now be a %PDF directive. Therefore look for this directive in the first twenty 01015 // lines. 01016 while ( ( Lines < 100 ) && !HeaderFile.eof () ) 01017 { 01018 // Get the current line from the file. 01019 HeaderFile.GetLineToken(); 01020 Buffer = const_cast<TCHAR *> ( HeaderFile.GetTokenBuf () ); 01021 01022 // Ensure that it's OK. 01023 ERROR2IF(Buffer == 0, 0, "Returned buffer from lex file == 0"); 01024 01025 // Increment the line counter. 01026 Lines++; 01027 01028 if (camStrncmp(Buffer, _T("%!PS-Adobe"), 10) == 0) 01029 { 01030 // Now find the %%Creator string. 01031 while ((Lines < 100) && !HeaderFile.eof()) 01032 { 01033 HeaderFile.GetLineToken(); 01034 Buffer = const_cast<TCHAR *> ( HeaderFile.GetTokenBuf() ); 01035 ERROR2IF(Buffer == 0, 0, "Returned buffer from lex file == 0"); 01036 Lines++; 01037 01038 // Return TRUE if this file was created by Illustrator, or has been exported 01039 // in Illustrator format. 01040 if (camStrncmp(Buffer, _T("%%Creator: Adobe Photoshop"), 26) == 0) 01041 { 01042 // We definitely want this. 01043 HeaderFile.close(); 01044 return 10; 01045 } 01046 01047 // If we find the compression token then stop the search as we don't want to 01048 // start looking in the compressed data! 01049 if (camStrncmp(Buffer, _T("%%Compression:"), 14)==0) 01050 break; 01051 } 01052 01053 // Remember to close the file before returning. 01054 HeaderFile.close(); 01055 01056 // The photoshop EPS filter is only there to stop Xara X from importing Photoshop 01057 // EPS files - so it's not suitable. 01058 return 0; 01059 } 01060 01061 // If we find the compression token then stop the search as we don't want to start 01062 // looking in the compressed data! 01063 if (camStrncmp(Buffer, _T("%%Compression:"), 14)==0) 01064 break; 01065 } 01066 01067 // Remember to close the file before returning. 01068 HeaderFile.close(); 01069 01070 // This file type isn't suitable. 01071 return 0; 01072 } 01073 01074 01075 /******************************************************************************************** 01076 01077 > INT32 PhotoShopEPSFilter::PrepareToImport() 01078 01079 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 01080 Created: 9/11/00 01081 Returns: FALSE - PhotoShop EPS files cannot be imported. 01082 Purpose: Displays an error, if a photoshop EPS file is imported. 01083 01084 ********************************************************************************************/ 01085 01086 BOOL PhotoShopEPSFilter::PrepareToImport() 01087 { 01088 // Display error message. 01089 String_256 WarnMsg; 01090 01091 WarnMsg.MakeMsg(_R(IDT_IMPORTMSG_PHOTOSHOPEPS), _T("")); 01092 Error::SetError(0, WarnMsg, 0); 01093 01094 return FALSE; 01095 } 01096 01097 01098 /******************************************************************************************** 01099 01100 > void PhotoShopEPSFilter::CleanUpAfterImport(BOOL Successful) 01101 01102 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 01103 Created: 10/11/00 01104 Inputs: Successful: TRUE => the import succeeded 01105 FALSE => something went wrong with the import, so abandon all 01106 changes made. 01107 Purpose: Cleans up after the PhotoShop "failed to import" message has been displayed 01108 SeeAlso: PhotoShopEPSFilter::PrepareToImport; EPSFilter::PrepareToImport 01109 Scope: Protected 01110 01111 ********************************************************************************************/ 01112 01113 void PhotoShopEPSFilter::CleanUpAfterImport(BOOL Successful) 01114 { 01115 // Inform all the document components that we have finished importing 01116 TheDocument->EPSEndImport(this, FALSE); 01117 TheDocument->PostImport(); 01118 }