coreleps.cpp

Go to the documentation of this file.
00001 // $Id: coreleps.cpp 1312 2006-06-13 15:46:45Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 // Implemenation of Corel EPS filters.
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 
00106 #include "coreleps.h"
00107 
00108 #include <sstream>
00109 
00110 #include "nodepath.h"
00111 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "tim.h"
00113 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 //#include "cdrfiltr.h"
00116 
00117 
00118 DECLARE_SOURCE("$Revision: 1312 $");
00119 
00120 #define new CAM_DEBUG_NEW
00121 
00122 CC_IMPLEMENT_DYNAMIC(CorelEPSFilter, EPSFilter)
00123 CC_IMPLEMENT_DYNAMIC(Corel3EPSFilter, CorelEPSFilter)
00124 CC_IMPLEMENT_DYNAMIC(Corel4EPSFilter, CorelEPSFilter)
00125 
00126 
00127 // All the commands used by Corel X.x EPS files.
00128 enum
00129 {
00130     EPSC_cd_0sv = EPSC_EOF + 1,
00131     EPSC_cd_0sm,
00132     EPSC_cd_0rs,
00133     EPSC_cd_0rax,
00134     EPSC_cd_0B,
00135     EPSC_cd_0E,
00136     EPSC_cd_0G,
00137     EPSC_cd_0g,
00138     EPSC_cd_0j,
00139     EPSC_cd_0J,
00140     EPSC_cd_0w,
00141     EPSC_cd_0c,
00142     EPSC_cd_0t,
00143     EPSC_cd_0tm,
00144     EPSC_cd_a,
00145     EPSC_cd_r,
00146     EPSC_cd_x,
00147     EPSC_cd_X,
00148     EPSC_cd_e,
00149     EPSC_cd_z,
00150     EPSC_cd_Z,
00151     EPSC_cd_T,
00152     EPSC_cd_m,
00153     EPSC_matrix,
00154     EPSC_currentmatrix,
00155     EPSC_def,
00156     EPSC_begin,
00157     EPSC_cd_Sentinel
00158 };
00159 
00160 // This is the array of Corel EPS command/keyword names.
00161 CommandMap CorelEPSFilter::CorelCommands[] =
00162 {
00163     EPSC_cd_0sv,        "@sv",
00164     EPSC_cd_0sm,        "@sm",
00165     EPSC_cd_0rs,        "@rs",
00166     EPSC_cd_0rax,       "@rax",
00167     EPSC_cd_0B,         "@B",
00168     EPSC_cd_0E,         "@E",
00169     EPSC_cd_0G,         "@G",
00170     EPSC_cd_0g,         "@g",
00171     EPSC_cd_0j,         "@j",
00172     EPSC_cd_0J,         "@J",
00173     EPSC_cd_0w,         "@w",
00174     EPSC_cd_0c,         "@c",
00175     EPSC_cd_0t,         "@t",
00176     EPSC_cd_0tm,        "@tm",
00177     EPSC_cd_a,          "a",
00178     EPSC_cd_r,          "r",
00179     EPSC_cd_x,          "x",
00180     EPSC_cd_X,          "X",
00181     EPSC_cd_e,          "e",
00182     EPSC_cd_z,          "z",
00183     EPSC_cd_Z,          "Z",
00184     EPSC_cd_T,          "T",
00185     EPSC_cd_m,          "m",
00186 
00187     EPSC_matrix,        "matrix",
00188     EPSC_currentmatrix, "currentmatrix",
00189     EPSC_def,           "def",
00190     EPSC_begin,         "begin",
00191 
00192     // Sentinel
00193     EPSC_Invalid,       "Invalid"
00194 };
00195 
00196 /********************************************************************************************
00197 
00198 >   CorelEPSFilter::CorelEPSFilter()
00199 
00200     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00201     Created:    28/10/93
00202     Purpose:    Constructor for an CorelEPSFilter object.  The object should be 
00203                 initialised before use.
00204     SeeAlso:    EPSFilter::Init
00205 
00206 ********************************************************************************************/
00207 
00208 CorelEPSFilter::CorelEPSFilter()
00209 {
00210     // Set up filter description.
00211     FilterID = FILTERID_NONE;
00212 
00213 #ifndef STANDALONE
00214     Flags.CanImport = TRUE;
00215     Flags.CanExport = FALSE;
00216 #else
00217     Flags.CanImport = FALSE;
00218     Flags.CanExport = FALSE;
00219 #endif
00220 
00221     // Corel EPS does not store layer information
00222     SupportsLayers = FALSE;
00223 }
00224 
00225 /********************************************************************************************
00226 
00227 >   BOOL CorelEPSFilter::Init()
00228 
00229     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00230     Created:    28/02/94
00231     Returns:    TRUE if the filter was initialised ok, FALSE otherwise.
00232     Purpose:    Initialise an CorelEPSFilter object.
00233     Errors:     Will fail if not enough memory to initialise the EPS stack.
00234     SeeAlso:    EPSStack
00235 
00236 ********************************************************************************************/
00237 
00238 BOOL CorelEPSFilter::Init()
00239 {
00240     // All ok
00241     return TRUE;
00242 }
00243 
00244 /********************************************************************************************
00245 
00246 >   void CorelEPSFilter::LookUpToken()
00247 
00248     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00249     Created:    25/02/94
00250     Purpose:    Compare the current token against the Corel keywords to see if it is
00251                 one of them.
00252     SeeAlso:    EPSFilter::LookUpToken
00253 
00254 ********************************************************************************************/
00255 
00256 void CorelEPSFilter::LookUpToken()
00257 {
00258     // Not interested in comments
00259     if (Token == EPSC_Comment)
00260         return;
00261 
00262     // Check to see if it is a keyword - cycle through the array of keyword names and
00263     // compare against our token (could use a hash table?)
00264     INT32 i = 0;
00265     while (CorelCommands[i].Cmd != EPSC_Invalid)
00266     {
00267         if (camStrcmp(TokenBuf, CorelCommands[i].CmdStr) == 0)
00268         {
00269             // Found the token - set the token variable and return success
00270             Token = CorelCommands[i].Cmd;
00271             return;
00272         }
00273         // Try next command
00274         i++;
00275     }
00276 
00277     // Did not find this token - pass on to base class.
00278     EPSFilter::LookUpToken();
00279 }
00280 
00281 /********************************************************************************************
00282 
00283 >   BOOL CorelEPSFilter::ProcessToken()
00284 
00285     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00286     Created:    25/02/94
00287     Returns:    TRUE if token understood and processed ok, FALSE if not.
00288     Purpose:    Processes EPS tokens that are not part of the standard Illustrator set.
00289                 i.e. this is the function that handles all the Corel EPS operators.
00290     Errors:     Syntax error in EPS, Out of memory.
00291     SeeAlso:    EPSFilter::ProcessToken
00292 
00293 ********************************************************************************************/
00294 
00295 BOOL CorelEPSFilter::ProcessToken()
00296 {
00297     // Variables used to extract operands from the stack
00298     DocCoord    Coords[3];
00299     INT32       Long;
00300     FIXEDPOINT  FixedPoint;
00301     PColourCMYK Col;
00302     DocColour   DocCol;
00303     String_64   ColName;
00304     FIXEDPOINT  TintVal;
00305 
00306     // Decode the command, and execute it...
00307     switch (Token)
00308     {
00309         case EPSC_S:
00310         case EPSC_b:
00311         case EPSC_B:
00312         case EPSC_f:
00313         case EPSC_F:
00314         case EPSC_s:
00315             if (ThePathType == PATH_DISCARD)
00316             {
00317                 // Discard this path, but try to use the next one.
00318                 ThePathType = PATH_NORMAL;
00319                 break;
00320             }
00321             
00322             if (ThePathType == PATH_DISCARD_STICKY)
00323                 // Keep discarding paths until explicitly told not to.
00324                 break;
00325 
00326             ENSURE((ThePathType == PATH_NORMAL) || 
00327                    (ThePathType == PATH_RECT) || 
00328                    (ThePathType == PATH_ELLIPSE), "No path in stroke!");
00329                         
00330             // If no path being constructed, probably just some strange masking going on
00331             // that we can't cope with yet, so ignore it.
00332             if (pPath == NULL)
00333                 break;
00334 
00335             // Terminate path - always have to do this with Corel EPS, as it doesn't
00336             // do it itself.
00337             if ((Token == EPSC_s) || (Token == EPSC_b) || (Token == EPSC_f))
00338             {
00339                 if (!pPath->InkPath.CloseSubPath())
00340                     // Not enough dynamic heap to insert the final element of the path
00341                     goto NoMemory;
00342             }
00343 
00344             // Make the path filled or not, depending on the EPS token.
00345             // NB. The IsFilled flag is set here too - this is an area in which
00346             //     Corel EPS is different to AI/AW/Camelot EPS.
00347             if ((Token == EPSC_b) || 
00348                 (Token == EPSC_B) || 
00349                 (Token == EPSC_F) || 
00350                 (Token == EPSC_f))
00351             {
00352                 pPath->InkPath.IsFilled = TRUE;
00353                 SetPathFilled(TRUE);
00354             }
00355             else
00356             {
00357                 pPath->InkPath.IsFilled = FALSE;
00358                 SetPathFilled(FALSE);
00359             }
00360 
00361             if (!EPSFlags.ComplexPath)
00362             {
00363                 // Not a complex path, so we terminate properly.
00364                 pPath->InvalidateBoundingRect();
00365                             
00366                 // Add the attributes, if we haven't done so for this path
00367                 if (EPSFlags.NoAttributes)
00368                 {
00369                     if (!AddAttributes(pPath, (Token != EPSC_f) && (Token != EPSC_F), pPath->InkPath.IsFilled))
00370                         goto NoMemory;
00371                     EPSFlags.NoAttributes = FALSE;
00372                 }
00373                 
00374                 // Add this path into the tree
00375                 if (!AddNewNode(pPath))
00376                     goto NoMemory;
00377 
00378                 // We've finished building this path - set to NULL so the other routines
00379                 // know that we're not building a path any more.
00380                 pPath = NULL;
00381                 pInkPath = NULL;
00382             }
00383             else
00384                 EPSFlags.StrokeComplexPath = (Token != EPSC_f) && (Token != EPSC_F);
00385 
00386             // Handle the next path normally
00387             ThePathType = PATH_NORMAL;
00388             break;
00389 
00390         case EPSC_cd_0sv:
00391         case EPSC_cd_0sm:
00392         case EPSC_cd_0rs:
00393         case EPSC_cd_0rax:
00394             // Ignore these commands - not needed
00395             break;
00396 
00397         case EPSC_cd_0E:
00398             // Bounding box of object - ignore it; we do it ourselves
00399             if (!Stack.Discard(4))
00400                 goto EPSError;
00401             break;
00402 
00403         case EPSC_cd_0B:
00404         case EPSC_cd_a:
00405         case EPSC_cd_r:
00406             // We don't need these commands - it seems safe to ignore them.
00407             // I think they're something to do with text handling, so when we do text
00408             // imoport, we'll need to process them properly.
00409             break;
00410 
00411         case EPSC_cd_0G:
00412         case EPSC_cd_0g:
00413             // Check the flag on the stack
00414             if (!Stack.Pop(&Long))
00415                 goto EPSError;
00416             if (Long == 1)
00417             {
00418                 // Discard the 3 top values from the stack
00419                 if (!Stack.Discard(3))
00420                     goto EPSError;
00421             }
00422             break;
00423 
00424         case EPSC_cd_0J:
00425         case EPSC_cd_0j:
00426             // Save/restore not needed - ignore
00427             break;
00428 
00429         case EPSC_cd_0w:
00430             // NOT IMPLEMENTED IN FULL
00431             // Set current line width to 1 (defined in points)
00432             if (!Stack.Discard(2))
00433                 goto EPSError;
00434                 
00435             if (Stack.Pop(&FixedPoint))
00436             {
00437                 // Scale line width from points to millipoints, and remember for future
00438                 // objects.
00439                 if (!SetLineWidth((MILLIPOINT) (FixedPoint * EPSScaleFactor) / FixedPointScale))
00440                     goto NoMemory;
00441 
00442                 // Check the flag
00443                 if (Stack.Pop(&Long))
00444                 {
00445                     if (Long == 1)
00446                     {
00447                         if (!Stack.DiscardArray())
00448                             goto EPSError;
00449                     }
00450                 }
00451                 else
00452                     goto EPSError;
00453             }
00454             else    
00455                 goto EPSError;
00456             break;
00457 
00458         case EPSC_cd_0c:
00459             // Close the current path  
00460             if (pPath == NULL)
00461                 // No path to close!
00462                 goto EPSError;
00463 
00464             if (!pPath->InkPath.CloseSubPath())
00465                 // Not enough dynamic heap to insert the final element of the path
00466                 goto NoMemory;
00467             break;
00468 
00469         case EPSC_cd_0t:
00470             // Display text - ignore for now; discard (x, y, string)
00471             if (!Stack.Discard(3))
00472                 goto EPSError;
00473             break;
00474                 
00475         case EPSC_cd_0tm:
00476             {
00477                 // Set text matrix - use this to update the stack's transform matrix, as
00478                 // otherwise pathified text will not be imported correctly.
00479                 EPSCommand Cmd;
00480                 Stack.PopCmd(&Cmd);
00481                 if (Cmd != EPSC_ArrayEnd)
00482                 {
00483                     if (IsUserName("Tim"))
00484                         TRACE( _T("@tm: Expected ArrayEnd, found '%s'\n"), GetEPSCommand(Cmd));
00485                     goto EPSError;
00486                 }
00487 
00488                 // Extract the six array values from the stack.
00489                 double M[6];
00490                 INT32 i = 5;
00491                 for (i = 5; i >= 0; i--)
00492                 {
00493                     if (!Stack.Pop(&M[i]))
00494                         goto EPSError;
00495                 }
00496 
00497                 Stack.PopCmd(&Cmd);
00498                 if (Cmd != EPSC_ArrayStart)
00499                 {
00500                     if (IsUserName("Tim"))
00501                         TRACE( _T("@tm: Expected ArrayStart, found '%s'\n"), GetEPSCommand(Cmd));
00502                     goto EPSError;
00503                 }
00504 
00505                 // Convert the abcd values into FIXED16s, cos that's what we use.
00506                 FIXED16 F16[4];
00507                 for (i = 0; i < 4; i++)
00508                 {
00509                     F16[i] = FIXED16(M[i]);
00510                 }
00511 
00512                 // Convert the Tx and Ty to MILLIPOINTS, cos that's what we use.
00513                 INT32 L1 = (INT32) (M[4] * 1000.0);
00514                 INT32 L2 = (INT32) (M[5] * 1000.0);
00515 
00516                 // Construct the matrix and tell the EPS stack to use it for future 
00517                 // coordinates.
00518                 Matrix TextMatrix(F16[0], F16[1], F16[2], F16[3], L1, L2);
00519                 Stack.SetXformMatrix(TextMatrix);
00520 
00521                 break;
00522             }
00523                 
00524         case EPSC_cd_x:
00525             // Set current fill colour (CMYK)
00526             GradFill = FALSE;
00527             if (Stack.PopColour(&Col, TINT_COREL, &TintVal, &ColName))
00528             {
00529                 GetEPSColour(&DocCol, &Col, TINT_COREL, TintVal, &ColName);
00530 
00531                 // Remember this fill colour for future objects
00532                 if (!SetFillColour(DocCol))
00533                     goto NoMemory;
00534             }
00535             else
00536                 // Invalid colour operands
00537                 goto EPSError;
00538             break;
00539             
00540         case EPSC_cd_X:
00541             // Set current line colour (CMYK)
00542             if (Stack.PopColour(&Col, TINT_COREL, &TintVal, &ColName))
00543             {
00544                 GetEPSColour(&DocCol, &Col, TINT_COREL, TintVal, &ColName);
00545 
00546                 // Remember this line colour for future objects
00547                 if (!SetLineColour(DocCol))
00548                     goto NoMemory;
00549             }
00550             else    
00551                 // Invalid colour operands
00552                 goto EPSError;
00553             break;
00554 
00555         case EPSC_cd_e:
00556             // Set text fill mode - ignore
00557             break;
00558 
00559         case EPSC_cd_z:
00560             // Get and scale font - ignore; discard font name and scale
00561             if (!Stack.Discard(2))
00562                 goto EPSError;
00563             break;
00564                 
00565         case EPSC_cd_Z:
00566             // Change font encosing vector - ignore; discard font names and encoding vector.
00567             if (!Stack.Discard(3) || !Stack.DiscardArray())
00568                 goto EPSError;
00569             break;
00570                 
00571         case EPSC_cd_T:
00572             // Stop using text matrix for transformations.
00573             Stack.SetNoXformMatrix();
00574             break;
00575 
00576         // MoveTo
00577         case EPSC_cd_m:
00578             // Get the co-ordinate from the stack
00579             if (Stack.PopCoordPair(&Coords[0]))
00580             {
00581                 if (pPath == NULL)
00582                 {
00583                     ERROR3IF(pInkPath != NULL,"Already got a path");
00584                     if (pInkPath != NULL)
00585                         goto EPSError;
00586 
00587                     // Create a new NodePath object
00588                     pPath = new NodePath;
00589                     
00590                     // No attributes on the path yet
00591                     EPSFlags.NoAttributes = TRUE;
00592                     
00593                     if ((pPath == NULL) || (!pPath->SetUpPath()))
00594                         // Not enough memory to initialise path
00595                         goto NoMemory;
00596                     
00597                     // Position tag at start of path.
00598                     pPath->InkPath.FindStartOfPath();
00599                     // Point inkpath pointer at the nodepath's path object.
00600                     pInkPath = &pPath->InkPath;
00601                 }
00602                 
00603                 // Insert a moveto into the path
00604                 if (!pPath->InkPath.InsertMoveTo(Coords[0]))
00605                     // Not enough dynamic heap to insert the moveto command
00606                     goto NoMemory;
00607             }
00608             else
00609                 // Invalid number/type of coordinate operands
00610                 goto EPSError;
00611             break;
00612 
00613         case EPSC_matrix:
00614             // NOT IMPLEMENTED IN FULL
00615             // Push dummy argument on
00616             Stack.Push((INT32) 0);
00617             break;
00618 
00619         case EPSC_currentmatrix:
00620             // NOT IMPLEMENTED IN FULL
00621             // Ignore this command
00622             break;
00623 
00624         case EPSC_def:
00625             // Pretend to do a 'def' - discard name and defn from stack
00626             if (!Stack.Discard(2))
00627                 goto EPSError;
00628             break;
00629 
00630         case EPSC_begin:
00631             // Pretend to do a 'begin' - discard dictionary
00632             if (!Stack.Discard())
00633                 goto EPSError;
00634             break;
00635 
00636         default:
00637             // Token not understood - pass onto base class.
00638             return EPSFilter::ProcessToken();
00639     }
00640 
00641 
00642     // No errors encountered while parsing this token and its operands.
00643     return TRUE;
00644     
00645     
00646     // Error handlers:
00647     
00648 EPSError:
00649     HandleEPSError();
00650     return FALSE;
00651 
00652 NoMemory:
00653     HandleNoMemory();
00654     return FALSE;
00655 }
00656 
00657 
00658 /********************************************************************************************
00659 
00660 >   char *CorelEPSFilter::GetEPSCommand(EPSCommand Cmd)
00661 
00662     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00663     Created:    28/02/94
00664     Inputs:     Cmd - the EPS token, e.g. EPSC_cd_c
00665     Returns:    Pointer to the string representation of the token, e.g. "@c"
00666     Purpose:    Given an EPS token, return the string representation of it; mainly for
00667                 debugging purposes.
00668 
00669 ********************************************************************************************/
00670 
00671 char *CorelEPSFilter::GetEPSCommand(EPSCommand Cmd)
00672 {
00673     INT32 i = 0;
00674     while (CorelCommands[i].Cmd != EPSC_Invalid)
00675     {
00676         if (CorelCommands[i].Cmd == Cmd)
00677             return CorelCommands[i].CmdStr;
00678 
00679         // Try next command
00680         i++;
00681     }
00682 
00683     // Couldn't find it - default to base class method
00684     return EPSFilter::GetEPSCommand(Cmd);
00685 }
00686 
00687 /********************************************************************************************
00688 
00689 >   BOOL CorelEPSFilter::DecodeCorelGradFill()
00690 
00691     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00692     Created:    18/04/94
00693     Returns:    TRUE if grad fill converted without problems;
00694                 FALSE if not.
00695     Purpose:    Convert the preposterous Corel format of graduated fill information into
00696                 something that resembles sanity, and install it as the current fill.
00697                 The graduated fill information is assumed to be in the
00698                 CorelEPSFilter::GradFillInfo structure.
00699 
00700 ********************************************************************************************/
00701 
00702 BOOL CorelEPSFilter::DecodeCorelGradFill()
00703 {
00704     switch (GradFillInfo.FillType)
00705     {
00706         case 0:
00707             return DecodeLinearGradFill();
00708 
00709         case 1:
00710         case 3:     // square - radial is closest approximation
00711             return DecodeRadialGradFill();
00712 
00713         case 2:
00714             return DecodeConicalGradFill();
00715     }
00716 
00717     // Can't handle any other kinds of fills - ignore them.
00718     return TRUE;
00719 }
00720 
00721 /********************************************************************************************
00722 
00723 >   BOOL CorelEPSFilter::DecodeLinearGradFill()
00724 
00725     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00726     Created:    19/04/94
00727     Returns:    TRUE if grad fill converted without problems;
00728                 FALSE if not.
00729     Purpose:    Convert the Corel grad values (padding, angle of fill etc) into a Camelot
00730                 style grad fill - i.e. start and end points, like Camelot.
00731                 This function copes with all styles of Corel linear graduated fills.
00732     Errors:     Out of memory.
00733     SeeAlso:    CorelEPSFilter::DecodeCorelGradFill; CorelEPSFilter::DecodeRadialGradFill
00734 
00735 ********************************************************************************************/
00736 
00737 BOOL CorelEPSFilter::DecodeLinearGradFill()
00738 {
00739     // NB. this function is (hopefully!) over-complex and will be simplified.
00740     // However, it's like this atm so I can get my head around the weird maths 
00741 
00742     // The desired start and end points of the grad fill 'arrow'.
00743     DocCoord Start, End;
00744 
00745     // First, get the bounding box.
00746     DocRect BBox; 
00747     CDRFilter::GetCorelBBox(pPath, &BBox);
00748 
00749     // Calculate width and height
00750     MILLIPOINT Width = BBox.Width();
00751     MILLIPOINT Height = BBox.Height();
00752 
00753     // Find centre of box
00754     DocCoord Centre;
00755     Centre.x = BBox.lo.x + (Width / 2);
00756     Centre.y = BBox.lo.y + (Height / 2);
00757 
00758     // Find total area of BBox
00759     double TotalArea = (double) Width * (double) Height;
00760 
00761     // Cope with angles > 180
00762     BOOL Mirror = FALSE;
00763     INT32 Angle = GradFillInfo.Angle;
00764     
00765     if (Angle >= 180)
00766     {
00767         Angle -= 180;
00768         Mirror = TRUE;
00769     }
00770     else if (Angle < 0)
00771     {
00772         Angle += 180;
00773         Mirror = TRUE;
00774     }
00775 
00776     Angle += 90;
00777 
00778     if (Angle >= 180)
00779     {
00780         Angle -= 180;
00781     }
00782 
00783     // Calculate tan of the angle - convert angle to radians first.
00784     double Radians = (((double) Angle) / 180.0) * PI;
00785     double TanTheta;
00786     if (Angle == 90)
00787     {
00788         // Special case for horizontal grad fill arrow.
00789 
00790         // Make 0% padding first
00791         Start.x = BBox.lo.x;
00792         Start.y = Centre.y;
00793         End.x = BBox.hi.x;
00794         End.y = Centre.y;
00795 
00796         // Find out width of padding
00797         INT32 Padding = (Width * GradFillInfo.EdgePad) / 100;
00798         Start.x += Padding;
00799         End.x -= Padding;
00800     }
00801     else if (Angle == 0)
00802     {
00803         // Special case for vertical grad fill arrow.
00804 
00805         // Make 0% padding first
00806         Start.x = Centre.x;
00807         Start.y = BBox.lo.y;
00808         End.x = Centre.x;
00809         End.y = BBox.hi.y;
00810 
00811         // Find out width of padding
00812         INT32 Padding = (Height * GradFillInfo.EdgePad) / 100;
00813         Start.y += Padding;
00814         End.y -= Padding;
00815     }
00816     else
00817     {
00818         TanTheta = tan(Radians);
00819 
00820         // Find out what the maximum padding is that we can achieve using just triangles:
00821 
00822         // Find the maximum triangle width
00823         MILLIPOINT TriWidth = (MILLIPOINT) ((double) Height / TanTheta);
00824 
00825         // Limit it to sensible value
00826         if (TriWidth < 0)
00827             TriWidth = -TriWidth;
00828         if (TriWidth > Width)
00829             TriWidth = Width;
00830 
00831         // Find the maximum triangle width
00832         MILLIPOINT TriHeight = (MILLIPOINT) ((double) Width * TanTheta);
00833 
00834         // Limit it to sensible value
00835         if (TriHeight < 0)
00836             TriHeight = -TriHeight;
00837         if (TriHeight > Height)
00838             TriHeight = Height;
00839 
00840         // The 'c' values of the y = mx+c equation.
00841         MILLIPOINT StartC, EndC;
00842 
00843         // Work out the maximum percentage/edge padding this gives us
00844         // (50 because it's 100 / 2 because we want area of triangle, not rectangle).
00845         double Percentage = (50.0 * (double) TriWidth * (double) TriHeight) / TotalArea;
00846 
00847         INT32 Diff = 0;
00848 
00849         // Is this enough?
00850         if (((INT32) Percentage) >= GradFillInfo.EdgePad)
00851         {
00852             // Yes - calculate exactly how big the triangle needs to be.
00853             TriHeight = (MILLIPOINT) sqrt(ABS(((double) GradFillInfo.EdgePad * TotalArea * TanTheta) / 100.0));
00854 
00855             TriWidth = (MILLIPOINT) ((double) TriHeight / TanTheta);
00856             if (TriWidth < 0)
00857                 TriWidth = -TriWidth;
00858 
00859             ENSURE(TriWidth < Width, "Error in Corel Grad fill decoding logic");
00860         }
00861         else
00862         {
00863             // How much percentage do we need to add with each rectangle?
00864             Percentage = (GradFillInfo.EdgePad - Percentage) / 2;
00865 
00866             // Handle the rectangle stuff.
00867             if (TriWidth == Width)
00868             {
00869                 // Need to add rectangles to the top and bottom.
00870                 Diff = (MILLIPOINT) ((Percentage * Height) / 100.0);
00871             }
00872             else
00873             {
00874                 // Need to add rectangles to left and right
00875                 Diff = (MILLIPOINT) ((Percentage * Width) / 100.0);
00876                 Diff = (MILLIPOINT) (Diff / tan(PI - Radians));
00877                 Diff = ABS(Diff);
00878             }
00879         }
00880 
00881         // Work out the C value for the start line (c = y - mx)
00882         // (m = tan(angle) )
00883         if (Angle == 90)
00884         {
00885             //ENSURE(FALSE, "90 degree angle found!");
00886         }
00887         else if (Angle < 90)
00888         {
00889             StartC = (MILLIPOINT) (BBox.lo.y - ((BBox.hi.x - TriWidth) * TanTheta));
00890             EndC = (MILLIPOINT) (BBox.hi.y - ((BBox.lo.x + TriWidth) * TanTheta));
00891         }
00892         else
00893         {
00894             StartC = (MILLIPOINT) (BBox.lo.y - ((BBox.lo.x + TriWidth) * TanTheta));
00895             EndC = (MILLIPOINT) (BBox.hi.y - ((BBox.hi.x - TriWidth) * TanTheta));
00896         }
00897 
00898         // Add on difference for rectangles, if any.
00899         StartC += Diff;
00900         EndC -= Diff;
00901 
00902 
00903         // Work out m and c for the grad fill line.
00904         // We know m is -1/m of the triangle's hypotenuse.
00905         // c = roy - (rox/m)
00906         double FillM = -1.00 / TanTheta;
00907         MILLIPOINT FillC = (MILLIPOINT) (Centre.y - (Centre.x * FillM));
00908 
00909         // Work out intersections:  x = (c2 - c1) / (2m)
00910 
00911         Start.x = (MILLIPOINT) ( (FillC - StartC) / (TanTheta + (1.00 / TanTheta)) );
00912         Start.y = (MILLIPOINT) ((FillM * Start.x) + FillC);
00913 
00914         End.x = (MILLIPOINT) ( (FillC - EndC) / (TanTheta + (1.00 / TanTheta)) );
00915         End.y = (MILLIPOINT) ((FillM * End.x) + FillC);
00916     }
00917 
00918     if (Mirror)
00919     {
00920         // Swap the grid fill end-points over.
00921         DocCoord Tmp = Start;
00922         Start = End;
00923         End = Tmp;
00924     }
00925 
00926     // Set the fill type according to these calculations.
00927     return SetLinearFill(StartColour, EndColour, Start, End);   
00928 }
00929 
00930 /********************************************************************************************
00931 
00932 >   BOOL CorelEPSFilter::DecodeRadialGradFill()
00933 
00934     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00935     Created:    24/04/95
00936     Returns:    TRUE if grad fill converted without problems;
00937                 FALSE if not.
00938     Purpose:    Convert the Corel grad values (padding, centre of fill etc) into a Camelot
00939                 style radial fill - i.e. start and end points, like ArtWorks.
00940                 The calculations may seem strange. They are - but that's how Corel define
00941                 their grad fills.
00942     Errors:     Out of memory.
00943     SeeAlso:    CorelEPSFilter::DecodeCorelGradFill; CorelEPSFilter::DecodeLinearGradFill
00944 
00945 ********************************************************************************************/
00946 
00947 BOOL CorelEPSFilter::DecodeRadialGradFill()
00948 {
00949     // The desired start and end points of the grad fill 'arrow'.
00950     DocCoord Start, End;
00951 
00952     // First, get the bounding box.
00953     DocRect BBox; 
00954     CDRFilter::GetCorelBBox(pPath, &BBox);
00955 
00956     // Calculate width and height
00957     MILLIPOINT Width = BBox.Width();
00958     MILLIPOINT Height = BBox.Height();
00959 
00960     // caluculate the source area
00961     // first, what's the diagonal length
00962     double dWidth = Width;
00963     double dHeight = Height;
00964     INT32 Diagonal = (INT32)sqrt(dWidth*dWidth + dHeight*dHeight);
00965 
00966     // and from that calculate area of the box containing the bit of the
00967     // bit of the circle in the bbox
00968     INT32 Edge = (Diagonal * (100 - (GradFillInfo.EdgePad * 2))) / 100;
00969 
00970     // Start point is the centre given by Corel.
00971     // This centre is percentage offsets from the centre of the object, i.e. (0,0) is
00972     // the centre of the bounding box.
00973     DocCoord Centre = DocCoord(BBox.lo.x + (Width / 2), BBox.lo.y + (Height / 2));
00974     INT32 OffX = (GradFillInfo.RotateX * Width) / 100;
00975     INT32 OffY = (GradFillInfo.RotateY * Height) / 100;
00976     Start.x = Centre.x + OffX;
00977     Start.y = Centre.y + OffY;
00978 
00979     // Find required radius of circle.
00980     double Radius = Edge / 2;
00981 
00982     // how far away is the centre of the fill from the centre of the bbox?
00983     double dOffX = OffX;
00984     double dOffY = OffY;
00985     double Dist = (INT32)sqrt(dOffX*dOffX + dOffY*dOffY);
00986 
00987     // and increase the radius by a bodge factor
00988     double BodgeFactor = 1 + (Dist / (double)(Diagonal / 2));
00989     Radius *= BodgeFactor;
00990     
00991     // End point is start point + radius
00992     End.x = Start.x + ((MILLIPOINT) Radius);
00993     End.y = Start.y;
00994 
00995     // Seems that we need to swap start and end colours...
00996 
00997     // Set the fill type according to these calculations.
00998     return SetRadialFill(EndColour, StartColour, Start, End);   
00999 }
01000 
01001 /********************************************************************************************
01002 
01003 >   BOOL CorelEPSFilter::DecodeConicalGradFill()
01004 
01005     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01006     Created:    19/04/94
01007     Returns:    TRUE if grad fill converted without problems;
01008                 FALSE if not.
01009     Purpose:    Convert the Corel grad values (padding, centre of fill etc) into a Camelot
01010                 style radial fill - i.e. start and end points, like ArtWorks.
01011     Errors:     Out of memory.
01012     SeeAlso:    CorelEPSFilter::DecodeCorelGradFill; CorelEPSFilter::DecodeLinearGradFill
01013 
01014 ********************************************************************************************/
01015 
01016 BOOL CorelEPSFilter::DecodeConicalGradFill()
01017 {
01018     // modified by Ben to get the start and end points right
01019 
01020     // The desired start and end points of the grad fill 'arrow'.
01021     DocCoord Start, End;
01022 
01023     // First, get the bounding box.
01024     DocRect BBox; 
01025     CDRFilter::GetCorelBBox(pPath, &BBox);
01026 
01027     // Calculate width and height
01028     MILLIPOINT Width = BBox.Width();
01029     MILLIPOINT Height = BBox.Height();
01030 
01031     // Start point is the centre given by Corel.
01032     // This centre is percentage offsets from the centre of the object, i.e. (0,0) is
01033     // the centre of the bounding box.
01034     Start.x = BBox.lo.x + (Width  / 2);
01035     Start.y = BBox.lo.y + (Height / 2);
01036     Start.x += ((GradFillInfo.RotateX * Width) / 100);
01037     Start.y += ((GradFillInfo.RotateY * Height) / 100);
01038 
01039     // End point is start point + radius but takes into account the angle
01040     double Radius = Width / 2;
01041     // angle is * 10, and needs to be in radians
01042     double Theta = (((double)(GradFillInfo.Angle)) / 360.0) * (2 * PI);
01043 
01044     // make the angle go anti-clockwise
01045     Theta = 0 - Theta;
01046 
01047     // rotate by PI / 2
01048     Theta -= PI / 2;
01049     
01050     // angle can be negative, ensure it's positive
01051     while(Theta < 0)
01052         Theta += (2 * PI);
01053 
01054     // calculate the triangle
01055     double dx, dy;
01056 
01057     dx = Radius * sin(Theta);
01058     dy = Radius * cos(Theta);
01059 
01060     End.x = Start.x + (INT32)dx;
01061     End.y = Start.y + (INT32)dy;
01062 
01063     // Seems that we need to swap start and end colours...
01064 
01065     // Set the fill type according to these calculations.
01066     return SetConicalFill(EndColour, StartColour, Start, End);  
01067 }
01068 
01069 
01070 /********************************************************************************************
01071 
01072 >   BOOL CorelEPSFilter::AddAttributes(NodeRenderableBounded *pNode, BOOL Stroked, BOOL Filled)
01073 
01074     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01075     Created:    18/04/94
01076     Inputs:     pNode - the bounded renderable node to add atributes to.
01077                 Stroked - TRUE if the object to add attributes to should be stroked, 
01078                          FALSE if not.
01079                 Stroked - TRUE if the object to add attributes to should be filled, 
01080                          FALSE if not.
01081     Returns:    TRUE if the attributes were added ok;
01082                 FALSE if not.
01083     Purpose:    Used as a veneer to EPSFilter::AddAttributes.  It checks to see if the
01084                 current fill style is a graduated fill - if it is, then it calls
01085                 CorelEPSFilter::DecodeCorelGradFill, which converts the Corel form of the
01086                 grad fill to the Camelot form.  This must be done for each object, as the
01087                 grad fill is stored relative to the object's bounding box in Corel EPS files.
01088     Errors:     Out of memory.
01089     SeeAlso:    EPSFilter::AddAttributes; CorelEPSFilter::DeocdeCorelGradFill
01090 
01091 ********************************************************************************************/
01092 
01093 BOOL CorelEPSFilter::AddAttributes(NodeRenderableBounded *pNode, BOOL Stroked, BOOL Filled)
01094 {
01095     // Check to see if we need to set up a Corel graduated fill attribute
01096     if (GradFill)
01097     {
01098         GradFill = FALSE;
01099         // Try to set up the grad fill for this object.
01100         if (!DecodeCorelGradFill())                                    
01101             return FALSE;
01102     }
01103 
01104     // Call the base class version
01105     return EPSFilter::AddAttributes(pNode, Stroked, Filled);
01106 }
01107 
01108 
01109 // All the commands used by Corel 3.x EPS files.
01110 enum
01111 {
01112     EPSC_cd3_0k = EPSC_cd_Sentinel + 1,
01113     EPSC_cd3_0x,
01114 };
01115 
01116 // This is the array of Corel EPS command/keyword names.
01117 CommandMap Corel3EPSFilter::Corel3Commands[] =
01118 {
01119     EPSC_cd3_0k,        "@k",
01120     EPSC_cd3_0x,        "@x",
01121 
01122     // Sentinel
01123     EPSC_Invalid,       "Invalid"
01124 };
01125 
01126 /********************************************************************************************
01127 
01128 >   Corel3EPSFilter::Corel3EPSFilter()
01129 
01130     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01131     Created:    28/10/93
01132     Purpose:    Constructor for a Corel3EPSFilter object.  The object should be 
01133                 initialised before use.
01134     SeeAlso:    EPSFilter::Init
01135 
01136 ********************************************************************************************/
01137 
01138 Corel3EPSFilter::Corel3EPSFilter()
01139 {
01140     // Set up filter description.
01141     FilterID = FILTERID_COREL3_EPS;
01142     ImportMsgID = _R(IDT_IMPORTMSG_COREL3);
01143 
01144 #ifndef STANDALONE
01145     Flags.CanImport = TRUE;
01146     Flags.CanExport = FALSE;
01147 #else
01148     Flags.CanImport = FALSE;
01149     Flags.CanExport = FALSE;
01150 #endif
01151 }
01152 
01153 /********************************************************************************************
01154 
01155 >   BOOL Corel3EPSFilter::Init()
01156 
01157     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01158     Created:    28/02/94
01159     Returns:    TRUE if the filter was initialised ok, FALSE otherwise.
01160     Purpose:    Initialise an Corel3EPSFilter object.
01161     Errors:     Will fail if not enough memory to initialise the EPS stack.
01162     SeeAlso:    EPSStack
01163 
01164 ********************************************************************************************/
01165 
01166 BOOL Corel3EPSFilter::Init()
01167 {
01168     // Get the OILFilter object
01169     pOILFilter = new Corel3EPSOILFilter(this);
01170     if (pOILFilter == NULL)
01171         return  FALSE;
01172 
01173     // Load the description strings
01174     FilterName.Load(_R(IDT_CORELEPS_FILTERNAME));
01175     FilterInfo.Load(_R(IDT_CORELEPS_FILTERINFO));
01176 
01177     // All ok
01178     return TRUE;
01179 }
01180 
01181 /********************************************************************************************
01182 
01183 >   INT32 Corel3EPSFilter::EPSHeaderIsOk(ADDR pFileHeader, UINT32 HeaderSize)
01184 
01185     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01186     Created:    28/02/94
01187     Returns:    TRUE if the header is ok and import should proceed, FALSE if not.
01188     Purpose:    Checks to see if the EPS comment headers specify that this is an Corel
01189                 generated EPS file, as required.
01190 
01191 ********************************************************************************************/
01192 
01193 INT32 Corel3EPSFilter::EPSHeaderIsOk(ADDR pFileHeader, UINT32 HeaderSize)
01194 {
01195     // Check the first line in EPS file
01196     if (camStrncmp((char *) pFileHeader, "%!PS-Adobe-2.0 EPSF", 19) != 0)
01197     {
01198         // Incorrect version of EPS header line - we don't want this
01199         return 0;
01200     }
01201 
01202     // !PS-Adobe line is ok - check creator line...
01203     istrstream HeaderFile((char *) pFileHeader, HeaderSize);
01204     char Buffer[200];
01205     BOOL HaveCreatorString = FALSE;
01206 
01207     UINT32 Lines = 0;
01208     while ((Lines < 20) && !HeaderFile.eof())
01209     {
01210         HeaderFile.getline(Buffer, 200);
01211         Lines++;
01212 
01213         if (camStrncmp(Buffer, "%%Creator: CorelDRAW!", 21) == 0)
01214         {
01215             HaveCreatorString = TRUE;
01216         }
01217 
01218         // Check for CorelDRAW exported by other packages
01219         if (camStrstr("Corel", Buffer) != NULL)
01220             // Found Corel in the creator line - good chance it's Corel EPS.
01221             return 8;
01222 
01223         if(camStrncmp(Buffer, "/wCorelDict", 11) == 0 && HaveCreatorString == TRUE)
01224         {
01225             // OK, found it
01226             return 10;
01227         }
01228 
01229         // If we find the compression token then stop the search as we don't want to start
01230         // looking in the compressed data!
01231         if (camStrncmp(Buffer, "%%Compression:", 14)==0)
01232             break;
01233     }
01234 
01235     // Didn't find a suitable Creator line, but we found an EPS header line.
01236     return 5;
01237 
01238     // May want to look for this string one day.
01239     #if 0
01240     if (camStrncmp(Buf, "% -------------- POSTSCRIPT PROLOG FOR CORELDRAW 3.X", 52) == 0)
01241         FoundProlog = TRUE;
01242     #endif
01243 }
01244 
01245 /********************************************************************************************
01246 
01247 >   void Corel3EPSFilter::LookUpToken()
01248 
01249     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01250     Created:    25/02/94
01251     Purpose:    Compare the current token against the Corel 3 specific keywords to see if it 
01252                 is one of them.
01253     SeeAlso:    EPSFilter::DecodeToken
01254 
01255 ********************************************************************************************/
01256 
01257 void Corel3EPSFilter::LookUpToken()
01258 {
01259     // Not interested in comments
01260     if (Token == EPSC_Comment)
01261         return;
01262 
01263     // Check to see if it is a keyword - cycle through the array of keyword names and
01264     // compare against our token (could use a hash table?)
01265     INT32 i = 0;
01266     while (Corel3Commands[i].Cmd != EPSC_Invalid)
01267     {
01268         if (camStrcmp(TokenBuf, Corel3Commands[i].CmdStr) == 0)
01269         {
01270             // Found the token - set the token variable and return success
01271             Token = Corel3Commands[i].Cmd;
01272             return;
01273         }
01274         // Try next command
01275         i++;
01276     }
01277 
01278     // Did not find this token - try base class
01279     CorelEPSFilter::LookUpToken();
01280 }
01281 
01282 /********************************************************************************************
01283 
01284 >   BOOL Corel3EPSFilter::ProcessToken()
01285 
01286     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01287     Created:    25/02/94
01288     Returns:    TRUE if token understood and processed ok, FALSE if not.
01289     Purpose:    Processes EPS tokens that are not part of the standard Illustrator set.
01290                 i.e. this is the function that handles all the Corel EPS operators.
01291     Errors:     Syntax error in EPS, Out of memory.
01292     SeeAlso:    EPSFilter::ProcessToken
01293 
01294 ********************************************************************************************/
01295 
01296 BOOL Corel3EPSFilter::ProcessToken()
01297 {
01298     // Variables used to extract operands from the stack
01299     PColourCMYK Col;
01300     DocCoord    Coords[3];
01301     TintType    Tint = TINT_NONE;
01302     FIXEDPOINT  TintVal;
01303     String_64   ColName;
01304     double      Padding, RotateX, RotateY;
01305 
01306     // Decode the command, and execute it...
01307     switch (Token)
01308     {
01309         case EPSC_cd3_0x:
01310             Tint = TINT_COREL;
01311         case EPSC_cd3_0k:
01312             // Get the grad fill parameters.
01313             if (!Stack.Pop(&RotateY) || !Stack.Pop(&RotateX) ||
01314                 !Stack.Pop(&Padding) || !Stack.Pop(&GradFillInfo.FillType) ||
01315                 !Stack.Pop(&GradFillInfo.Angle))
01316                 goto EPSError;
01317             
01318             // Convert values from floating point to integer
01319             GradFillInfo.EdgePad = (INT32) (Padding * 100.0);
01320             GradFillInfo.RotateX = (INT32) (RotateX * 100.0);
01321             GradFillInfo.RotateY = (INT32) (RotateY * 100.0);
01322 
01323             // Get the end colour.
01324             if (!Stack.PopColour(&Col, Tint, &TintVal, &ColName))
01325                 // Invalid colour operands
01326                 goto EPSError;
01327 
01328             GetEPSColour(&EndColour, &Col, Tint, TintVal, &ColName);
01329 //          EndColour.SetCMYKValue(&Col);
01330 
01331             // Get the start colour.
01332             if (!Stack.PopColour(&Col, Tint, &TintVal, &ColName))
01333                 // Invalid colour operands
01334                 goto EPSError;
01335 
01336             GetEPSColour(&StartColour, &Col, Tint, TintVal, &ColName);
01337 //          StartColour.SetCMYKValue(&Col);
01338 
01339             GradFill = TRUE;
01340             break;
01341             
01342         default:
01343             return CorelEPSFilter::ProcessToken();
01344     }
01345 
01346 
01347     // No errors encountered while parsing this token and its operands.
01348     return TRUE;
01349     
01350     
01351     // Error handlers:
01352     
01353 EPSError:
01354     HandleEPSError();
01355     return FALSE;
01356 #if 0
01357 NoMemory:
01358     HandleNoMemory();
01359     return FALSE;
01360 #endif
01361 }
01362 
01363 
01364 /********************************************************************************************
01365 
01366 >   char *Corel3EPSFilter::GetEPSCommand(EPSCommand Cmd)
01367 
01368     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01369     Created:    28/02/94
01370     Inputs:     Cmd - the EPS token, e.g. EPSC_cd_c
01371     Returns:    Pointer to the string representation of the token, e.g. "@c"
01372     Purpose:    Given an EPS token, return the string representation of it; mainly for
01373                 debugging purposes.
01374 
01375 ********************************************************************************************/
01376 
01377 char *Corel3EPSFilter::GetEPSCommand(EPSCommand Cmd)
01378 {
01379     INT32 i = 0;
01380     while (Corel3Commands[i].Cmd != EPSC_Invalid)
01381     {
01382         if (Corel3Commands[i].Cmd == Cmd)
01383             return Corel3Commands[i].CmdStr;
01384 
01385         // Try next command
01386         i++;
01387     }
01388 
01389     // Couldn't find it - default to base class method
01390     return CorelEPSFilter::GetEPSCommand(Cmd);
01391 }
01392 
01393 
01394 
01395 
01396 
01397 // All the commands used by Corel 4.x EPS files.
01398 enum
01399 {
01400     EPSC_cd4_0k = EPSC_cd_Sentinel + 1,
01401     EPSC_cd4_0x,
01402     EPSC_eoclip,
01403     EPSC_cd5_0gs,
01404     EPSC_cd5_0gr,
01405     EPSC_cd5_0np
01406 };
01407 
01408 // This is the array of Corel EPS command/keyword names.
01409 CommandMap Corel4EPSFilter::Corel4Commands[] =
01410 {
01411     EPSC_cd4_0k,        "@k",
01412     EPSC_cd4_0x,        "@x",
01413     EPSC_eoclip,        "eoclip",
01414     EPSC_cd5_0gs,       "@gs",
01415     EPSC_cd5_0gr,       "@gr",
01416     EPSC_cd5_0np,       "@np",
01417 
01418     // Sentinel
01419     EPSC_Invalid,       "Invalid"
01420 };
01421 
01422 /********************************************************************************************
01423 
01424 >   Corel4EPSFilter::Corel4EPSFilter()
01425 
01426     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01427     Created:    28/10/93
01428     Purpose:    Constructor for a Corel4EPSFilter object.  The object should be 
01429                 initialised before use.
01430     SeeAlso:    EPSFilter::Init
01431 
01432 ********************************************************************************************/
01433 
01434 Corel4EPSFilter::Corel4EPSFilter()
01435 {
01436     // Set up filter description.
01437     FilterID = FILTERID_COREL4_EPS;
01438     ImportMsgID = _R(IDT_IMPORTMSG_COREL4);
01439 
01440 #ifndef STANDALONE
01441     Flags.CanImport = TRUE;
01442     Flags.CanExport = FALSE;
01443 #else
01444     Flags.CanImport = FALSE;
01445     Flags.CanExport = FALSE;
01446 #endif
01447 }
01448 
01449 /********************************************************************************************
01450 
01451 >   BOOL Corel4EPSFilter::Init()
01452 
01453     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01454     Created:    28/02/94
01455     Returns:    TRUE if the filter was initialised ok, FALSE otherwise.
01456     Purpose:    Initialise an Corel4EPSFilter object.
01457     Errors:     Will fail if not enough memory to initialise the EPS stack.
01458     SeeAlso:    EPSStack
01459 
01460 ********************************************************************************************/
01461 
01462 BOOL Corel4EPSFilter::Init()
01463 {
01464     // Get the OILFilter object
01465     pOILFilter = new Corel4EPSOILFilter(this);
01466     if (pOILFilter == NULL)
01467         return FALSE;
01468 
01469     // Load the description strings
01470     FilterName.Load(_R(IDT_CORELEPS_FILTERNAME));
01471     FilterInfo.Load(_R(IDT_CORELEPS_FILTERINFO));
01472 
01473     // All ok
01474     return TRUE;
01475 }
01476 
01477 /********************************************************************************************
01478 
01479 >   INT32 Corel4EPSFilter::EPSHeaderIsOk(ADDR pFileHeader, UINT32 HeaderSize)
01480 
01481     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01482     Created:    28/02/94
01483     Returns:    TRUE if the header is ok and import should proceed, FALSE if not.
01484     Purpose:    Checks to see if the EPS comment headers specify that this is an Corel
01485                 generated EPS file, as required.
01486 
01487 ********************************************************************************************/
01488 
01489 INT32 Corel4EPSFilter::EPSHeaderIsOk(ADDR pFileHeader, UINT32 HeaderSize)
01490 {
01491     // Check the first line in EPS file
01492     if (camStrncmp((char *) pFileHeader, "%!PS-Adobe-2.0 EPSF-2.0", 23) != 0)
01493     {
01494         // Incorrect version of EPS header line - we don't want this
01495         return 0;
01496     }
01497 
01498     // !PS-Adobe line is ok...
01499 
01500     // Scan first 20 lines for Corel 4.x's unique(ish) line
01501     // (If you have no prolog, then it won't be there)
01502     istrstream HeaderFile((char *) pFileHeader, HeaderSize);
01503     char Buffer[200];
01504     BOOL HaveCreatorString = FALSE;
01505 
01506     UINT32 Lines = 0;
01507     while ((Lines < 20) && !HeaderFile.eof())
01508     {
01509         HeaderFile.getline(Buffer, 200);
01510         Lines++;
01511 
01512         if (camStrncmp(Buffer, "%%BeginResource: procset wCorel4Dict", 36) == 0)
01513             // This must be Corel 4.0 EPS
01514             return 10;
01515 
01516         if ((camStrncmp(Buffer, "%%Creator:", 10) == 0) && (camStrclen(Buffer) <= 12))
01517         {
01518             // Blank Creator comment - this could be Corel 4.0 EPS
01519             if (IsUserName("Tim"))
01520                 TRACE( _T("Found blank creator field\n"));
01521 
01522             // Return 6 rather than 5 so we're just above the other EPS filters in terms
01523             // of compatibility, because a blank Creator comment is a reasonably good
01524             // sign thatthis file came from Corel 4.
01525             return 6;
01526         }
01527         
01528         if ((camStrncmp(Buffer, "%%Creator: CorelDRAW!", 21) == 0) && (camStrclen(Buffer) <= 23))
01529         {
01530             // yep, that's the one
01531             HaveCreatorString = TRUE;
01532         }
01533 
01534         if(camStrncmp(Buffer, "/wCorel5Dict", 12) == 0 && HaveCreatorString)
01535         {
01536             // it's a Corel5 file
01537             return 10;
01538         }
01539 
01540     }
01541 
01542     // Corel 4.0 doesn't put anything in the Creator comment field - return
01543     // 5 to indicate we're interested, but not sure.
01544     return 5;
01545 
01546 }
01547 
01548 /********************************************************************************************
01549 
01550 >   void Corel4EPSFilter::LookUpToken()
01551 
01552     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01553     Created:    25/02/94
01554     Purpose:    Compare the current token against the Corel keywords to see if it is
01555                 one of them.
01556     SeeAlso:    EPSFilter::DecodeToken
01557 
01558 ********************************************************************************************/
01559 
01560 void Corel4EPSFilter::LookUpToken()
01561 {
01562 //  // Not interested in comments
01563 //  if (Token == EPSC_Comment)
01564 //      return;
01565 
01566     if(Token == EPSC_Comment)
01567     {
01568         // is it one of the clipping things?
01569         if(camStrncmp(TokenBuf, "%SetClippingRegion", 17) == 0)
01570             Token = EPSC_q;
01571         else if(camStrncmp(TokenBuf, "%ClearClipping", 13) == 0)
01572             Token = EPSC_Q; 
01573 
01574         return;
01575     }
01576 
01577     // Check to see if it is a keyword - cycle through the array of keyword names and
01578     // compare against our token (could use a hash table?)
01579     INT32 i = 0;
01580     while (Corel4Commands[i].Cmd != EPSC_Invalid)
01581     {
01582         if (camStrcmp(TokenBuf, Corel4Commands[i].CmdStr) == 0)
01583         {
01584             // Found the token - set the token variable and return success
01585             Token = Corel4Commands[i].Cmd;
01586             return;
01587         }
01588         // Try next command
01589         i++;
01590     }
01591 
01592     // Did not find this token - try base class
01593     CorelEPSFilter::LookUpToken();
01594 }
01595 
01596 /********************************************************************************************
01597 
01598 >   BOOL Corel4EPSFilter::ProcessToken()
01599 
01600     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01601     Created:    25/02/94
01602     Returns:    TRUE if token understood and processed ok, FALSE if not.
01603     Purpose:    Processes EPS tokens that are not part of the standard Illustrator set.
01604                 i.e. this is the function that handles all the Corel EPS operators.
01605     Errors:     Syntax error in EPS, Out of memory.
01606     SeeAlso:    EPSFilter::ProcessToken
01607 
01608 ********************************************************************************************/
01609 
01610 BOOL Corel4EPSFilter::ProcessToken()
01611 {
01612     // Variables used to extract operands from the stack
01613     PColourCMYK Col;
01614     DocCoord    Coords[3];
01615     TintType    Tint = TINT_NONE;
01616     double      Padding, RotateX, RotateY;
01617 
01618     // Decode the command, and execute it...
01619     switch (Token)
01620     {
01621         case EPSC_cd4_0x:
01622             Tint = TINT_COREL;
01623         case EPSC_cd4_0k:
01624             // Get the grad fill parameters
01625             if (!Stack.Pop(&RotateY) || !Stack.Pop(&RotateX) ||
01626                 !Stack.Pop(&Padding) || !Stack.Pop(&GradFillInfo.FillType) ||
01627                 !Stack.Pop(&GradFillInfo.Angle) || !Stack.Discard(3))
01628                 goto EPSError;
01629 
01630             // Convert angle to sane value
01631 //          GradFillInfo.Angle = GradFillInfo.Angle;
01632 
01633             // Convert values from floating point to integer
01634             GradFillInfo.EdgePad = (INT32) (Padding * 100.0);
01635             GradFillInfo.RotateX = (INT32) (RotateX * 100.0);
01636             GradFillInfo.RotateY = (INT32) (RotateY * 100.0);
01637 
01638             if (Stack.GetType() != EPSTYPE_COMMAND)
01639             {
01640                 if (IsUserName("Tim"))
01641                     TRACE( _T("@x/@k: Expected ArrayEnd, found '%s'\n"), TokenBuf);
01642                 goto EPSError;
01643             }
01644             
01645             EPSCommand Cmd;
01646             Stack.PopCmd(&Cmd);
01647             if (Cmd != EPSC_ArrayEnd)
01648             {
01649                 if (IsUserName("Tim"))
01650                     TRACE( _T("@x/@k: Expected ArrayEnd, found '%s'\n"), GetEPSCommand(Cmd));
01651                 goto EPSError;
01652             }
01653 
01654             // Discard the steps parameter 
01655             if (!Stack.Discard())
01656                 goto EPSError;
01657 
01658             // Get the end colour.
01659             if (!Stack.PopColour(&Col, Tint))
01660                 // Invalid colour operands
01661                 goto EPSError;
01662             EndColour.SetCMYKValue(&Col);
01663 
01664             // Discard some strange parameter I don't yet understand
01665             if (!Stack.Discard())
01666                 goto EPSError;
01667 
01668             // Get the start colour.
01669             if (!Stack.PopColour(&Col, Tint))
01670                 // Invalid colour operands
01671                 goto EPSError;
01672             StartColour.SetCMYKValue(&Col);
01673 
01674             // Discard the array end symbol
01675             if (Stack.IsEmpty())
01676             {
01677                 // Run out of operands!
01678                 if (IsUserName("Tim"))
01679                     TRACE( _T("@x/@k: Run out of operands\n"));
01680                 goto EPSError;
01681             }
01682                 
01683             if (Stack.GetType() != EPSTYPE_COMMAND)
01684             {
01685                 if (IsUserName("Tim"))
01686                     TRACE( _T("@x/@k: Expected ArrayStart but found '%s'\n"), TokenBuf);
01687                 goto EPSError;
01688             }
01689             else
01690             {
01691                 EPSCommand Cmd = Stack.ReadCmd();
01692                 if (!Stack.PopCmd(&Cmd) || Cmd != EPSC_ArrayStart)
01693                 {
01694                     if (IsUserName("Tim"))
01695                         TRACE( _T("@x/@k: Expected ArrayStart, found '%s'\n"), GetEPSCommand(Cmd));
01696                     goto EPSError;
01697                 }
01698             }
01699 
01700             GradFill = TRUE;
01701 
01702             break;
01703             
01704         case EPSC_eoclip:
01705             // add clip thingy operator...
01706             EPSFlags.PathIsHidden = TRUE;
01707             Token = EPSC_W;
01708             return EPSFilter::ProcessToken();
01709             break;
01710 
01711         case EPSC_cd5_0gs:
01712             return Import_gsave();
01713             break;
01714 
01715         case EPSC_cd5_0gr:
01716             return Import_grestore();
01717             break;
01718 
01719         case EPSC_cd5_0np:
01720             // newpath... blank current if necessary
01721             if(pInkPath !=0)
01722             {
01723                 if(!pInkPath->ClearPath())
01724                     return FALSE;
01725             }
01726             break;
01727 
01728         default:
01729             return CorelEPSFilter::ProcessToken();
01730             break;
01731     }
01732 
01733 
01734     // No errors encountered while parsing this token and its operands.
01735     return TRUE;
01736     
01737     
01738     // Error handlers:
01739     
01740 EPSError:
01741     HandleEPSError();
01742     return FALSE;
01743 #if 0
01744 NoMemory:
01745     HandleNoMemory();
01746     return FALSE;
01747 #endif
01748 }
01749 
01750 
01751 /********************************************************************************************
01752 
01753 >   char *Corel4EPSFilter::GetEPSCommand(EPSCommand Cmd)
01754 
01755     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01756     Created:    28/02/94
01757     Inputs:     Cmd - the EPS token, e.g. EPSC_cd_c
01758     Returns:    Pointer to the string representation of the token, e.g. "@c"
01759     Purpose:    Given an EPS token, return the string representation of it; mainly for
01760                 debugging purposes.
01761 
01762 ********************************************************************************************/
01763 
01764 char *Corel4EPSFilter::GetEPSCommand(EPSCommand Cmd)
01765 {
01766     INT32 i = 0;
01767     while (Corel4Commands[i].Cmd != EPSC_Invalid)
01768     {
01769         if (Corel4Commands[i].Cmd == Cmd)
01770             return Corel4Commands[i].CmdStr;
01771 
01772         // Try next command
01773         i++;
01774     }
01775 
01776     // Couldn't find it - default to base class method
01777     return CorelEPSFilter::GetEPSCommand(Cmd);
01778 }
01779 
01780 

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