1794 lines
50 KiB
C++
1794 lines
50 KiB
C++
/**************************************************************************\
|
|
*
|
|
* 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
|