Microsoft Windows MetafileMicrosoft Windows Metafile Format (WMF) используется для хранения векторных и растровых изображений и графических данных в памяти или в дисковых файлах. Векторные данные хранимые WMF-файлом описывают команды Microsoft Windows Graphics Device Interface (GDI). Система интерпретирует и воспроизводит эти команды в контексте отображения, используя Windows API функцию PlayMetaFile(). Растровые изображения в WMF файле могут содержаться в формате Microsoft Device Dependent Bitmap (DDB), или Device Independent Bitmap (DIB). В Windows, метафайлы обычно создаются и воспроизводятся в памяти. Если данные метафайла слишком велики, что бы держать их в памяти, или должены быть сохранены прежде, чем приложение завершилось, то они могут быть записаны на диск в формате WMF или EMF и воспроизведены обратно с диска. Максимальный размер метафайла – 4 Гб. WMF – это базовый 16-битный формат, который появлялся в Windows 2.0. Формат EMF является 32-битной дополненной переработкой формата WMF. EMF расширил функциональное назначение WMF, включая цветную палитру и полную поддержку для всех 32-битовых команд GDI. Win32 API (Windows 95 и Windows NT) и 32-битный OLE поддерживает как WMF, так и EMF файлы. Win16 API и 16-битный OLE поддерживает только WMF. Хотя формат Windows Metafile поддерживают большое количество приложений, работающих на других платформах, основное его назначение – это обмен графической информацией между Windows приложениями. Например, Adobe's Encapsulated PostScript (EPS) поддерживает использование включенного Windows Metafile, когда требуется сохранить векторные данные. При использовании метафайлов в Windows или OS/2, нет необходимости писать специальные программы для выполнения грамматического разбора их содержимого, можно вызывать имеющиеся в Windows API функции. Поскольку есть обширная документация Microsoft и IBM по использованию метафайлов в Windows и OS/2, эта статья рассмотрит структуру и синтаксический анализ метафайлов без использования Windows API. Все структуры данных и определения типов данных связанные с файлами WMF находятся в заголовочном файле WINDOWS.H. Для Win32 SDK определения WMF и EMF содержатся в WINUSER.H WINGDI.H. Оба этих SDK пригодны для всех C и C++ компиляторов, которые поддерживают разработку Windows приложений. Структура Файлов Метафайл состоит из одного или двух информационных заголовков и массива переменной длины, который содержит информацию о реальных GDI командах. Есть четыре разновидности метафайлов standard, placeable, clipboard, и enhanced. Метафайлы standardсодержат 18-байтовый заголовок WMF, после которого следуют одна или более записей GDI команд. Последняя запись в файле содержит информацию, указывающую, что достигнут конец данных. Рисунок Microsoft Windows Metafile-1: Standard metafile format Метафайлыplaceableсодержат дополнительный 22-байтовый заголовок, который содержит информацию, описывающую положение изображения на устройстве отображения. После него следует стандартный 18-байтовый заголовок WMF и командные записи GDI. Figure Microsoft Windows Metafile-2: Placeable metafile format Метафайлы clipboardсодержат дополнительный 8-байтовый (Win16) или 16-байтовый заголовок (Win32), который предшествует стандартному заголовку метафайла и описывает режим отображения и размер изображения. Figure Microsoft Windows Metafile-3: Clipboard metafile format Figure Microsoft Windows Metafile-4: Enhanced metafile format Описание заголовков Стандартный заголовок Windows metafile занимает 18 байт и его стуктура выглядит следующим образом: typedef struct _WindowsMetaHeader { WORD FileType; /* Расположение метафайла (0=память, 1=диск) */ WORD HeaderSize; /* Размер заголовка в словах (WORDS) (всегда = 9) */ WORD Version; /* Версия Microsoft Windows */ DWORD FileSize; /* Общий размер метафайла в словах */ WORD NumOfObjects; /* Количество объектов в файле */ DWORD MaxRecordSize; /* Размер самой большой записи в словах */ WORD NumOfParams; /* Не используется (всегда 0) */ } WMFHEAD; FileTypeсодержит флаг, указывающий местоположение данных метафайла. FileType=0 указывает, что метафайл находится в памяти,FileType=1 указывает, что метафайл находится на диске. HeaderSizeсодержит размер заголовка метафайла в словах, и всегда равно 9. Versionуказывает версию Microsoft Windows создавшую этот метафайл. Это значение должно быть всегда указано. Например, в метафайле созданном Windows 3.0 and 3.1, Version=0x0300. FileSizeопределяет общий размер файла в словах. NumOfObjects определяет количество объектов в файле. MaxRecordSizeопределяет максимально возможный размер объекта, содержащегося в файле. NumOfParams не используется. Всегда имеет значение 0. Placeable метафайлы были разработаны корпорацией Aldus, как нестандартный путь указать параметры отображения на устройстве отображения. Placeable метафайлы широко распространены, но не поддерживаются Windows API. Для воспроизведения placeable метафайла используя Windows API необходимо переделать его заголовок. Каждый Placeable заголовок содержит 22 байта и выглядит следующим образом: typedef struct _PlaceableMetaHeader { DWORD Key; /* Ключик (всегда 9AC6CDD7h) */ WORD Handle; /* (всегда 0) */ SHORT Left; /* Левая координата */ SHORT Top; /* Верхняя координата */ SHORT Right; /* Правая координата */ SHORT Bottom; /* Нижняя координата */ WORD Inch; /* Кол-во логических единиц в дюйме */ DWORD Reserved; /* Не используется (всегда 0) */ WORD Checksum; /* Контрольная сумма для предыдущих 10 слов */ } PLACEABLEMETAHEADER; Key содержит специальное значение, идентифицируцие заголовок и всегда равное 9AC6CDD7h. Handle исспользуется при расположении метафайла в памяти. Когда файл находится на диске, всегда равен 0. Left, Top, Right, and Bottom содержит координаты изображения на устройстве отображения в логических единицах. (1 логическая единица 1/1440 дюйма, 720 логических единиц = 1/2 дюйма). Inchсодержит количество логических единиц в дюйме для данного изображения. Обычно это 1440 логических единиц в дюйме. Reserved не используется и всегда = 0. Checksumсодержит контрольную сумму предыдущих 10 слов заголовка. Вычисляется посредством XOR кодирования: PLACEABLEMETAHEADER pmh; pmh.Checksum = 0; pmh.Checksum ^= (pmh.Key & 0x0000FFFFUL); pmh.Checksum ^= ((pmh.Key & 0xFFFF0000UL) >> 16); pmh.Checksum ^= pmh.Handle; pmh.Checksum ^= pmh.Left; pmh.Checksum ^= pmh.Top; pmh.Checksum ^= pmh.Right; pmh.Checksum ^= pmh.Bottom; pmh.Checksum ^= pmh.Inch; pmh.Checksum ^= (pmh.Reserved & 0x0000FFFFUL); pmh.Checksum ^= ((pmh.Reserved & 0xFFFF0000UL) >> 16);или: PLACEABLEMETAHEADER *pmh; WORD *ptr; pmh->Checksum = 0; for (ptr = (WORD *) pmh; ptr < (WORD *)pmh->Checksum; ptr++) pmh->Checksum ^= *ptr; Clipboardметафайлы используют формат заголовка стандартных метафайлов, но ему предшествует 8- или 16-байтный заголовок: typedef struct _Clipboard16MetaHeader { SHORT MappingMode; /* Units used to playback metafile */ SHORT Width; /* Width of the metafile */ SHORT Height; /* Height of the metafile */ WORD Handle; /* Handle to the metafile in memory */ } CLIPBOARD16METAHEADER; typedef struct _Clipboard32MetaHeader { LONG MappingMode; /* Единицы, использующиеся для отображения */ LONG Width; /* Ширина */ LONG Height; /* Высота */ DWORD Handle; /* Указатель на область памяти */ } CLIPBOARD32METAHEADER; MappingMode указывает тип координат для отбражения. Может принимать следующие значения:
Width и Height размер изображения с учетом значения MappingMode Enhancedметафайлы являются новой и расширенной 32-битной версией стандартных метафайлов. Только 32-разрядный Windows API (Win32) поддерживает EMF файлы. Строковые данные в EMF файлах используют Unicode кодировку. Заголовок EMF содержит 80 байт и выглядит так: typedef struct _EnhancedMetaHeader { DWORD RecordType; /* Тип записи */ DWORD RecordSize; /* Размер записи в байтах */ LONG BoundsLeft; /* Левая граница */ LONG BoundsRight; /* Правая граница */ LONG BoundsTop; /* Верхняя граница */ LONG BoundsBottom; /* Нижняя граница */ LONG FrameLeft; /* Left side of inclusive picture frame */ LONG FrameRight; /* Right side of inclusive picture frame */ LONG FrameTop; /* Top side of inclusive picture frame */ LONG FrameBottom; /* Bottom side of inclusive picture frame */ DWORD Signature; /* ID (Всегда 0x464D4520) */ DWORD Version; /* Версия метафайла */ DWORD Size; /* Размер файла в байтах */ DWORD NumOfRecords; /* Количество записей в файле */ WORD NumOfHandles; /* Number of handles in the handle table */ WORD Reserved; /* Не используется (Всегда 0) */ DWORD SizeOfDescrip; /* Размер строки описания в словах */ DWORD OffsOfDescrip; /* Смещение строки описания */ DWORD NumPalEntries; /* Количество цветов в палитре */ LONG WidthDevPixels; /* Ширина устройства в пикселях */ LONG HeightDevPixels; /* Высота устройства в пикселях */ LONG WidthDevMM; /* Ширина устройства в миллиметрах */ LONG HeightDevMM; /* Высота устройства в миллиметрах */ //Если версия Windows >= 4 то есть еще поля DWORD cbPixelFormat; // размер PIXELFORMATDESCRIPTOR //Равен 0 если структура отсутствует DWORD offPixelFormat; // сммещение PIXELFORMATDESCRIPTOR // Равен 0 если структура отсутсвует DWORD bOpenGL; // 1 если OpenGL присутствуют // команды OpenGL } ENHANCEDMETAHEADER; RecordType идентифицирует EMF запись. Для заголовка всегда 00000001h. RecordSizeразмер заголовка в байтах. BoundsLeft, BoundsRight, BoundsTop, и BoundsBottom указывает размер изображения в координатах X, Y, ширина, и высота. BoundsTop и BoundsBottom должны быть больше чем BoundsLeft и BoundsRight соответственно. FrameLeft, FrameRight, FrameTop, и FrameBottom указывает размер страницы включающей изображение в координатах X, Y, ширина, и высота.FrameTop и FrameBottom должны быть больше чемFrameLeft и FrameRight соответственно. Signature идентификатор. Всегда равен 0x464D4520. Version версия EMF файла. Версия 1.0 выглядит как 0x00000100. Size размер файла в байтах. NumOfRecords< количество записей метафайла, влючая заголовочную запись. NumOfHandlesколичество заголовков, используемых метафайлом при размещении его в памяти. Всегда равен 0 для дисковых файлов. Reserved не используется. Всегда 0. SizeOfDescrip количество 16-битных Unicode символов строки описания, включая все NULL символы. Если параметр равен 0, то строки описания в файле нет. OffsOfDescrip положение строки описания от начала файла. Если параметр равен 0, то строки описания в файле нет. NumPalEntries количество цветов в палитре. Палитра, если она присутствует должна находиться в конечной записи файла. Если парамет равен 0, палитра отсутствует. WidthDevPixels и HeightDevPixels ширина и высота устройства отображения в пикселах. WidthDevMM и HeightDevMM ширина и высота устройства отображения в миллиметрах. Строка описанния EMF файла.Строка описания EMF файла представляет собой набор Unicode символов. Размер строки практически не ограничен (может содержать более 2 билионов символов). Формат строки является "double NULL-terminated" где каждый первый 0 является признаком конца подстроки. Типичная строка оописания выглядит следующим образом: "Pain Paint 1.5\0Eating at Polly's\0\0" Структура Записей стандартных МетафайловПосле заголовка всех типов метафайлов следуют записи описания данных. Структура записей METARECORD описана в файле WINDOWS.H и выглядит следующим образом: typedef struct _StandardMetaRecord { DWORD Size; /* общий размер записи в словах */ WORD Function; /* Номер функции */ WORD Parameters[]; /* Параметры функции */ } WMFRECORD; Size общий размер записи в словах, включая поляSize и Function. Минимальное значение для этого поля равно 3. Function номер GDI функции вызываемой для воспроизведения записи. Младший байт указывает номер функции, старший – количество параметров функции в словах. Например, значение 0x0213 указывает на функцию LineTo() (0x13) и на то, что функции необходимо два параметра. Параметры, используемые функцией, следуют в обратном порядке. Например, функции LineTo() необходимы параметры X и Y, но в записи они следуют, как Y и X. Все параметры при сохранении метафайла приведены к типу WORD, Поэтому необходимо преобразовать их тип перед использованием в функции. Последняя запись метафайлов всегда содержит функцию с номером 0000h, поле Size равно 0003h, отсутствует массив параметров. Эта запись является заглушкой и показывает, что достигнут конец данных. (Q99334) Например, запись, описывающая функцию LineTo должна отобразить линию от текущей точки до точки, описанной в записи: Size 5 /* 5 слов в записи */ Function 0x0213 /* номер функции LineTo */ Parameters[0] 50 /* координата Y */ Parameters[1] 100 /* координата X */ Эти данные приведут к вызову GDI функции LineTo(): LineTo(hDC, 100, 5); Некоторые функции содержат не только массив параметров, но и структуры с данными. Например, запись, описывающая функцию BitBlt использует сохраненное растровое изображениев формате Device Dependent Bitmap (DDB). Структура записи BitBlt в метафайлах Windows 2.x выглядит следующим образом: typedef struct _BitBltRecord { DWORD Size; /* Размер записи в словах */ WORD Function; /* Номер функции (0x0922) */ WORD RasterOp; /* старшее слово растровой операции */ WORD YSrcOrigin; /* Y-координата источника */ WORD XSrcOrigin; /* X-координата источника */ WORD YDest; /* ширина отображения */ WORD XDest; /* высота отображения */ WORD YDestOrigin; /* Y-координата отображения */ WORD XDestOrigin; /* X-координата отображения */ /* DDB Bitmap */ DWORD Width; /* ширина растра в пикселях */ DWORD Height; /* высота растра в строках */ DWORD BytesPerLine; /* разрешение */ WORD NumColorPlanes; /* количество цветов в палитре */ WORD BitsPerPixel; /* количество бит на пиксель */ RGBTRIPLE Bitmap[]; /* растр */ } BITBLTRECORD; Массив bitmap состоит из структур RGBTRIPLE: typedef struct _RGBTriple { BYTE Red; BYTE Green; BYTE Blue; } RGBTRIPLE; DDB формат поддерживается Windows 2.x но не совместим с Windows 3.0 и старше. Windows 3.0 описывает функцию DibBitBlt и Device Independent Bitmap (DIB): typedef struct _DibBitBltRecord { DWORD Size; /* Размер записи в словах */ WORD Function; /* Номер функции (0x0922) */ WORD RasterOp; /* старшее слово растровой операции */ WORD YSrcOrigin; /* Y-координата источника */ WORD XSrcOrigin; /* X-координата источника */ WORD YDest; /* ширина отображения */ WORD XDest; /* высота отображения */ WORD YDestOrigin; /* Y-координата отображения */ WORD XDestOrigin; /* X-координата отображения */ /* DIB Bitmap */ DWORD Width; /* ширина растра в пикселях */ DWORD Height; /* высота растра в строках */ DWORD BytesPerLine; /* разрешение */ WORD NumColorPlanes; /* количество цветов в палитре */ WORD BitsPerPixel; /* количество бит на пиксель */ DWORD Compression; /* Формат сжатия */ DWORD SizeImage; /* Размер растра в байтах */ LONG XPelsPerMeter; /* расрешение по горизонтали */ LONG YPelsPerMeter; /* разрешение по вертикали */ DWORD ClrUsed; /* Количетсво используемых цветов */ DWORD ClrImportant; /* Количество важных цветов */ RGBQUAD Bitmap[]; /* растр */ } DIBBITBLTRECORD; Массив bitmapсостоит из структур RGBQUAD: typedef struct _RGBQuad { BYTE Red; BYTE Green; BYTE Blue; BYTE Reserved; } RGBQUAD; Другая специфическая запись метафайлов, заслуживающая внимание это Escape (0x0626). API Windows 3.x поддерживает 64 escape-последовательностей, которые могут содержаться в метафайле. Но на практике каждая escape-последовательность работает по разному, в зависимости от типа принтера. Ниже приведен список GDI функций, поддержка которых в метафайлах была изменена с Microsoft Windows 3.0: AnimatePalette Не все GDI функции могут быть использованы в метафайлах, а только те, которые используют заголовок устройства отображения в качестве первого параметра. Структура записей Enhanced метафайловEnhanced метафайлы имеют свою собственную структуру, которая похожа на структуру записей стандартных метафайолв, но является полностью 32-разрядной: typedef struct _EnhancedMetaRecord { DWORD Function; /* Номер функции (определено в WINGDI.H) */ DWORD Size; /* Общий размер записи в байтах */ DWORD Parameters[]; /* параметры */ } EMFRECORD; Фунции, поддерживаемые EMFописаны в WINDOWS.H и начинаются с преффикса EMR_*. Size общий размер записи в байтах, включая поля Size и Function. Минимальное значение равно 8. Parameters массив параметров, используемых GDI функцией. Параметры следуют в обратном порядке, чем в вызове функции. Например, два параметра для LineTo(X, Y) будут следовать, как Y и X. EMF метафайл может состоять из любых из 97 типов записей, но 2 типа должны присутствовать обязательно. Это заголовочная запись (1) и Заглушка (14).
Таблица цветовEMF файл также может содержать таблицу цветов, используемую при отображении изображения. По умолчанию, файл не содержит таблицу цветов и использует системную палитру. Поле NumPalEntries заголовка EMF файла указывает на количество цветов в таблице и равно 0 если таблица отсутствует. Если таблица присутствует, то она находится в конечной записи-заглушке: typedef struct _EndOfRecord { DWORD Function; /* Номер функции (14) */ DWORD Size; /* Размер записи в байтах */ DWORD NumPalEntries; /* ККоличество цветов палитре */ DWORD OffPalEntries; /* Смещение первого цвета */ PALENT Palette[]; /* Палитра */ DWORD OffToEOF; /* Смещение о тначала записи */ } ENDOFRECORD; Function Номер функции. Для заглушки всегда равен 14. Size общий размер записи в байтах. Для записи не содержаещй палитры равен 20. NumPalEntries количество цветов в палитре. Значение переписывается из поля NumPalEntries заголовка. OffPalEntries указывает позицию первого значения палитры от начала записи. Palette массив стурктур PALENT. Поле отсутвует, если палитры нет. OffToEOF смещение от начала записи. Равно значению поля Size. Структура PALENT: typedef struct _PaletteEntry { BYTE Red; /* */ BYTE Green; /* */ BYTE Blue; /* */ BYTE Flags; /* */ } PALENT; Red, Green, и Blue содержат цветовые компоненты определения цвета. Flags может принимать значения:
GDI CommentОдной из важных особенностей EMF формата является возможность использования скрытых данных в файле. В отличие от escape-последовательностей WMF, комментарий GDI может содержать любой тип данных, полностью независящий от внешних устройств GDICOMMENT запись имеет формат: typedef struct _GdiCommentRecord { DWORD Function; /* Номер функции (70) */ DWORD Size; /* Размер записи в байтах */ DWORD SizeOfData; /* Размер данных в байтах */ BYTE Data[]; /* Комментарий */ } GDICOMMENTRECORD; Function номер функции. Для GDI комментария всегда равен 70. Size Общий размер записи в байтах. Для пустой записи комментария равен 12 SizeOfData Размер записи Data в байтах. Data сам комментарий. GDI комментарии могут содержать несколько определенных типов комментариев:
Заголовок Public комментария выглядит следующим образом: typedef struct _GdiCommentMetafile { DWORD Identifier; /* ID комментария(0x43494447) */ DWORD Comment; /* ID типа комментария (0x80000001) */ DWORD Version; /* Версия метафайла */ DWORD Checksum; /* Контрольная сумма метафайла */ DWORD Flags; /* Флаг (0) */ DWORD Size; /* Размер данных в байтах */ } GDICOMMENTMETAFILE; Identifier содержит значение 0x43494447 идентифицирующее комментарий. Comment содержит значение 0x80000001 идентифицирующее структуру Public комментария Version содержит значение версии метафайла. Обычно это 0x00000001. Checksum контрольная сумма данных метафайла. Flags всегда содержит 0. Size Размер данных метафайла в байтах. BeginGroup / EndGroup комментарии содержат один или несколько EMF объектов. BeginGroup указывает начало списка, EMF записей, и заканчивается EndGroup структурой. Такие группы могут быть вложенными. typedef struct _GdiCommentBeginGroup { DWORD Identifier; /* ID комментария(0x43494447) */ DWORD Comment; /* BeginGroup ID (0x00000002) */ LONG BoundsLeft; /* Левая точка прямоугольника */ LONG BoundsRight; /* Правая точка прямоугольника */ LONG BoundsTop; /* Верхняя точка прямоугольника */ LONG BoundsBottom; /* Нижняя точка прямоугольника */ DWORD SizeOfDescrip; /* Количество символов в описании */ } GDICOMMENTBEGINGROUP; Identifier содержит значение 0x43494447 идентифицирующее комментарий Comment содержит значение 0x00000002 идентифицирующее структуру BeginGroup комментария. BoundsLeft, BoundsRight, BoundsTop, и BoundsBottom определяют область вывода изображения. SizeOfDescrip количество Unicode символов строки описания. Строка,если она присутствует, должна следовать сразу за заголовком. Поле равно 0, если строки нет. EndGroup содержит только идентификационный заголовок без данных: typedef struct _GdiCommentEndGroup { DWORD Identifier; /* комментария ID (0x43494447) */ DWORD Comment; /* EndGroup ID (0x00000003) */ } GDICOMMENTENDGROUP; Identifier содержит значение 0x43494447 идентифицирующее комментарий. Comment содержит значение 0x00000003 идентифицирующее структуру EndGroup комментария. Multiformats комментарий используется для хранения метафайлов и Encapsulated PostScript (EPS) данных. Этот комментарий начинается с заголовка, затем идет одно или последовательност изображений: typedef struct _GdiCommentMultiFormats { DWORD Identifier; /* ID комментария(0x43494447) */ DWORD Comment; /* Multiformats ID (0x40000004) */ LONG BoundsLeft; /* Левая точка прямоугольника */ LONG BoundsRight; /* Правая точка прямоугольника */ LONG BoundsTop; /* Верхняя точка прямоугольника */ LONG BoundsBottom; /* Нижняя точка прямоугольника */ DWORD NumFormats; /* Количество объектов в структуре */ EMRFORMAT Data[]; /* Массим объектов */ } GDICOMMENTMULTIFORMATS Identifier содержит значение 0x43494447 идентифицирующее комментарий. Comment содержит значение 0x40000004 идентифицирующее структуру Multiformats комментария. BoundsLeft, BoundsRight, BoundsTop, и BoundsBottom определяют область вывода изображения. NumFormats кличество структур EMRFORMAT. Data сами структуры EMRFORMAT. typedef struct _EmrFormat { DWORD Signature; /* Идентификатор формата */ DWORD Version; /* Версия формата */ DWORD Data; /* Размер данных в байтах */ DWORD OffsetToData; /* Смещение в байтах */ } EMRFORMAT; Signature содержит значение 0x464D4520 идентифицирующее структуру метафайла, и значение 0x46535045 идентифицирующее Encapsulated PostScript файл. Version версия данных. Для EPS содержит версию EPS файла. Для EMF обычно равно 0x00000001. Data размер содержащейся структуры в байтах. OffsetToData содержит смещение данных относительно начала структуры GDICOMMENTMULTIFORMATS. Copyright © 1996, 1994 O'Reilly & Associates, Inc. All Rights Reserved. |