// $Id: epsstack.cpp 1660 2006-08-03 17:28:20Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // Implementation of a PostScript style stack for the EPS reader #include "camtypes.h" //#include "list.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "listitem.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "basestr.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "tim.h" //#include "epsfiltr.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "epsstack.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "epssitem.h" /******************************************************************************************** > void FIXEDPOINT::FromAscii(const TCHAR *FltPtString) Author: Tim_Browse (Xara Group Ltd) Created: 28/02/94 Inputs: FltPtString - string form of required number. Returns: TRUE if ok, FALSE if not (e.g. syntax error in string) Purpose: Decodes the ASCII string containing a floating point number and stores it as fixed point in this object. SeeAlso: FIXEDPOINT ********************************************************************************************/ void FIXEDPOINT::FromAscii(const TCHAR *Str) { // Initialise data member. Long = 0; // keep a check on the sign BOOL neg = (Str[0] == '-'); // Look for the decimal place INT32 i = 0; while ((Str[i] != 0) && (Str[i] != '.')) i++; if (Str[i] == '.') { // Found a decimal point - extract the integer and fractional parts and use them // to construct the fixed point number. TCHAR Tmp[20]; camStrcpy(Tmp, Str); Tmp[i] = 0; Long = 0; camSscanf(Tmp, _T("%d"), &Long); Long *= 1000; // Force fraction to be 3 digits at the most (as we only store with 3 digits accuracy) Tmp[i + 4] = 0; // Convert fraction to integer INT32 Frac = 0; camSscanf(&(Tmp[i+1]), _T("%d"), &Frac); // The fraction can be of the form .1, .10, or .100 - we must scale it correctly. INT32 FracLen = camStrlen(Tmp + i + 1); if (FracLen == 1) Frac *= 100; else if (FracLen == 2) Frac *= 10; // Fraction is now scaled correctly - add to integer part. if (neg) // Negative number, so subtract the fractional part Long -= Frac; else // Positive number, so add the fractional part Long += Frac; } else { // No decimal point found - just scale the integer part. Long = 0; camSscanf(Str, _T("%d"), &Long); Long *= 1000; } } CC_IMPLEMENT_MEMDUMP(EPSStack, CC_CLASS_MEMDUMP) /******************************************************************************************** > EPSStack::EPSStack(UINT32 StackLimit = 50) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Purpose: Constructor. Initialises scaling factor to be 1. ********************************************************************************************/ EPSStack::EPSStack() : List () { // Set scaling to unity. ScaleFactor = 1; // Set origin to default Origin.x = 0; Origin.y = 0; // By default, no additional transformation matrix is used. UseXformMatrix = FALSE; } /******************************************************************************************** > EPSStack::~EPSStack() Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Purpose: Destructor - deallocates all storage associated with the stack. ********************************************************************************************/ EPSStack::~EPSStack() { // Delete the contents of the list. DeleteAll (); } /******************************************************************************************** > BOOL EPSStack::Push(const INT32 Long) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Inputs: Long - the data to push onto the stack. Returns: TRUE if successful, FALSE if out of stack space. Purpose: Push a INT32 value onto the stack. ********************************************************************************************/ BOOL EPSStack::Push ( const INT32 Long ) { EPSStackItem *pItem = new EPSStackItem; // Ensure that the item has been created. if ( pItem == NULL) { // Clear the stack as the caller will now abort. DeleteAll (); // Tell caller about the error ERROR ( _R(IDT_EPS_STACKLIMIT), FALSE ); } // Initialise stack item. pItem->Init ( Long ); // Add it to the list. AddHead ( pItem ); return TRUE; } /******************************************************************************************** > BOOL EPSStack::Push(const FIXEDPOINT FixedPoint) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Inputs: FixedPoint - the data to push onto the stack. Outputs: - Returns: TRUE if successful, FALSE if out of stack space. Purpose: Push a fixed point value onto the stack. ********************************************************************************************/ BOOL EPSStack::Push ( const FIXEDPOINT FixedPoint ) { EPSStackItem *pItem = new EPSStackItem; // Ensure that the item has been created. if ( pItem == NULL) { // Clear the stack as the caller will now abort. DeleteAll (); // Tell caller about the error ERROR ( _R(IDT_EPS_STACKLIMIT), FALSE ); } // Initialise stack item. pItem->Init ( FixedPoint ); // Add it to the list. AddHead ( pItem ); return TRUE; } /******************************************************************************************** > BOOL EPSStack::Push(const double Double) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Inputs: Double - the data to push onto the stack. Outputs: - Returns: TRUE if successful, FALSE if out of stack space. Purpose: Push a double value onto the stack. ********************************************************************************************/ BOOL EPSStack::Push ( const double Double ) { EPSStackItem *pItem = new EPSStackItem; // Ensure that the item has been created. if ( pItem == NULL) { // Clear the stack as the caller will now abort. DeleteAll (); // Tell caller about the error ERROR ( _R(IDT_EPS_STACKLIMIT), FALSE ); } // Initialise stack item. pItem->Init ( Double ); // Add it to the list. AddHead ( pItem ); return TRUE; } /******************************************************************************************** > BOOL EPSStack::Push ( const TCHAR *pString, BOOL IsName = FALSE ) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Inputs: pString - pointer to the string data to push onto the stack. Returns: TRUE if successful, FALSE if out of memory or stack space. Purpose: Push a TCHAR* string item onto the stack. ********************************************************************************************/ BOOL EPSStack::Push ( const TCHAR *pString, BOOL IsName ) { EPSStackItem *pItem = new EPSStackItem; // Ensure that the item has been created. if ( pItem == NULL) { // Clear the stack as the caller will now abort. DeleteAll (); // Tell caller about the error ERROR ( _R(IDT_EPS_STACKLIMIT), FALSE ); } // Try to copy string TCHAR *NewStr = new TCHAR[camStrlen(pString) + 1]; ERRORIF(NewStr == NULL, _R(IDT_EPS_NOMEMORY), FALSE); camStrcpy(NewStr, pString); // Initialise stack item. pItem->Init ( NewStr ); // Add it to the list. AddHead ( pItem ); return TRUE; } /******************************************************************************************** > BOOL EPSStack::Push ( const EPSCommand Cmd ) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Inputs: Cmd - the EPS command to push onto the stack. Returns: TRUE if successful, FALSE if out of stack space. Purpose: Push an EPS command onto the stack. ********************************************************************************************/ BOOL EPSStack::Push ( const EPSCommand Cmd ) { EPSStackItem *pItem = new EPSStackItem; // Ensure that the item has been created. if ( pItem == NULL) { // Clear the stack as the caller will now abort. DeleteAll (); // Tell caller about the error ERROR ( _R(IDT_EPS_STACKLIMIT), FALSE ); } // Initialise stack item. pItem->Init ( Cmd ); // Add it to the list. AddHead ( pItem ); return TRUE; } /******************************************************************************************** > BOOL EPSStack::Pop(INT32 *pLong) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Outputs: pLong - the value popped from the stack. Returns: TRUE if there is a numeric value on the top of the stack; FALSE if not. Purpose: Pop a INT32 value from the top of the stack. If there is a floating point value on the stack, it is converted before being returned to the caller. ********************************************************************************************/ BOOL EPSStack::Pop( INT32 *pLong ) { // Get pointer to the stack item. EPSStackItem *pItem = static_cast ( RemoveHead () ); // Return error if no items on stack. if ( pItem == NULL ) return FALSE; // Check that the item is of the correct type switch ( pItem->Type ) { case EPSTYPE_INT32: // Correct type - remove item from stack and return to caller. *pLong = static_cast ( pItem->Data.Long ); break; case EPSTYPE_FIXEDPOINT: // Perform implicit type conversion a la PostScript *pLong = static_cast ( pItem->Data.FixedPoint.Long / FixedPointScale ); break; case EPSTYPE_DOUBLE: // Perform implicit type conversion a la PostScript *pLong = static_cast ( pItem->Data.Double ); break; default: // Type mismatch - return error condition return FALSE; } // Delete item fron stack and return delete pItem; return TRUE; } /******************************************************************************************** > BOOL EPSStack::Pop(UINT32 *pUint) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Outputs: pUint - the value popped from the stack. Returns: TRUE if there is a numeric value on the top of the stack; FALSE if not. Purpose: Pop a UINT32 value from the top of the stack. If there is a floating point value on the stack, it is converted before being returned to the caller. ********************************************************************************************/ BOOL EPSStack::Pop ( UINT32 *pUint ) { // Get pointer to the stack item. EPSStackItem *pItem = static_cast ( RemoveHead () ); // Return error if no items on stack. if ( pItem == NULL ) return FALSE; // Check that the item is of the correct type switch ( pItem->Type ) { case EPSTYPE_INT32: // Correct type - remove item from stack and return to caller. *pUint = static_cast ( pItem->Data.Long ); break; case EPSTYPE_FIXEDPOINT: // Perform implicit type conversion a la PostScript *pUint = static_cast ( pItem->Data.FixedPoint.Long / FixedPointScale ); break; case EPSTYPE_DOUBLE: // Perform implicit type conversion a la PostScript *pUint = static_cast ( pItem->Data.Double ); break; default: // Type mismatch - return error condition return FALSE; } // Delete item fron stack and return delete pItem; return TRUE; } /******************************************************************************************** > BOOL EPSStack::Pop(FIXEDPOINT *pFixedPoint) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Outputs: pFixedPoint - the value popped from the stack. Returns: TRUE if there is a numeric value on the top of the stack; FALSE if not. Purpose: Pop a double value from the top of the stack. If there is an integer value on top of the stack, it is converted to a floating point value before being returned to the caller. ********************************************************************************************/ BOOL EPSStack::Pop ( FIXEDPOINT *pFixedPoint ) { // Get pointer to the stack item. EPSStackItem *pItem = static_cast ( RemoveHead () ); // Return error if no items on stack. if ( pItem == NULL ) return FALSE; // Check that the item is of the correct type switch (pItem->Type) { case EPSTYPE_INT32: // Correct type - remove item from stack and return to caller. pFixedPoint->Long = ( pItem->Data.Long * FixedPointScale ); break; case EPSTYPE_FIXEDPOINT: // Perform implicit type conversion a la PostScript *pFixedPoint = pItem->Data.FixedPoint; break; case EPSTYPE_DOUBLE: // Perform implicit type conversion a la PostScript pFixedPoint->Long = static_cast ( pItem->Data.Double ); break; default: // Type mismatch - return error condition return FALSE; } // Delete item fron stack and return delete pItem; return TRUE; } /******************************************************************************************** > BOOL EPSStack::Pop(double *pDouble) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Outputs: pDouble - the value popped from the stack. Returns: TRUE if there is a numeric value on the top of the stack; FALSE if not. Purpose: Pop a double value from the top of the stack. If there is an integer value on top of the stack, it is converted to a floating point value before being returned to the caller. ********************************************************************************************/ BOOL EPSStack::Pop ( double *pDouble ) { // Get pointer to the stack item. EPSStackItem *pItem = static_cast ( RemoveHead () ); // Return error if no items on stack. if ( pItem == NULL ) return FALSE; // Check that the item is of the correct type switch ( pItem->Type ) { case EPSTYPE_INT32: // Correct type - remove item from stack and return to caller. *pDouble = static_cast ( pItem->Data.Long ); break; case EPSTYPE_FIXEDPOINT: // Perform implicit type conversion a la PostScript *pDouble = static_cast ( pItem->Data.FixedPoint.Long ) / FixedPointScale; break; case EPSTYPE_DOUBLE: // Perform implicit type conversion a la PostScript *pDouble = pItem->Data.Double; break; default: // Type mismatch - return error condition return FALSE; } // Delete item fron stack and return delete pItem; return TRUE; } /******************************************************************************************** > BOOL EPSStack::Pop(TCHAR* pString) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Outputs: pString - the buffer to put the string value into. Returns: TRUE if there is a string value on the top of the stack; FALSE if not. Purpose: Pop a TCHAR* string value from the top of the stack. ********************************************************************************************/ BOOL EPSStack::Pop ( TCHAR* pString ) { // Get pointer to the stack item. EPSStackItem *pItem = static_cast ( RemoveHead () ); // Return error if no items on stack. if ( pItem == NULL ) return FALSE; // Check that the item is of the correct type if ( pItem->Type == EPSTYPE_STRING ) { // Correct type - remove item from stack and return to caller. camStrcpy ( pString, pItem->Data.pString ); delete pItem; return TRUE; } else { // Tidy up the memory. delete pItem; // Type mismatch - return error condition return FALSE; } } /******************************************************************************************** > BOOL EPSStack::Pop(StringBase* pString) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Outputs: pString - the String object to put the string value into. Returns: TRUE if there is a string value on the top of the stack; FALSE if not. Purpose: Pop a string value from the top of the stack. ********************************************************************************************/ BOOL EPSStack::Pop(StringBase* pString) { // Get pointer to the stack item. EPSStackItem *pItem = static_cast ( RemoveHead () ); // Return error if no items on stack. if ( pItem == NULL ) return FALSE; // Check that the item is of the correct type if ( pItem->Type == EPSTYPE_STRING ) { // Correct type - remove item from stack and return to caller. *pString = String_256(pItem->Data.pString); delete pItem; return TRUE; } else { // Tidy up the memory. delete pItem; // Type mismatch - return error condition return FALSE; } } /******************************************************************************************** > BOOL EPSStack::PopCmd(EPSCommand *pCmd) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Outputs: pCmd - the command on top of the stack. Returns: TRUE if there is an EPS command on the top of the stack; FALSE if not. Purpose: Pop an EPS command from the top of the stack. ********************************************************************************************/ BOOL EPSStack::PopCmd(EPSCommand *pCmd) { // Get pointer to the stack item. EPSStackItem *pItem = static_cast ( RemoveHead () ); // Return error if no items on stack. if ( pItem == NULL ) return FALSE; // Check that the item is of the correct type if (pItem->Type == EPSTYPE_COMMAND) { // Correct type - remove item from stack and return to caller. *pCmd = pItem->Data.Cmd; delete pItem; return TRUE; } else { // Type mismatch - return error condition delete pItem; return FALSE; } } /******************************************************************************************** > BOOL EPSStack::PopCoord(INT32 *pLong) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Outputs: pLong - the (scaled) value popped from the stack. Returns: TRUE if there is a numeric value on the top of the stack; FALSE if not. Purpose: Pop a INT32 value from the top of the stack. If there is a fixed point value on the stack, it is converted before being returned to the caller. The value is scaled before being returned, so that it is easy to cope with EPS files that use brainless coordinate schemes (i.e. all of them). Scaling factor is initially 1, but can be changed via SetCoordScaleFactor(). SeeAlso: EPSStack::SetCoordScaleFactor ********************************************************************************************/ BOOL EPSStack::PopCoord ( INT32 *pLong ) { // Get pointer to the stack item. EPSStackItem *pItem = static_cast ( RemoveHead () ); // Return error if no items on stack. if ( pItem == NULL ) return FALSE; // Check that the item is of the correct type switch ( pItem->Type ) { case EPSTYPE_INT32: // Correct type - remove item from stack and return to caller. *pLong = ScaleFactor * (pItem->Data.Long); break; case EPSTYPE_FIXEDPOINT: // Perform implicit type conversion a la PostScript // Fixed point values are stored as value * 1000, so if the ScaleFactor is // actually 1000, don't bother to scale - just return the value. if (ScaleFactor == FixedPointScale) *pLong = static_cast ( pItem->Data.FixedPoint.Long ); else { // Perform the necessary scaling *pLong = static_cast ( pItem->Data.FixedPoint.Long * ( static_cast ( ScaleFactor ) ) ); *pLong /= FixedPointScale; } break; case EPSTYPE_DOUBLE: // Perform implicit type conversion a la PostScript *pLong = static_cast ( static_cast ( ScaleFactor ) * pItem->Data.Double ); break; default: // Type mismatch - return error condition return FALSE; } // Delete item fron stack and return delete pItem; return TRUE; } /******************************************************************************************** > BOOL EPSStack::PopCoordPair(DocCoord *pCoord) Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Outputs: pCoord - the (scaled and translated) coordinate pair popped from the stack. Returns: TRUE if there is a coord pair on the top of the stack; FALSE if not. Purpose: Pop two INT32 values from the top of the stack. If they are in floating point format, they are converted before being returned to the caller. The coords are scaled and translated before being returned, so that it is easy to cope with EPS files that use brainless coordinate schemes (ArtWorks EPS are you listening?). Scaling factor is initially 1, but can be changed via SetCoordScaleFactor(). Origin is initially (0,0), but can be changed via SetCoordOrigin(). SeeAlso: EPSStack::SetCoordScaleFactor; EPSStack::SetCoordOrigin ********************************************************************************************/ BOOL EPSStack::PopCoordPair(DocCoord *pCoord) { if (PopCoord(&(pCoord->y)) && PopCoord(&(pCoord->x))) { // Use the transform matrix if necessary. if (UseXformMatrix) XformMatrix.transform((Coord *) pCoord, 1); // Translate coord using given origin and return success. pCoord->x += Origin.x; pCoord->y += Origin.y; return TRUE; } else return FALSE; } /******************************************************************************************** > BOOL EPSStack::PopColour(PColourCMYK *Col, TintType Tint = TINT_NONE, FIXEDPOINT *pTintVal = NULL, String_64 *pName = NULL) Author: Tim_Browse (Xara Group Ltd) Created: 18/10/93 Outputs: Col - the CMYK values popped from the stack and converted to 0-255 range. TintType - indicates what kind of tint is on the stack: TINT_NONE - no tint is on the stack TINT_ILLUSTRATOR - An Illustrator type tint is on the stack, i.e. a value between 0 and 1, with 0 being 100% and 1 being 0%. TINT_COREL - An Corel Draw type tint is on the stack, i.e. a value between 0 and 1, with 1 being 100% and 0 being 0%. TintVal - the value of the tint operand. pName - the textual name of this colour. If there is a tint, then the CMYK values are followed by a colour name and a tint value (0.0 to 1.0). The colour name is discarded, and the colour is adjusted according to the tint value found. Returns: TRUE if valid colour parameters were found on the stack; FALSE if not enough parameters, or if there are not enough, or if they are outside the 0-1 range. Purpose: Extract CYMK values from an ArtWorks EPS format and convert to Camelot range. AWEPS colour values are in the range 0 to 1; this function converts them to the 0 to 255 range. See Also: EPSStack::PopColourRGB ********************************************************************************************/ BOOL EPSStack::PopColour(PColourCMYK *Col, TintType Tint, FIXEDPOINT *pTintVal, String_64 *pName) { double Cyan, Magenta, Yellow, Key; FIXEDPOINT TintValue; TintValue=0; // Warning suppression if (Tint != TINT_NONE) { // Get the tint. if (!Pop(&TintValue)) return FALSE; // Does the caller want the name of the colour? if (pName == NULL) { // Name is not wanted - discard it if (!Discard()) return FALSE; } else { // Name is wanted - get it from the stack if (!Pop(pName)) return FALSE; } ENSURE((TintValue >= 0) && (TintValue <= 1000), "Bad tint"); // Convert Tint to sensible value, if required if (Tint == TINT_ILLUSTRATOR) TintValue = (1 * FixedPointScale) - (INT32) TintValue; if (pTintVal != NULL) *pTintVal = TintValue; } if (Pop(&Key) && Pop(&Yellow) && Pop(&Magenta) && Pop(&Cyan)) { if ((Cyan < 0.0) || (Cyan > 1.0) || (Magenta < 0.0) || (Magenta > 1.0) || (Yellow < 0.0) || (Yellow > 1.0) || (Key < 0.0) || (Key > 1.0)) // Invalid colour value return FALSE; // Got the values ok - translate from 0->1 range to sensible range. // NB. Important that we round up here, because otherwise 8 bit values will // sometimes fail to match on boundary conditions. Col->Cyan = (INT32) ((Cyan * 255.0) + 0.5); Col->Magenta = (INT32) ((Magenta * 255.0) + 0.5); Col->Yellow = (INT32) ((Yellow * 255.0) + 0.5); Col->Key = (INT32) ((Key * 255.0) + 0.5); if (Tint != TINT_NONE) { // Tint the colour Col->Cyan = (Col->Cyan * TintValue) / FixedPointScale; Col->Magenta = (Col->Magenta * TintValue) / FixedPointScale; Col->Yellow = (Col->Yellow * TintValue) / FixedPointScale; Col->Key = (Col->Key * TintValue) / FixedPointScale; } return TRUE; } else return FALSE; } /******************************************************************************************** > BOOL EPSStack::PopColourRGB (INT32 * red, INT32 * green, INT32 * blue, TintType Tint = TINT_NONE, FIXEDPOINT *pTintVal = NULL, String_64 *pName = NULL) Author: Chris_Gallimore (Xara Group Ltd) Created: 12/12/00 Outputs: red, green, blue - the RGB values popped from the stack and converted to 0-255 range. TintType - indicates what kind of tint is on the stack: TINT_NONE - no tint is on the stack TINT_ILLUSTRATOR - An Illustrator type tint is on the stack, i.e. a value between 0 and 1, with 0 being 100% and 1 being 0%. TINT_COREL - An Corel Draw type tint is on the stack, i.e. a value between 0 and 1, with 1 being 100% and 0 being 0%. TintVal - the value of the tint operand. pName - the textual name of this colour. NOTE: The tint is currently not supported for RGB colours, although the syntax has been kept to keep it consistent with the CMYK/Greyscale versions, as well to enable expansion of this function. Returns: TRUE if valid colour parameters were found on the stack; FALSE if not enough parameters, or if there are not enough, or if they are outside the 0-1 range. Purpose: Extract RGB values from a generic EPS format and convert to Camelot range. EPS colour values are in the range 0 to 1; this function converts them to the 0 to 255 range. See Also: EPSStack::PopColour ********************************************************************************************/ BOOL EPSStack::PopColourRGB (INT32 * red, INT32 * green, INT32 * blue, TintType Tint, FIXEDPOINT *pTintVal, String_64 *pName) { double tempRed, tempGreen, tempBlue; FIXEDPOINT TintValue; if (Tint != TINT_NONE) { // Get the tint. if (!Pop(&TintValue)) return FALSE; // Does the caller want the name of the colour? if (pName == NULL) { // Name is not wanted - discard it if (!Discard()) return FALSE; } else { // Name is wanted - get it from the stack if (!Pop(pName)) return FALSE; } ENSURE((TintValue >= 0) && (TintValue <= 1000), "Bad tint"); // Convert Tint to sensible value, if required if (Tint == TINT_ILLUSTRATOR) TintValue = (1 * FixedPointScale) - (INT32) TintValue; if (pTintVal != NULL) *pTintVal = TintValue; } if (Pop(&tempBlue) && Pop(&tempGreen) && Pop(&tempRed)) { if ((tempRed < 0.0) || (tempRed > 1.0) || (tempBlue < 0.0) || (tempBlue > 1.0) || (tempGreen < 0.0) || (tempGreen > 1.0)) // Invalid colour value return FALSE; // Got the values ok - translate from 0->1 range to sensible range. // NB. Important that we round up here, because otherwise 8 bit values will // sometimes fail to match on boundary conditions. *red = (INT32) ((tempRed * 255.0) + 0.5); *green = (INT32) ((tempGreen * 255.0) + 0.5); *blue = (INT32) ((tempBlue * 255.0) + 0.5); if (Tint != TINT_NONE) { // Tint the colour - Not currently done for RGB colours } return TRUE; } else return FALSE; } /******************************************************************************************** > BOOL EPSStack::PopGrayScale(PColourCMYK *Col) Author: Tim_Browse (Xara Group Ltd) Created: 28/02/94 Outputs: Col - the CMYK version of the grayscale popped from the stack and converted to 0-255 range. Returns: TRUE if a valid grayscale parameter was found on the stack; FALSE if not. Purpose: Extract grayscale value from an EPS format file and convert to Camelot range. SeeAlso: PopColour ********************************************************************************************/ BOOL EPSStack::PopGrayScale(PColourCMYK *Col) { double Gray=0.0; if (Pop(&Gray)) { if ((Gray < 0.0) || (Gray > 1.0)) // invalid gray scale value return FALSE; // Got the grayscale ok - translate from 0->1 range to sensible range. PColourValue GrayVal = 255 - (static_cast (Gray * 255)); Col->Cyan = 0; Col->Magenta = 0; Col->Yellow = 0; Col->Key = static_cast ( GrayVal ); return TRUE; } else return FALSE; } /******************************************************************************************** > BOOL EPSStack::Pop(Matrix *pMatrix, BOOL UseBrackets) Author: Tim_Browse (Xara Group Ltd) Created: 2/2/95 Inputs: pMatrix - the matrix to hold the popped values. UseBrackets - TRUE if the matrix is bracketed by []; FALSE if just the numbers are in the file. Returns: TRUE if the matrix was decode ok; FALSE otherwise Purpose: Pop a matrix object from the EPS stack. Errors: Not enough parameters/incorrect parameters. ********************************************************************************************/ BOOL EPSStack::Pop(Matrix *pMatrix, BOOL UseBrackets) { if (UseBrackets) { EPSCommand Cmd=EPSC_Invalid; PopCmd(&Cmd); if (Cmd != EPSC_ArrayEnd) return FALSE; } // Extract the six array values from the stack. double M[6]; INT32 i = 5; for (i = 5; i >= 0; i--) { if (!Pop(&M[i])) return FALSE; } if (UseBrackets) { EPSCommand Cmd=EPSC_Invalid; PopCmd(&Cmd); if (Cmd != EPSC_ArrayStart) return FALSE; } // Convert the abcd values into FIXED16s, cos that's what we use. FIXED16 F16[4]; for (i = 0; i < 4; i++) { F16[i] = FIXED16(M[i]); } // Convert the Tx and Ty to MILLIPOINTS, cos that's what we use. INT32 L1 = (INT32) (M[4] * 1000.0); INT32 L2 = (INT32) (M[5] * 1000.0); // Construct the matrix in the variable supplied by the caller. *pMatrix = Matrix(F16[0], F16[1], F16[2], F16[3], L1, L2); // Success return TRUE; } /******************************************************************************************** > void EPSStack::SetCoordScaleFactor(INT32 NewScaleFactor) Author: Tim_Browse (Xara Group Ltd) Created: 15/10/93 Inputs: NewScaleFactor - the new factor to use when scaling coordinates. Purpose: Set the scale factor used by PopCoord(). Scaling factor is initially 1. SeeAlso: EPSStack::PopCoord() ********************************************************************************************/ void EPSStack::SetCoordScaleFactor(INT32 NewScaleFactor) { ScaleFactor = NewScaleFactor; } /******************************************************************************************** > void EPSStack::SetCoordOrigin(DocCoord NewOrigin) Author: Tim_Browse (Xara Group Ltd) Created: 15/10/93 Inputs: NewOrigin - the new origin to use when translating coordinates. Purpose: Set the translation values used by PopCoord(). Initially (0,0). SeeAlso: EPSStack::PopCoord() ********************************************************************************************/ void EPSStack::SetCoordOrigin(DocCoord NewOrigin) { Origin = NewOrigin; } /******************************************************************************************** > void EPSStack::TranslateCoordOrigin(MILLIPOINT dx, MILLIPOINT dy) Author: Tim_Browse (Xara Group Ltd) Created: 08/04/94 Inputs: dx, dy - the translation values. Purpose: Translate the current origin for the EPS file by the given amounts. This is used when the %%BoundingBox comment is encountered, so that the image appears in a sensible place. SeeAlso: EPSStack::SetCoordOrigin ********************************************************************************************/ void EPSStack::TranslateCoordOrigin(MILLIPOINT dx, MILLIPOINT dy) { Origin.x += dx; Origin.y += dy; } /******************************************************************************************** > void EPSStack::SetXformMatrix(Matrix& NewMatrix) Author: Tim_Browse (Xara Group Ltd) Created: 10/08/94 Inputs: NewMatrix - the matrix to use from now on. Purpose: Sets up an additional transformation matrix to be used when decoding document coordinates (via EPSStack::PopCoordPair). When a transform matrix is active, all coords returned from PopCoordPair will have been transformed by the matrix after first having had the usual origin translation performed. The transformation matrix can be disabled by called SetNoXFormMatrix(). Errors: - SeeAlso: EPSStack::PopCoordPair; EPSStack::SetNoXFormMatrix ********************************************************************************************/ void EPSStack::SetXformMatrix(Matrix& NewMatrix) { // Install the new matrix XformMatrix = NewMatrix; UseXformMatrix = TRUE; } /******************************************************************************************** > void EPSStack::SetNoXFormMatrix() Author: Tim_Browse (Xara Group Ltd) Created: 10/08/94 Purpose: Disable the transformation matrix used by EPSStack::PopCoordPair(). See SetXFormMatrix() for details. SeeAlso: EPSStack::PopCoordPair; EPSStack::SetXFormMatrix ********************************************************************************************/ void EPSStack::SetNoXformMatrix() { UseXformMatrix = FALSE; } /******************************************************************************************** > BOOL EPSStack::Discard(UINT32 NumToDiscard = 1, BOOL EvenCommands = FALSE) Author: Tim_Browse (Xara Group Ltd) Created: 14/10/93 Inputs: NumToDiscard - the number of items to remove from the top of the stack. Returns: TRUE if there were sufficient items on the stack to satisfy request, FALSE if not. Purpose: Discard a number of items from the stack, irrespective of their type. NB. The exception is that you cannot discard a command, only operands (e.g. strings, numbers or names) unless EvenCommands == TRUE. SeeAlso: EPSStack::Pop ********************************************************************************************/ BOOL EPSStack::Discard(UINT32 NumToDiscard, BOOL EvenCommands) { // Check we can discard this many items if ( GetCount () < NumToDiscard ) return FALSE; while (NumToDiscard > 0) { EPSStackItem *pItem = static_cast ( GetHead () ); // Catch NULL pointers. if ( pItem == NULL ) { // Cannot discard any more list items. break; } if((pItem->Type == EPSTYPE_COMMAND) && (EvenCommands == FALSE)) { // Cannot discard a command return FALSE; } // Clean up any storage for this item RemoveHead (); delete pItem; // Move to next item NumToDiscard--; } return TRUE; } /******************************************************************************************** > BOOL EPSStack::PopArray(INT32 *Array, INT32* Elements) Author: Will_Cowling (Xara Group Ltd) Created: 15/4/95 Returns: TRUE if the array was popped ok, FALSE if an error occured. Purpose: Pop a PostScript array object from the stack. Errors: No syntactically correct array on the stack. SeeAlso: EPSStack::Discard ********************************************************************************************/ BOOL EPSStack::PopArray(INT32 *Array, INT32* Elements) { if (Array == NULL || Elements == NULL) return FALSE; if (GetType() != EPSTYPE_COMMAND) { TRACEUSER( "Will", _T("EPSStack::PopArray: Expected ArrayEnd\n")); return FALSE; } // First this we find should be the 'Array End' command (']') EPSCommand Cmd=EPSC_Invalid; PopCmd(&Cmd); if (Cmd != EPSC_ArrayEnd) { TRACEUSER( "Will", _T("EPSStack::PopArray: Expected ArrayEnd\n")); return FALSE; } INT32 NumElements = 0; // The array element will be popped off the stack backwards, // so we need to make a tempory array, so we can swap them, // around at the end. INT32* TempArray = new INT32[*Elements]; if (TempArray == NULL) return FALSE; // Read the rest of the array for(;;) { if (IsEmpty()) { // Run out of operands! TRACEUSER( "Will", _T("EPSStack::PopArray: Run out of operands\n")); delete TempArray; return FALSE; } if (GetType() != EPSTYPE_COMMAND) { // Pop the array member double Double=0.0; if (!Pop(&Double)) { delete TempArray; return FALSE; } if (NumElements < *Elements) { TempArray[NumElements] = (INT32) (Double * EPSScaleFactor); NumElements++; } } else { EPSCommand Cmd = ReadCmd(); if (!PopCmd(&Cmd) || Cmd != EPSC_ArrayStart) { TRACEUSER( "Will", _T("EPSStack::PopArray: Expected ArrayStart\n")); delete TempArray; return FALSE; } else break; // exit loop - end of array found } } *Elements = NumElements; // Actual number of elements read // Now swap the elements so they are the correct way around. if (NumElements > 0) { INT32 LastEl = NumElements - 1; for (INT32 el = 0; el < NumElements; el++) { Array[el] = TempArray[LastEl - el]; } } delete TempArray; // Array popped ok return TRUE; } /******************************************************************************************** > BOOL EPSStack::DiscardArray() Author: Tim_Browse (Xara Group Ltd) Created: 07/03/94 Returns: TRUE if the array was discarded ok, FALSE if an error occured. Purpose: Discard a PostScript array object from the stack. This is normally used when an EPS filter is not complete, but the file is still parsed correctly by discarding information that is npt yet needed/processed. Errors: No syntactically correct array on the stack. SeeAlso: EPSStack::Discard ********************************************************************************************/ BOOL EPSStack::DiscardArray() { if (GetType() != EPSTYPE_COMMAND) { TRACEUSER( "Tim", _T("EPSStack::DiscardArray: Expected ArrayEnd\n")); return FALSE; } EPSCommand Cmd=EPSC_Invalid; PopCmd(&Cmd); if (Cmd != EPSC_ArrayEnd) { TRACEUSER( "Tim", _T("EPSStack::DiscardArray: Expected ArrayEnd\n")); return FALSE; } // Discard the rest of the array for(;;) { if (IsEmpty()) { // Run out of operands! TRACEUSER( "Tim", _T("EPSStack::DiscardArray: Run out of operands\n")); return FALSE; } if (GetType() != EPSTYPE_COMMAND) // Discard array member Discard(); else { EPSCommand Cmd = ReadCmd(); if (!PopCmd(&Cmd) || Cmd != EPSC_ArrayStart) { TRACEUSER( "Tim", _T("EPSStack::DiscardArray: Expected ArrayStart\n")); return FALSE; } else break; // exit loop - end of array found } } // Array discarded ok return TRUE; } /******************************************************************************************** > EPSType EPSStack::GetType() Author: Tim_Browse (Xara Group Ltd) Created: 14/10/93 Returns: The type of the object on the top of the stack (if the stack is empty, the value EPSTYPE_NONE is returned). Purpose: Find out what type of object is on the top of the stack. The item is not removed from the stack by this operation. ********************************************************************************************/ EPSType EPSStack::GetType() { EPSStackItem *pItem = static_cast ( GetHead () ); if ( pItem == NULL ) return EPSTYPE_NONE; else return pItem->Type; } /******************************************************************************************** > EPSCommand EPSStack::ReadCmd() Author: Tim_Browse (Xara Group Ltd) Created: 14/10/93 Returns: The EPS command on the top of the stack, or EPSC_Invalid if there is no EPS command at the top of the stack. Purpose: Find out what command is on top of the stack. The command is not removed from the stack. Numbers, strings, names, etc. do not count as being commands. SeeAlso: EPSStack::GetType ********************************************************************************************/ EPSCommand EPSStack::ReadCmd() { EPSStackItem *pItem = static_cast ( GetHead () ); if ( ( pItem == NULL ) || ( pItem->Type != EPSTYPE_COMMAND ) ) return EPSC_Invalid; else return pItem->Data.Cmd; } /******************************************************************************************** > BOOL EPSStack::IsEmpty() Author: Tim_Browse (Xara Group Ltd) Created: 13/10/93 Returns: Returns TRUE if the stack is empty, FALSE if it is not. Purpose: Test to see if the stack is empty. SeeAlso: EPSStack::GetCount(); ********************************************************************************************/ BOOL EPSStack::IsEmpty() { return ( GetCount () == 0 ); } /******************************************************************************************** > void EPSStack::Dump(EPSFilter *pFilter) Author: Tim_Browse (Xara Group Ltd) Created: 15/10/93 Inputs: Pointer to the filter that this stack is owned by. Purpose: Dump out the contents of the stack to the debug window. The stack is unchanged. ********************************************************************************************/ void EPSStack::Dump(EPSFilter *pFilter) { #if defined(_DEBUG) if (!Error::IsUserName("Tim") && !Error::IsUserName("Ben")) return; TRACE( _T("EPS STACK DUMP START\n\n")); for ( DWORD i = 0; i < GetCount (); i++ ) { EPSStackItem *pItem = static_cast ( FindItem ( i ) ); switch (pItem->Type) { case EPSTYPE_COMMAND: TRACE( _T("Command: %s\n"), pFilter->GetEPSCommand(pItem->Data.Cmd)); break; case EPSTYPE_FIXEDPOINT: TRACE( _T("Fixed point: %f\n"), ((double) pItem->Data.FixedPoint.Long) / FixedPointScale); break; case EPSTYPE_INT32: TRACE( _T("Long: %ld\n"), pItem->Data.Long); break; case EPSTYPE_STRING: TRACE( _T("String: '%s'\n"), pItem->Data.pString); break; case EPSTYPE_NAME: TRACE( _T("Name: '%s'\n"), pItem->Data.pString); break; case EPSTYPE_DOUBLE: TRACE( _T("Double: %f\n"), pItem->Data.Double); break; case EPSTYPE_EMPTY: case EPSTYPE_NONE: TRACE( _T("Empty/None\n")); break; default: TRACE( _T("Unknown type\n")); break; } } TRACE( _T("\nEPS STACK DUMP END\n")); #endif }