|
|
/**************************************************************************\
* * Copyright (c) 1999 Microsoft Corporation * * Module Name: * * MetaFile.hpp * * Abstract: * * Metafile definitions * * Created: * * 4/14/1999 DCurtis * \**************************************************************************/
#ifndef _METAFILE_HPP
#define _METAFILE_HPP
#define EMFPLUS_SIGNATURE 0x2B464D45
#define EMFPLUS_DUAL 0x4C415544 // EMF+ with down-level GDI records
#define EMFPLUS_ONLY 0x594C4E4F // EMF+ only -- no down-level
/* The following are defined in Object.hpp:
#define EMFPLUS_VERSION
#define EMFPLUS_MAJORVERSION_BITS
#define EMFPLUS_MINORVERSION_BITS
*/
// Constants for MFCOMMENT Escape
#define MFCOMMENT_IDENTIFIER 0x43464D57
#define MFCOMMENT_ENHANCED_METAFILE 1
// When serializing an object, we need to leave room for the record header
// and possibly a dependent object id. Also, an image can be part of a
// texture brush, so leave room for the texture brush data.
// Subtract 480 for good measure.
#define GDIP_MAX_OBJECT_SIZE (GDIP_MAX_COMMENT_SIZE - 480)
#define GDIP_METAFILE_BUFFERSIZE 2048
#define GDIP_MAX_OBJECTS 64 // max num cached objects
#define GDIP_SAVE_STACK_SIZE 16 // for save/restores
#define GDIP_LIST_NIL 0xFFFFFFFF
#define GDIP_OBJECTID_NONE GDIP_LIST_NIL // no object present
#define GDIP_REAL_SIZE 4
#define GDIP_RECTF_SIZE (4 * GDIP_REAL_SIZE)
#define GDIP_POINTF_SIZE (2 * GDIP_REAL_SIZE)
#define GDIP_MATRIX_SIZE (6 * GDIP_REAL_SIZE)
// Set in Flags in EMF+ record header
// Flags Used in Object Records
#define GDIP_EPRFLAGS_CONTINUEOBJECT 0x8000 // more data for previous object
#define GDIP_EPRFLAGS_OBJECTTYPE 0x7F00
// Used in Object records and "Fill..." and "Draw..." and many other records
#define GDIP_EPRFLAGS_METAOBJECTID 0x00FF
#define GDIP_BACKUP_OBJECTID 255 // the object is a "backup object"
// Used in "Fill..." records
#define GDIP_EPRFLAGS_SOLIDCOLOR 0x8000
// Used in "Fill..." and "Draw..." records
#define GDIP_EPRFLAGS_COMPRESSED 0x4000 // point data is compressed
// Used in some "Fill..." records
#define GDIP_EPRFLAGS_WINDINGFILL 0x2000
// Used in DrawLines record
#define GDIP_EPRFLAGS_CLOSED 0x2000
// Used in matrix operations
#define GDIP_EPRFLAGS_APPEND 0x2000
// Used in SetAntiAliasMode record
#define GDIP_EPRFLAGS_ANTIALIAS 0x0001
// Used in SetTextRenderingHint record
#define GDIP_EPRFLAGS_TEXTRENDERINGHINT 0x00FF
// Used in SetTextContrast record (1000~2200)
#define GDIP_EPRFLAGS_CONTRAST 0x0FFF
// Used in EndOfFile record
#define GDIP_EPRFLAGS_DIDGETDC 0x2000
// Used in BeginContainer and SetPageTransform records
#define GDIP_EPRFLAGS_PAGEUNIT 0x00FF // can't be mixed with Ids
// Used in SetInterpolationMode record
#define GDIP_EPRFLAGS_INTERPOLATIONMODE 0x00FF
// Used in SetPixelOffsetMode record
#define GDIP_EPRFLAGS_PIXELOFFSETMODE 0x00FF
// Used in SetCompositingMode record
#define GDIP_EPRFLAGS_COMPOSITINGMODE 0x00FF
// Used in SetCompositingQuality record
#define GDIP_EPRFLAGS_COMPOSITINGQUALITY 0x00FF
// Used in SetClipRect, SetClipPath, and SetClipRegion records
#define GDIP_EPRFLAGS_COMBINEMODE 0x0F00
// Used in SetClipPath record
#define GDIP_EPRFLAGS_ISDEVICEPATH 0x2000
// Used in Header record
#define GDIP_EPRFLAGS_EMFPLUSDUAL 0x0001
inline ObjectType GetObjectType( INT flags ) { return static_cast<ObjectType>((flags & GDIP_EPRFLAGS_OBJECTTYPE) >> 8); }
inline GpFillMode GetFillMode( INT flags ) { return ((flags & GDIP_EPRFLAGS_WINDINGFILL) == 0) ? FillModeAlternate : FillModeWinding; }
inline BOOL IsClosed( INT flags ) { return ((flags & GDIP_EPRFLAGS_CLOSED) != 0); }
inline BOOL DidGetDC( INT flags ) { return ((flags & GDIP_EPRFLAGS_DIDGETDC) != 0); }
inline GpMatrixOrder GetMatrixOrder( INT flags ) { return ((flags & GDIP_EPRFLAGS_APPEND) == 0) ? MatrixOrderPrepend : MatrixOrderAppend; }
inline BOOL GetAntiAliasMode( INT flags ) { return ((flags & GDIP_EPRFLAGS_ANTIALIAS) != 0); }
inline TextRenderingHint GetTextRenderingHint( INT flags ) { return static_cast<TextRenderingHint> (flags & GDIP_EPRFLAGS_TEXTRENDERINGHINT); }
inline UINT GetTextContrast( INT flags ) { return static_cast<UINT> (flags & GDIP_EPRFLAGS_CONTRAST); }
inline InterpolationMode GetInterpolationMode( INT flags ) { return static_cast<InterpolationMode> (flags & GDIP_EPRFLAGS_INTERPOLATIONMODE); }
inline PixelOffsetMode GetPixelOffsetMode( INT flags ) { return static_cast<PixelOffsetMode> (flags & GDIP_EPRFLAGS_PIXELOFFSETMODE); }
inline GpCompositingMode GetCompositingMode( INT flags ) { return static_cast<GpCompositingMode> (flags & GDIP_EPRFLAGS_COMPOSITINGMODE); }
inline GpCompositingQuality GetCompositingQuality( INT flags ) { return static_cast<GpCompositingQuality> (flags & GDIP_EPRFLAGS_COMPOSITINGQUALITY); }
inline UINT GetMetaObjectId( INT flags ) { return flags & GDIP_EPRFLAGS_METAOBJECTID; }
inline GpPageUnit GetPageUnit( INT flags ) { return static_cast<GpPageUnit>(flags & GDIP_EPRFLAGS_PAGEUNIT); }
inline CombineMode GetCombineMode( INT flags ) { return static_cast<CombineMode>((flags & GDIP_EPRFLAGS_COMBINEMODE) >> 8); }
inline BOOL GetIsDevicePath( INT flags ) { return ((flags & GDIP_EPRFLAGS_ISDEVICEPATH) != 0); }
inline BOOL GetIsEmfPlusDual( INT flags ) { return ((flags & GDIP_EPRFLAGS_EMFPLUSDUAL) != 0); }
class MetafileRecorder; class MetafilePlayer;
class EmfPlusRecord { public: INT16 Type; UINT16 Flags; // This has to be unsigned or the code breaks!
UINT32 Size; // Record size in bytes (including size field)
UINT32 DataSize; // Record size in bytes, excluding header size.
};
class EmfPlusContinueObjectRecord : public EmfPlusRecord { public: UINT32 TotalObjectSize; };
class EmfPlusRecordPlay { public: VOID Play( MetafilePlayer * player, EmfPlusRecordType recordType, UINT flags, UINT dataSize ) const { return; } };
class EmfPlusHeaderRecord : public EmfPlusRecordPlay { public: INT32 Version; // Version of the file
INT32 EmfPlusFlags; // flags (display and non-dual)
INT32 LogicalDpiX; // DpiX of referenceHdc
INT32 LogicalDpiY; // DpiY of referenceHdc
EmfPlusHeaderRecord() { /* no initialization */ } EmfPlusHeaderRecord(INT emfPlusFlags, INT logicalDpiX, INT logicalDpiY) { Version = EMFPLUS_VERSION; EmfPlusFlags = emfPlusFlags; LogicalDpiX = logicalDpiX; LogicalDpiY = logicalDpiY; } };
#ifdef GDIP_RECORD_DEVICEBOUNDS
class EmfPlusBoundsRecord : public EmfPlusRecordPlay { public: GpRectF DeviceBounds; }; #else
#define EmfPlusBoundsRecord EmfPlusRecordPlay
#endif
// When recording, we convert REAL data to INT16 data if we can without
// losing precision.
typedef struct { INT16 X; INT16 Y; } GpPoint16;
typedef struct { INT16 X; INT16 Y; INT16 Width; INT16 Height; } GpRect16;
inline BOOL EmfHeaderIsValid( ENHMETAHEADER3 & emfHeader ) { return ((emfHeader.iType == EMR_HEADER) && (emfHeader.dSignature == ENHMETA_SIGNATURE) && (emfHeader.nSize >= sizeof(ENHMETAHEADER3)) && (emfHeader.nHandles > 0) && (emfHeader.nRecords >= 2) && // must have at least header and EOF record
((emfHeader.nBytes & 3) == 0) && (emfHeader.szlDevice.cx > 0) && (emfHeader.szlDevice.cy > 0) && (emfHeader.szlMillimeters.cx > 0) && (emfHeader.szlMillimeters.cy > 0)); }
GpStatus GetMetafileHeader( HMETAFILE hWmf, const WmfPlaceableFileHeader * wmfPlaceableFileHeader, MetafileHeader & header );
GpStatus GetMetafileHeader( HENHMETAFILE hEmf, MetafileHeader & header, BOOL * isCorrupted = NULL );
GpStatus GetMetafileHeader( IStream * stream, MetafileHeader & header, BOOL tryWmfOnly = FALSE );
GpStatus GetMetafileHeader( const WCHAR * filename, MetafileHeader & header );
///////////////////////////////////////////////////////////////////////////
// Stream helper methods
IStream * CreateStreamOnFile( const OLECHAR * pwcsName, UINT access = GENERIC_WRITE // GENERIC_READ and/or GENERIC_WRITE
);
inline INT HResultSuccess( HRESULT hResult ) { return (!FAILED(hResult)) ? 1 : 0; }
inline INT GetStreamPosition( IStream * stream, LONGLONG & position ) { HRESULT hResult; ULARGE_INTEGER curPosition; LARGE_INTEGER zeroOffset;
zeroOffset.QuadPart = 0; hResult = stream->Seek(zeroOffset, STREAM_SEEK_CUR, &curPosition); position = curPosition.QuadPart; return HResultSuccess(hResult); }
inline INT SeekFromHere( IStream * stream, const LONGLONG & offsetFromHere ) { HRESULT hResult; LARGE_INTEGER offset;
offset.QuadPart = offsetFromHere; hResult = stream->Seek(offset, STREAM_SEEK_CUR, NULL); return HResultSuccess(hResult); }
inline INT SeekFromStart( IStream * stream, const LONGLONG & offsetFromStart ) { HRESULT hResult; LARGE_INTEGER offset;
offset.QuadPart = offsetFromStart; hResult = stream->Seek(offset, STREAM_SEEK_SET, NULL); return HResultSuccess(hResult); }
inline INT CopyStream( IStream * srcStream, IStream * destStream, const LONGLONG & bytesToCopy ) { HRESULT hResult; ULARGE_INTEGER numBytes; ULARGE_INTEGER bytesWritten;
ASSERT (bytesToCopy > 0);
numBytes.QuadPart = bytesToCopy; hResult = srcStream->CopyTo(destStream, numBytes, NULL, &bytesWritten); return ((!FAILED(hResult)) && (bytesWritten.QuadPart == numBytes.QuadPart)) ? 1 : 0; }
///////////////////////////////////////////////////////////////////////////
// Read methods to read values from a stream
inline INT ReadInt16( IStream * stream, INT16 * value ) { ASSERT(sizeof(INT16) == 2);
HRESULT hResult; hResult = stream->Read(value, sizeof(INT16), NULL); return HResultSuccess(hResult); }
inline INT ReadInt32( IStream * stream, INT32 * value ) { ASSERT(sizeof(INT32) == 4);
HRESULT hResult; hResult = stream->Read(value, sizeof(INT32), NULL); return HResultSuccess(hResult); }
inline INT ReadInt32( IStream * stream, UINT32 * value ) { ASSERT(sizeof(UINT32) == 4);
HRESULT hResult; hResult = stream->Read(value, sizeof(UINT32), NULL); return HResultSuccess(hResult); }
inline INT ReadReal( IStream * stream, REAL * value ) { ASSERT(sizeof(REAL) == 4);
HRESULT hResult; hResult = stream->Read(value, sizeof(REAL), NULL); return HResultSuccess(hResult); }
inline INT ReadRect( IStream * stream, GpRectF * value ) { ASSERT(sizeof(GpRectF) == GDIP_RECTF_SIZE);
HRESULT hResult; hResult = stream->Read(value, sizeof(GpRectF), NULL); return HResultSuccess(hResult); }
inline INT ReadMatrix( IStream * stream, GpMatrix * value ) { ASSERT(sizeof(REAL) == GDIP_REAL_SIZE);
REAL matrix[6]; HRESULT hResult; hResult = stream->Read(matrix, GDIP_MATRIX_SIZE, NULL); value->SetMatrix(matrix); return HResultSuccess(hResult); }
inline INT ReadBytes( IStream * stream, VOID * bytes, INT count ) { ASSERT(sizeof(BYTE) == 1);
HRESULT hResult; hResult = stream->Read(bytes, count, NULL); return HResultSuccess(hResult); }
inline INT ReadPoints( IStream * stream, GpPointF * points, INT count ) { ASSERT(sizeof(GpPointF) == GDIP_POINTF_SIZE);
HRESULT hResult; hResult = stream->Read(points, sizeof(GpPointF) * count, NULL); return HResultSuccess(hResult); }
///////////////////////////////////////////////////////////////////////////
// Write methods to write values to a stream
inline INT WriteByte( IStream * stream, BYTE value ) { ASSERT(sizeof(value) == 1);
HRESULT hResult; hResult = stream->Write(&value, sizeof(value), NULL); return HResultSuccess(hResult); }
inline INT WriteInt16( IStream * stream, INT16 value ) { ASSERT(sizeof(value) == 2);
HRESULT hResult; hResult = stream->Write(&value, sizeof(value), NULL); return HResultSuccess(hResult); }
inline INT WriteInt32( IStream * stream, INT32 value ) { ASSERT(sizeof(value) == 4);
HRESULT hResult; hResult = stream->Write(&value, sizeof(value), NULL); return HResultSuccess(hResult); }
inline INT WriteReal( IStream * stream, REAL value ) { ASSERT(sizeof(value) == GDIP_REAL_SIZE);
HRESULT hResult; hResult = stream->Write(&value, sizeof(value), NULL); return HResultSuccess(hResult); }
inline INT WriteColor64( IStream * stream, const ARGB64 & value ) { ASSERT(sizeof(value) == 8);
HRESULT hResult; hResult = stream->Write(&value, sizeof(value), NULL); return HResultSuccess(hResult); }
inline INT WriteRect( IStream * stream, const GpRectF & value ) { ASSERT(sizeof(value) == GDIP_RECTF_SIZE);
HRESULT hResult; hResult = stream->Write(&value, sizeof(value), NULL); return HResultSuccess(hResult); }
inline INT WriteMatrix( IStream * stream, const GpMatrix & value ) { ASSERT(sizeof(REAL) == GDIP_REAL_SIZE);
REAL matrix[6]; value.GetMatrix(matrix); HRESULT hResult; hResult = stream->Write(matrix, GDIP_MATRIX_SIZE, NULL); return HResultSuccess(hResult); }
inline INT WriteBytes( IStream * stream, const VOID * bytes, INT count // number of bytes
) { ASSERT(sizeof(BYTE) == 1);
HRESULT hResult; hResult = stream->Write(bytes, count, NULL); return HResultSuccess(hResult); }
inline INT WritePoints( IStream * stream, const GpPointF * points, INT count ) { ASSERT(sizeof(GpPointF) == GDIP_POINTF_SIZE);
HRESULT hResult; hResult = stream->Write(points, sizeof(GpPointF) * count, NULL); return HResultSuccess(hResult); }
inline INT WriteRects( IStream * stream, const GpRectF * rects, INT count ) { ASSERT(sizeof(GpRectF) == GDIP_RECTF_SIZE);
HRESULT hResult; hResult = stream->Write(rects, sizeof(GpRectF) * count, NULL); return HResultSuccess(hResult); }
GpPointF * GetPointsForPlayback( const BYTE * pointData, UINT pointDataSize, INT count, INT flags, UINT bufferSize, BYTE * buffer, BYTE * & allocedBuffer );
GpRectF * GetRectsForPlayback( BYTE * rectData, UINT rectDataSize, INT count, INT flags, UINT bufferSize, BYTE * buffer, BYTE * & allocedBuffer );
#define GDIP_POINTDATA_BUFFERSIZE 64 // Number of points for the PointBuffer
class MetafilePointData { public: MetafilePointData(const GpPointF * points, INT count); ~MetafilePointData() { delete [] AllocedPoints; } INT WriteData(IStream * stream) const { return WriteBytes(stream, PointData, PointDataSize); } BYTE * GetData() const { return PointData; } INT GetDataSize() const { return PointDataSize; } INT GetFlags() const { return Flags; }
protected: /**************************************************************************\
* * Function Description: * * Determine if a GpPointF is equal to a GpPoint16 (within the tolerance). * * Arguments: * * [IN] point16 - the 16-bit integer point * [IN] point - the REAL point * * Return Value: * * BOOL - whether or not the points are equal * * Created: * * 6/15/1999 DCurtis * \**************************************************************************/ BOOL IsPoint16Equal( const GpPoint16 * point16, const GpPointF * point ) { REAL dx = point->X - (REAL)(point16->X); REAL dy = point->Y - (REAL)(point16->Y);
return ((dx > -REAL_TOLERANCE) && (dx < REAL_TOLERANCE) && (dy > -REAL_TOLERANCE) && (dy < REAL_TOLERANCE)); }
protected: GpPoint16 PointBuffer[GDIP_POINTDATA_BUFFERSIZE]; BYTE * PointData; GpPoint16 * AllocedPoints; INT PointDataSize; INT Flags; };
#define GDIP_RECTDATA_BUFFERSIZE 16 // Number of rects for the RectBuffer
class MetafileRectData { public: MetafileRectData(const GpRectF * rects, INT count); ~MetafileRectData() { delete [] AllocedRects; } INT WriteData(IStream * stream) const { return WriteBytes(stream, RectData, RectDataSize); } BYTE * GetData() const { return RectData; } INT GetDataSize() const { return RectDataSize; } INT GetFlags() const { return Flags; }
protected: /**************************************************************************\
* * Function Description: * * Determine if a GpRectF is equal to a GpRect16 (within the toleranc). * * Arguments: * * [IN] rect16 - the 16-bit integer rect * [IN] rect - the REAL rect * * Return Value: * * BOOL - whether or not the rects are equal * * Created: * * 6/15/1999 DCurtis * \**************************************************************************/ BOOL IsRect16Equal( const GpRect16 * rect16, const GpRectF * rect ) { REAL dx = rect->X - static_cast<REAL>(rect16->X); REAL dy = rect->Y - static_cast<REAL>(rect16->Y); REAL dw = rect->Width - static_cast<REAL>(rect16->Width); REAL dh = rect->Height - static_cast<REAL>(rect16->Height);
return ((dx > -REAL_TOLERANCE) && (dx < REAL_TOLERANCE) && (dy > -REAL_TOLERANCE) && (dy < REAL_TOLERANCE) && (dw > -REAL_TOLERANCE) && (dw < REAL_TOLERANCE) && (dh > -REAL_TOLERANCE) && (dh < REAL_TOLERANCE)); }
protected: GpRect16 RectBuffer[GDIP_RECTDATA_BUFFERSIZE]; BYTE * RectData; GpRect16 * AllocedRects; INT RectDataSize; INT Flags; };
class IMetafileRecord { public: virtual ~IMetafileRecord() {}
virtual VOID GetMetafileBounds(GpRect & metafileBounds) const = 0;
// Record methods to be called only from API classes
// This is for backward compatiblity. If we are using a new object
// (such as a new kind of brush), then we can record a backup object
// for down-level apps to use when they see a new object that they
// don't know how to deal with.
virtual GpStatus RecordBackupObject( const GpObject * object ) = 0;
virtual GpStatus RecordClear( const GpRectF * deviceBounds, GpColor color ) = 0; virtual GpStatus RecordFillRects( const GpRectF * deviceBounds, GpBrush * brush, const GpRectF * rects, INT count ) = 0; virtual GpStatus RecordDrawRects( const GpRectF * deviceBounds, GpPen * pen, const GpRectF * rects, INT count ) = 0; virtual GpStatus RecordFillPolygon( const GpRectF * deviceBounds, GpBrush* brush, const GpPointF * points, INT count, GpFillMode fillMode ) = 0; virtual GpStatus RecordDrawLines( const GpRectF * deviceBounds, GpPen * pen, const GpPointF * points, INT count, BOOL closed ) = 0; virtual GpStatus RecordFillEllipse( const GpRectF * deviceBounds, GpBrush * brush, const GpRectF & rect ) = 0; virtual GpStatus RecordDrawEllipse( const GpRectF * deviceBounds, GpPen * pen, const GpRectF & rect ) = 0; virtual GpStatus RecordFillPie( const GpRectF * deviceBounds, GpBrush * brush, const GpRectF & rect, REAL startAngle, REAL sweepAngle ) = 0; virtual GpStatus RecordDrawPie( const GpRectF * deviceBounds, GpPen * pen, const GpRectF & rect, REAL startAngle, REAL sweepAngle ) = 0; virtual GpStatus RecordDrawArc( const GpRectF * deviceBounds, GpPen * pen, const GpRectF & rect, REAL startAngle, REAL sweepAngle ) = 0; virtual GpStatus RecordFillRegion( const GpRectF * deviceBounds, GpBrush * brush, GpRegion * region ) = 0; virtual GpStatus RecordFillPath( const GpRectF * deviceBounds, const GpBrush * brush, GpPath * path ) = 0; virtual GpStatus RecordDrawPath( const GpRectF * deviceBounds, GpPen * pen, GpPath * path ) = 0; virtual GpStatus RecordFillClosedCurve( const GpRectF * deviceBounds, GpBrush * brush, const GpPointF * points, INT count, REAL tension, GpFillMode fillMode ) = 0; virtual GpStatus RecordDrawClosedCurve( const GpRectF * deviceBounds, GpPen * pen, const GpPointF * points, INT count, REAL tension ) = 0; virtual GpStatus RecordDrawCurve( const GpRectF * deviceBounds, GpPen * pen, const GpPointF * points, INT count, REAL tension, INT offset, INT numberOfSegments ) = 0; virtual GpStatus RecordDrawBeziers( const GpRectF * deviceBounds, GpPen * pen, const GpPointF * points, INT count ) = 0; virtual GpStatus RecordDrawImage( const GpRectF * deviceBounds, const GpImage * image, const GpRectF & destRect, const GpRectF & srcRect, GpPageUnit srcUnit, const GpImageAttributes * imageAttributes ) = 0; virtual GpStatus RecordDrawImage( const GpRectF * deviceBounds, const GpImage * image, const GpPointF * destPoints, INT count, const GpRectF & srcRect, GpPageUnit srcUnit, const GpImageAttributes * imageAttributes ) = 0; virtual GpStatus RecordDrawString( const GpRectF * deviceBounds, const WCHAR *string, INT length, const GpFont *font, const RectF *layoutRect, const GpStringFormat *format, const GpBrush *brush ) = 0; virtual GpStatus RecordDrawDriverString( const GpRectF *deviceBounds, const UINT16 *text, INT glyphCount, const GpFont *font, const GpBrush *brush, const PointF *positions, INT flags, const GpMatrix *matrix ) = 0;
virtual GpStatus RecordSave( INT gstate ) = 0; virtual GpStatus RecordRestore( INT gstate ) = 0; virtual GpStatus RecordBeginContainer( const GpRectF & destRect, const GpRectF & srcRect, GpPageUnit srcUnit, INT containerState ) = 0; virtual GpStatus RecordBeginContainer( INT containerState ) = 0; virtual GpStatus RecordEndContainer( INT containerState ) = 0; virtual GpStatus RecordSetWorldTransform( const GpMatrix & matrix ) = 0; virtual GpStatus RecordResetWorldTransform() = 0; virtual GpStatus RecordMultiplyWorldTransform( const GpMatrix & matrix, GpMatrixOrder order ) = 0; virtual GpStatus RecordTranslateWorldTransform( REAL dx, REAL dy, GpMatrixOrder order ) = 0; virtual GpStatus RecordScaleWorldTransform( REAL sx, REAL sy, GpMatrixOrder order ) = 0; virtual GpStatus RecordRotateWorldTransform( REAL angle, GpMatrixOrder order ) = 0; virtual GpStatus RecordSetPageTransform( GpPageUnit unit, REAL scale ) = 0; virtual GpStatus RecordResetClip() = 0; virtual GpStatus RecordSetClip( const GpRectF & rect, CombineMode combineMode ) = 0; virtual GpStatus RecordSetClip( GpRegion * region, CombineMode combineMode ) = 0; virtual GpStatus RecordSetClip( GpPath * path, CombineMode combineMode, BOOL isDevicePath ) = 0; virtual GpStatus RecordOffsetClip( REAL dx, REAL dy ) = 0; virtual GpStatus RecordGetDC() = 0; virtual GpStatus RecordSetAntiAliasMode( BOOL newMode ) = 0; virtual GpStatus RecordSetTextRenderingHint( TextRenderingHint newMode ) = 0; virtual GpStatus RecordSetTextContrast( UINT gammaValue ) = 0; virtual GpStatus RecordSetInterpolationMode( InterpolationMode newMode ) = 0; virtual GpStatus RecordSetPixelOffsetMode( PixelOffsetMode newMode ) = 0; virtual GpStatus RecordSetCompositingMode( GpCompositingMode newMode ) = 0; virtual GpStatus RecordSetCompositingQuality( GpCompositingQuality newQuality ) = 0;
virtual GpStatus RecordSetRenderingOrigin( INT x, INT y ) = 0;
virtual GpStatus RecordComment( UINT sizeData, const BYTE * data ) = 0; virtual VOID EndRecording() = 0; };
class GpMetafile : public GpImage { friend class GpGraphics; // so graphics can call Play
friend class MetafileRecorder; // to write Header when recording
friend class MetafilePlayer; friend class GpObject; // for empty constructor
public: // Constructors for playback only
GpMetafile(HMETAFILE hWmf, const WmfPlaceableFileHeader * wmfPlaceableFileHeader, BOOL deleteWmf); GpMetafile(HENHMETAFILE hEmf, BOOL deleteEmf); GpMetafile(const WCHAR* filename, const WmfPlaceableFileHeader * wmfPlaceableFileHeader = NULL); GpMetafile(IStream* stream); // this requires an extra copy
// Constructors for recording followed (optionally) by playback
GpMetafile( HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, const GpRectF * frameRect = NULL, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, const WCHAR * description = NULL ); GpMetafile( const WCHAR* fileName, HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, const GpRectF * frameRect = NULL, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, const WCHAR * description = NULL ); GpMetafile( // this requires an extra copy
IStream* stream, HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, const GpRectF * frameRect = NULL, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, const WCHAR * description = NULL );
// Make a copy of the image object
virtual GpImage* Clone() const;
virtual GpImage* CloneColorAdjusted( GpRecolor * recolor, ColorAdjustType adjustType = ColorAdjustTypeDefault ) const;
// Dispose of the image object
virtual VOID Dispose();
// Derive a graphics context to draw into the GpImage object
virtual GpGraphics* GetGraphicsContext();
// When deleting the metafile, we have to lock the graphics, so
// no one can use the graphics while the metafile is being deleted --
// so we need a private method to get the graphics just for that purpose.
// Also, when setting the down-level rasterization limit, we have to
// make sure the graphics is locked as well as the metafile, so we
// use this method for that too.
GpGraphics* PrivateAPIForGettingMetafileGraphicsContext() const { // If they haven't requested the graphics, then we don't need
// to worry about locking it.
return (RequestedMetaGraphics) ? MetaGraphics : NULL; }
// Check if the GpImage object is valid
virtual BOOL IsValid() const { // If the metafile came from a different version of GDI+, its tag
// will not match, and it won't be considered valid.
return ((State >= RecordingMetafileState) && (State <= PlayingMetafileState) && GpImage::IsValid()); }
virtual BOOL IsCorrupted() const { return (State == CorruptedMetafileState); }
VOID GetHeader( MetafileHeader & header ) const { ASSERT(IsValid()); header = Header; }
// Is this an EMF or EMF+ file?
BOOL IsEmfOrEmfPlus() const { return Header.IsEmfOrEmfPlus(); }
GpStatus GetHemf(HENHMETAFILE * hEmf) const;
GpStatus PlayRecord( EmfPlusRecordType recordType, UINT flags, UINT dataSize, const BYTE * data ) const;
VOID SetThreadId(DWORD threadId) const { ThreadId = threadId; } DWORD GetThreadId() const { return ThreadId; }
// Create a bitmap and play the metafile into it.
GpBitmap * GetBitmap( INT width = 0, // 0 means figure use default size
INT height = 0, const GpImageAttributes * imageAttributes = NULL );
////////////////////////////////////////////////////////////
// GpObject virtual methods
////////////////////////////////////////////////////////////
virtual UINT GetDataSize() const; virtual GpStatus GetData(IStream * stream) const; virtual GpStatus SetData(const BYTE * dataBuffer, UINT size);
virtual GpStatus ColorAdjust( GpRecolor * recolor, ColorAdjustType adjustType );
////////////////////////////////////////////////////////////
// GpImage virtual methods
////////////////////////////////////////////////////////////
// Get metafile resolution
virtual GpStatus GetResolution( REAL* xdpi, REAL* ydpi ) const { ASSERT(IsValid());
*xdpi = Header.GetDpiX(); *ydpi = Header.GetDpiY();
return Ok; }
// Get metafile physical dimension in 0.01mm units
virtual GpStatus GetPhysicalDimension( REAL* width, REAL* height ) const { ASSERT(IsValid());
const MetafileHeader * header = &Header;
if (header->IsEmfOrEmfPlus()) { // Don't forget to add one Device Unit
*width = (REAL)(header->EmfHeader.rclFrame.right - header->EmfHeader.rclFrame.left) + 2540.0f / (header->GetDpiX()); *height = (REAL)(header->EmfHeader.rclFrame.bottom - header->EmfHeader.rclFrame.top) + 2540.0f / (header->GetDpiY()); } else { *width = ((REAL)(header->Width) / (header->GetDpiX())) * 2540.0f; *height = ((REAL)(header->Height) / (header->GetDpiY())) * 2540.0f; }
return Ok; }
// Get metafile bounding rectangle in pixels
virtual GpStatus GetBounds( GpRectF* rect, GpPageUnit* unit ) const { ASSERT(IsValid());
const MetafileHeader * header = &Header;
#if 0
if (header->IsEmfOrEmfPlus()) { rect->X = (REAL)(header->EmfHeader.rclFrame.left) / 2540.0f; rect->Y = (REAL)(header->EmfHeader.rclFrame.top) / 2540.0f; rect->Width = (REAL)(header->EmfHeader.rclFrame.right - header->EmfHeader.rclFrame.left) / 2540.0f; rect->Height = (REAL)(header->EmfHeader.rclFrame.bottom - header->EmfHeader.rclFrame.top) / 2540.0f; } else { rect->X = header->X / header->GetDpiX(); rect->Width = header->Width / header->GetDpiX(); rect->Y = header->Y / header->GetDpiY(); rect->Height = header->Height / header->GetDpiY(); } *unit = UnitInch; #else
rect->X = (REAL)header->X; rect->Width = (REAL)header->Width; rect->Y = (REAL)header->Y; rect->Height = (REAL)header->Height; *unit = UnitPixel; #endif
return Ok; }
virtual GpStatus GetImageInfo(ImageInfo* imageInfo) const;
virtual GpImage* GetThumbnail(UINT thumbWidth, UINT thumbHeight, GetThumbnailImageAbort callback, VOID *callbackData) { if ((thumbWidth == 0) && (thumbHeight == 0)) { thumbWidth = thumbHeight = DEFAULT_THUMBNAIL_SIZE; } if ((thumbWidth > 0) && (thumbHeight > 0)) { return this->GetBitmap(thumbWidth, thumbHeight); } return NULL; }
virtual GpStatus GetPalette(ColorPalette *palette, INT size) { return NotImplemented; // There is no palette support for metafiles
}
virtual GpStatus SetPalette(ColorPalette *palette) { return NotImplemented; }
virtual INT GetPaletteSize() { return 0; }
// Save images
// !!!TODO: save functionality?
virtual GpStatus GetEncoderParameterListSize( CLSID* clsidEncoder, UINT* size ) { // Create a new temp bitmap to query
GpStatus status = OutOfMemory; GpBitmap *bitmap = new GpBitmap(1, 1, PixelFormat32bppARGB); if (bitmap != NULL) { if (bitmap->IsValid()) { status = bitmap->GetEncoderParameterListSize(clsidEncoder, size); } bitmap->Dispose(); } return status; }
virtual GpStatus GetEncoderParameterList( CLSID* clsidEncoder, UINT size, EncoderParameters* pBuffer ) { GpStatus status = OutOfMemory; GpBitmap *bitmap = new GpBitmap(1, 1, PixelFormat32bppARGB); if (bitmap != NULL) { if (bitmap->IsValid()) { status = bitmap->GetEncoderParameterList(clsidEncoder, size, pBuffer); } bitmap->Dispose(); } return status; }
virtual GpStatus SaveToStream( IStream* stream, CLSID* clsidEncoder, EncoderParameters* encoderParams ) { GpStatus status = GenericError; GpBitmap *bitmap = GetBitmap(); if (bitmap != NULL) { status = bitmap->SaveToStream(stream, clsidEncoder, encoderParams); bitmap->Dispose(); } return status; }
virtual GpStatus SaveToFile( const WCHAR* filename, CLSID* clsidEncoder, EncoderParameters* encoderParams ) { GpStatus status = GenericError; GpBitmap *bitmap = GetBitmap(); if (bitmap != NULL) { status = bitmap->SaveToFile(filename, clsidEncoder, encoderParams); bitmap->Dispose(); } return status; }
GpStatus SaveAdd( const EncoderParameters* encoderParams ) { return NotImplemented; }
GpStatus SaveAdd( GpImage* newBits, const EncoderParameters* encoderParams ) { return NotImplemented; }
// !!!TODO: what do I do with the dimensionID?
virtual GpStatus GetFrameCount(const GUID* dimensionID, UINT* count) const { if (count != NULL) { *count = 1; return Ok; } return InvalidParameter; }
virtual GpStatus GetFrameDimensionsCount(OUT UINT* count) const { if (count != NULL) { *count = 1; return Ok; } return InvalidParameter; }
virtual GpStatus GetFrameDimensionsList(OUT GUID* dimensionIDs, IN UINT count) const { // Note: the "count" has to be 1
if ((count == 1) && (dimensionIDs != NULL)) { dimensionIDs[0] = FRAMEDIM_PAGE; return Ok; } return InvalidParameter; }
virtual GpStatus SelectActiveFrame(const GUID* dimensionID, UINT index) { // There is only 1 frame in a metafile, so we always succeed
return Ok; }
virtual GpStatus RotateFlip(RotateFlipType rfType) { return NotImplemented; }
virtual GpStatus GetPropertyCount(UINT* numOfProperty) { if (numOfProperty != NULL) { *numOfProperty = 0; return Ok; } return InvalidParameter; }
virtual GpStatus GetPropertyIdList(UINT numOfProperty, PROPID* list) { if (list != NULL) { return NotImplemented; } return InvalidParameter; }
virtual GpStatus GetPropertyItemSize(PROPID propId, UINT* size) { if (size != NULL) { return NotImplemented; } return InvalidParameter; }
virtual GpStatus GetPropertyItem(PROPID propId,UINT propSize, PropertyItem* buffer) { if (buffer != NULL) { return NotImplemented; } return InvalidParameter; }
virtual GpStatus GetPropertySize(UINT* totalBufferSize, UINT* numProperties) { if ((totalBufferSize != NULL) && (numProperties != NULL)) { return NotImplemented; } return InvalidParameter; }
virtual GpStatus GetAllPropertyItems(UINT totalBufferSize, UINT numProperties, PropertyItem* allItems) { if (allItems != NULL) { return NotImplemented; } return InvalidParameter; }
virtual GpStatus RemovePropertyItem(PROPID propId) { return NotImplemented; }
virtual GpStatus SetPropertyItem(PropertyItem* item) { return NotImplemented; }
GpStatus SetDownLevelRasterizationLimit( UINT metafileRasterizationLimitDpi );
GpStatus GetDownLevelRasterizationLimit( UINT * metafileRasterizationLimitDpi ) const;
protected: enum MetafileState { InvalidMetafileState, CorruptedMetafileState, RecordingMetafileState, DoneRecordingMetafileState, ReadyToPlayMetafileState, PlayingMetafileState, }; MetafileHeader Header; mutable DWORD ThreadId; // for syncing enumeration
mutable MetafileState State; mutable HENHMETAFILE Hemf; // for playing metafiles
WCHAR * Filename; IStream * Stream; GpGraphics * MetaGraphics; // for recording to metafile
mutable MetafilePlayer * Player; // for playing the metafile
INT MaxStackSize; BOOL DeleteHemf; BOOL RequestedMetaGraphics;
// Dummy constructors and destructors to prevent
// apps from directly using new and delete operators
// on GpImage objects.
GpMetafile() : GpImage(ImageTypeMetafile) { /* used by object factory */ InitDefaults(); } ~GpMetafile();
VOID InitDefaults(); VOID CleanUp();
BOOL InitForRecording( HDC referenceHdc, EmfType type, const GpRectF * frameRect, // can be NULL
MetafileFrameUnit frameUnit, // if NULL frameRect, doesn't matter
const WCHAR * description // can be NULL
);
GpStatus PrepareToPlay( GpGraphics * g, GpRecolor * recolor, ColorAdjustType adjustType, EnumerateMetafileProc enumerateCallback, VOID * callbackData, DrawImageAbort drawImageCallback, VOID* drawImageCallbackData ) const;
GpStatus EnumerateForPlayback( const RectF & destRect, const RectF & srcRect, Unit srcUnit, GpGraphics * g, EnumerateMetafileProc callback, // if null, just play the metafile
VOID * callbackData, GpRecolor * recolor = NULL, ColorAdjustType adjustType = ColorAdjustTypeDefault, DrawImageAbort drawImageCallback = NULL, VOID* drawImageCallbackData = NULL ) const;
// Play is only to be called by GpGraphics::DrawImage()
GpStatus Play( const GpRectF& destRect, const GpRectF& srcRect, GpPageUnit srcUnit, GpGraphics * graphics, GpRecolor * recolor = NULL, ColorAdjustType adjustType = ColorAdjustTypeDefault, DrawImageAbort drawImageCallback = NULL, VOID* drawImageCallbackData = NULL ) const { return EnumerateForPlayback( destRect, srcRect, srcUnit, graphics, NULL, NULL, recolor, adjustType, drawImageCallback, drawImageCallbackData ); }
VOID InitWmf( HMETAFILE hWmf, const WmfPlaceableFileHeader * wmfPlaceableFileHeader, BOOL deleteWmf );
VOID InitEmf( HENHMETAFILE hEmf, BOOL deleteEmf ); VOID InitStream( IStream* stream, BOOL tryWmfOnly = FALSE ); };
HENHMETAFILE GetEmf( const WCHAR * fileName, MetafileType type );
// GillesK 05/12/2000
// Data types needed for WMF to EMF conversion.
#pragma pack(2)
typedef struct _META_ESCAPE_ENHANCED_METAFILE { DWORD rdSize; // Size of the record in words
WORD rdFunction; // META_ESCAPE
WORD wEscape; // MFCOMMENT
WORD wCount; // Size of the following data + emf in bytes
DWORD ident; // MFCOMMENT_IDENTIFIER
DWORD iComment; // MFCOMMENT_ENHANCED_METAFILE
DWORD nVersion; // Enhanced metafile version 0x10000
WORD wChecksum; // Checksum - used by 1st record only
DWORD fFlags; // Compression etc - used by 1st record only
DWORD nCommentRecords; // Number of records making up the emf
DWORD cbCurrent; // Size of emf data in this record in bytes
DWORD cbRemainder; // Size of remainder in following records
DWORD cbEnhMetaFile; // Size of enhanced metafile in bytes
// The enhanced metafile data follows here
} META_ESCAPE_ENHANCED_METAFILE; typedef META_ESCAPE_ENHANCED_METAFILE UNALIGNED *PMETA_ESCAPE_ENHANCED_METAFILE; #pragma pack()
// Macro to check that it is a meta_escape embedded enhanced metafile record.
inline BOOL IsMetaEscapeEnhancedMetafile( PMETA_ESCAPE_ENHANCED_METAFILE pmfeEnhMF ) { return ((pmfeEnhMF)->rdFunction == META_ESCAPE && (pmfeEnhMF)->rdSize > sizeof(META_ESCAPE_ENHANCED_METAFILE) / 2 && (pmfeEnhMF)->wEscape == MFCOMMENT && (pmfeEnhMF)->ident == MFCOMMENT_IDENTIFIER && (pmfeEnhMF)->iComment == MFCOMMENT_ENHANCED_METAFILE) ; }
// Macro to check the checksum of an EMF file
inline WORD GetWordCheckSum(UINT cbData, PWORD pwData) { WORD wCheckSum = 0; UINT cwData = cbData / sizeof(WORD);
ASSERTMSG(!(cbData%sizeof(WORD)), ("GetWordCheckSum data not WORD multiple")); ASSERTMSG(!((ULONG_PTR)pwData%sizeof(WORD)), ("GetWordCheckSum data not WORD aligned"));
while (cwData--) wCheckSum += *pwData++;
return(wCheckSum); }
extern "C" UINT ConvertEmfToPlaceableWmf ( HENHMETAFILE hemf, UINT cbData16, LPBYTE pData16, INT iMapMode, INT eFlags );
#endif // !_METAFILE_HPP
|