ai_eps.cpp

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

Generated on Sat Nov 10 03:44:08 2007 for Camelot by  doxygen 1.4.4