diff options
Diffstat (limited to 'external/construct/formats/graphics')
-rw-r--r-- | external/construct/formats/graphics/__init__.py | 4 | ||||
-rw-r--r-- | external/construct/formats/graphics/bmp.py | 113 | ||||
-rw-r--r-- | external/construct/formats/graphics/emf.py | 198 | ||||
-rw-r--r-- | external/construct/formats/graphics/gif.py | 151 | ||||
-rw-r--r-- | external/construct/formats/graphics/png.py | 355 | ||||
-rw-r--r-- | external/construct/formats/graphics/wmf.py | 129 |
6 files changed, 950 insertions, 0 deletions
diff --git a/external/construct/formats/graphics/__init__.py b/external/construct/formats/graphics/__init__.py new file mode 100644 index 0000000..4abda02 --- /dev/null +++ b/external/construct/formats/graphics/__init__.py @@ -0,0 +1,4 @@ +""" +graphic file formats, including imagery (bmp, jpg, gif, png, ...), +models (3ds, ...), etc. +""" diff --git a/external/construct/formats/graphics/bmp.py b/external/construct/formats/graphics/bmp.py new file mode 100644 index 0000000..abe1ad0 --- /dev/null +++ b/external/construct/formats/graphics/bmp.py @@ -0,0 +1,113 @@ +""" +Windows/OS2 Bitmap (BMP) +this could have been a perfect show-case file format, but they had to make +it ugly (all sorts of alignment or +""" +from construct import * + + +#=============================================================================== +# pixels: uncompressed +#=============================================================================== +def UncompressedRows(subcon, align_to_byte = False): + """argh! lines must be aligned to a 4-byte boundary, and bit-pixel + lines must be aligned to full bytes...""" + if align_to_byte: + line_pixels = Bitwise( + Aligned(Array(lambda ctx: ctx.width, subcon), modulus = 8) + ) + else: + line_pixels = Array(lambda ctx: ctx.width, subcon) + return Array(lambda ctx: ctx.height, + Aligned(line_pixels, modulus = 4) + ) + +uncompressed_pixels = Switch("uncompressed", lambda ctx: ctx.bpp, + { + 1 : UncompressedRows(Bit("index"), align_to_byte = True), + 4 : UncompressedRows(Nibble("index"), align_to_byte = True), + 8 : UncompressedRows(Byte("index")), + 24 : UncompressedRows( + Sequence("rgb", Byte("red"), Byte("green"), Byte("blue")) + ), + } +) + +#=============================================================================== +# pixels: Run Length Encoding (RLE) 8 bit +#=============================================================================== +class RunLengthAdapter(Adapter): + def _encode(self, obj): + return len(obj), obj[0] + def _decode(self, obj): + length, value = obj + return [value] * length + +rle8pixel = RunLengthAdapter( + Sequence("rle8pixel", + Byte("length"), + Byte("value") + ) +) + +#=============================================================================== +# file structure +#=============================================================================== +bitmap_file = Struct("bitmap_file", + # header + Const(String("signature", 2), "BM"), + ULInt32("file_size"), + Padding(4), + ULInt32("data_offset"), + ULInt32("header_size"), + Enum(Alias("version", "header_size"), + v2 = 12, + v3 = 40, + v4 = 108, + ), + ULInt32("width"), + ULInt32("height"), + Value("number_of_pixels", lambda ctx: ctx.width * ctx.height), + ULInt16("planes"), + ULInt16("bpp"), # bits per pixel + Enum(ULInt32("compression"), + Uncompressed = 0, + RLE8 = 1, + RLE4 = 2, + Bitfields = 3, + JPEG = 4, + PNG = 5, + ), + ULInt32("image_data_size"), # in bytes + ULInt32("horizontal_dpi"), + ULInt32("vertical_dpi"), + ULInt32("colors_used"), + ULInt32("important_colors"), + + # palette (24 bit has no palette) + OnDemand( + Array(lambda ctx: 2 ** ctx.bpp if ctx.bpp <= 8 else 0, + Struct("palette", + Byte("blue"), + Byte("green"), + Byte("red"), + Padding(1), + ) + ) + ), + + # pixels + OnDemandPointer(lambda ctx: ctx.data_offset, + Switch("pixels", lambda ctx: ctx.compression, + { + "Uncompressed" : uncompressed_pixels, + } + ), + ), +) + + +if __name__ == "__main__": + obj = bitmap_file.parse_stream(open("../../../tests/bitmap8.bmp", "rb")) + print (obj) + print (repr(obj.pixels.value)) diff --git a/external/construct/formats/graphics/emf.py b/external/construct/formats/graphics/emf.py new file mode 100644 index 0000000..4f00a03 --- /dev/null +++ b/external/construct/formats/graphics/emf.py @@ -0,0 +1,198 @@ +""" +Enhanced Meta File +""" +from construct import * + + +record_type = Enum(ULInt32("record_type"), + ABORTPATH = 68, + ANGLEARC = 41, + ARC = 45, + ARCTO = 55, + BEGINPATH = 59, + BITBLT = 76, + CHORD = 46, + CLOSEFIGURE = 61, + CREATEBRUSHINDIRECT = 39, + CREATEDIBPATTERNBRUSHPT = 94, + CREATEMONOBRUSH = 93, + CREATEPALETTE = 49, + CREATEPEN = 38, + DELETEOBJECT = 40, + ELLIPSE = 42, + ENDPATH = 60, + EOF = 14, + EXCLUDECLIPRECT = 29, + EXTCREATEFONTINDIRECTW = 82, + EXTCREATEPEN = 95, + EXTFLOODFILL = 53, + EXTSELECTCLIPRGN = 75, + EXTTEXTOUTA = 83, + EXTTEXTOUTW = 84, + FILLPATH = 62, + FILLRGN = 71, + FLATTENPATH = 65, + FRAMERGN = 72, + GDICOMMENT = 70, + HEADER = 1, + INTERSECTCLIPRECT = 30, + INVERTRGN = 73, + LINETO = 54, + MASKBLT = 78, + MODIFYWORLDTRANSFORM = 36, + MOVETOEX = 27, + OFFSETCLIPRGN = 26, + PAINTRGN = 74, + PIE = 47, + PLGBLT = 79, + POLYBEZIER = 2, + POLYBEZIER16 = 85, + POLYBEZIERTO = 5, + POLYBEZIERTO16 = 88, + POLYDRAW = 56, + POLYDRAW16 = 92, + POLYGON = 3, + POLYGON16 = 86, + POLYLINE = 4, + POLYLINE16 = 87, + POLYLINETO = 6, + POLYLINETO16 = 89, + POLYPOLYGON = 8, + POLYPOLYGON16 = 91, + POLYPOLYLINE = 7, + POLYPOLYLINE16 = 90, + POLYTEXTOUTA = 96, + POLYTEXTOUTW = 97, + REALIZEPALETTE = 52, + RECTANGLE = 43, + RESIZEPALETTE = 51, + RESTOREDC = 34, + ROUNDRECT = 44, + SAVEDC = 33, + SCALEVIEWPORTEXTEX = 31, + SCALEWINDOWEXTEX = 32, + SELECTCLIPPATH = 67, + SELECTOBJECT = 37, + SELECTPALETTE = 48, + SETARCDIRECTION = 57, + SETBKCOLOR = 25, + SETBKMODE = 18, + SETBRUSHORGEX = 13, + SETCOLORADJUSTMENT = 23, + SETDIBITSTODEVICE = 80, + SETMAPMODE = 17, + SETMAPPERFLAGS = 16, + SETMETARGN = 28, + SETMITERLIMIT = 58, + SETPALETTEENTRIES = 50, + SETPIXELV = 15, + SETPOLYFILLMODE = 19, + SETROP2 = 20, + SETSTRETCHBLTMODE = 21, + SETTEXTALIGN = 22, + SETTEXTCOLOR = 24, + SETVIEWPORTEXTEX = 11, + SETVIEWPORTORGEX = 12, + SETWINDOWEXTEX = 9, + SETWINDOWORGEX = 10, + SETWORLDTRANSFORM = 35, + STRETCHBLT = 77, + STRETCHDIBITS = 81, + STROKEANDFILLPATH = 63, + STROKEPATH = 64, + WIDENPATH = 66, + _default_ = Pass, +) + +generic_record = Struct("records", + record_type, + ULInt32("record_size"), # Size of the record in bytes + Union("params", # Parameters + Field("raw", lambda ctx: ctx._.record_size - 8), + Array(lambda ctx: (ctx._.record_size - 8) // 4, ULInt32("params")) + ), +) + +header_record = Struct("header_record", + Const(record_type, "HEADER"), + ULInt32("record_size"), # Size of the record in bytes + SLInt32("bounds_left"), # Left inclusive bounds + SLInt32("bounds_right"), # Right inclusive bounds + SLInt32("bounds_top"), # Top inclusive bounds + SLInt32("bounds_bottom"), # Bottom inclusive bounds + SLInt32("frame_left"), # Left side of inclusive picture frame + SLInt32("frame_right"), # Right side of inclusive picture frame + SLInt32("frame_top"), # Top side of inclusive picture frame + SLInt32("frame_bottom"), # Bottom side of inclusive picture frame + Const(ULInt32("signature"), 0x464D4520), + ULInt32("version"), # Version of the metafile + ULInt32("size"), # Size of the metafile in bytes + ULInt32("num_of_records"), # Number of records in the metafile + ULInt16("num_of_handles"), # Number of handles in the handle table + Padding(2), + ULInt32("description_size"), # Size of description string in WORDs + ULInt32("description_offset"), # Offset of description string in metafile + ULInt32("num_of_palette_entries"), # Number of color palette entries + SLInt32("device_width_pixels"), # Width of reference device in pixels + SLInt32("device_height_pixels"), # Height of reference device in pixels + SLInt32("device_width_mm"), # Width of reference device in millimeters + SLInt32("device_height_mm"), # Height of reference device in millimeters + + # description string + Pointer(lambda ctx: ctx.description_offset, + StringAdapter( + Array(lambda ctx: ctx.description_size, + Field("description", 2) + ) + ) + ), + + # padding up to end of record + Padding(lambda ctx: ctx.record_size - 88), +) + +emf_file = Struct("emf_file", + header_record, + Array(lambda ctx: ctx.header_record.num_of_records - 1, + generic_record + ), +) + + +if __name__ == "__main__": + obj = emf_file.parse_stream(open("../../../tests/emf1.emf", "rb")) + print (obj) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/construct/formats/graphics/gif.py b/external/construct/formats/graphics/gif.py new file mode 100644 index 0000000..fa50150 --- /dev/null +++ b/external/construct/formats/graphics/gif.py @@ -0,0 +1,151 @@ +# Contributed by +# Dany Zatuchna (danzat at gmail) +""" Implementation of the following grammar for the GIF89a file format +<GIF Data Stream> ::= Header <Logical Screen> <Data>* Trailer + +<Logical Screen> ::= Logical Screen Descriptor [Global Color Table] + +<Data> ::= <Graphic Block> | + <Special-Purpose Block> + +<Graphic Block> ::= [Graphic Control Extension] <Graphic-Rendering Block> + +<Graphic-Rendering Block> ::= <Table-Based Image> | + Plain Text Extension + +<Table-Based Image> ::= Image Descriptor [Local Color Table] Image Data + +<Special-Purpose Block> ::= Application Extension | + Comment Extension +""" +from construct import * +import six + + +data_sub_block = Struct("data_sub_block", + ULInt8("size"), + String("data", lambda ctx: ctx["size"]) +) + +gif_logical_screen = Struct("logical_screen", + ULInt16("width"), + ULInt16("height"), + BitStruct("flags", + Bit("global_color_table"), + BitField("color_resolution", 3), + Bit("sort_flag"), + BitField("global_color_table_bpp", 3) + ), + ULInt8("bgcolor_index"), + ULInt8("pixel_aspect_ratio"), + If(lambda ctx: ctx["flags"]["global_color_table"], + Array(lambda ctx: 2**(ctx["flags"]["global_color_table_bpp"] + 1), + Struct("palette", + ULInt8("R"), + ULInt8("G"), + ULInt8("B") + ) + ) + ) +) + +gif_header = Struct("gif_header", + Const(String("signature", 3), six.b("GIF")), + Const(String("version", 3), six.b("89a")), +) + +application_extension = Struct("application_extension", + Const(ULInt8("block_size"), 11), + String("application_identifier", 8), + String("application_auth_code", 3), + data_sub_block, + ULInt8("block_terminator") +) + +comment_extension = Struct("comment_extension", + data_sub_block, + ULInt8("block_terminator") +) + +graphic_control_extension = Struct("graphic_control_extension", + Const(ULInt8("block_size"), 4), + BitStruct("flags", + BitField("reserved", 3), + BitField("disposal_method", 3), + Bit("user_input_flag"), + Bit("transparent_color_flag"), + ), + ULInt16("delay"), + ULInt8("transparent_color_index"), + ULInt8("block_terminator") +) + +plain_text_extension = Struct("plain_text_extension", + Const(ULInt8("block_size"), 12), + ULInt16("text_left"), + ULInt16("text_top"), + ULInt16("text_width"), + ULInt16("text_height"), + ULInt8("cell_width"), + ULInt8("cell_height"), + ULInt8("foreground_index"), + ULInt8("background_index"), + data_sub_block, + ULInt8("block_terminator") +) + +extension = Struct("extension", + ULInt8("label"), + Switch("ext", lambda ctx: ctx["label"], { + 0xFF: application_extension, + 0xFE: comment_extension, + 0xF9: graphic_control_extension, + 0x01: plain_text_extension + }) +) + +image_descriptor = Struct("image_descriptor", + ULInt16("left"), + ULInt16("top"), + ULInt16("width"), + ULInt16("height"), + BitStruct("flags", + Bit("local_color_table"), + Bit("interlace"), + Bit("sort"), + BitField("reserved", 2), + BitField("local_color_table_bpp", 3) + ), + If(lambda ctx: ctx["flags"]["local_color_table"], + Array(lambda ctx: 2**(ctx["flags"]["local_color_table_bpp"] + 1), + Struct("palette", + ULInt8("R"), + ULInt8("G"), + ULInt8("B") + ) + ) + ), + ULInt8("LZW_minimum_code_size"), + RepeatUntil(lambda obj, ctx: obj.size == 0, data_sub_block) +) + +gif_data = Struct("gif_data", + ULInt8("introducer"), + Switch("dat", lambda ctx: ctx["introducer"], { + 0x21: extension, + 0x2C: image_descriptor + }) +) + +gif_file = Struct("gif_file", + gif_header, + gif_logical_screen, + OptionalGreedyRange(gif_data), + #Const(ULInt8("trailer"), 0x3B) +) + +if __name__ == "__main__": + f = open("../../../tests/sample.gif", "rb") + s = f.read() + f.close() + print(gif_file.parse(s)) diff --git a/external/construct/formats/graphics/png.py b/external/construct/formats/graphics/png.py new file mode 100644 index 0000000..39edf3a --- /dev/null +++ b/external/construct/formats/graphics/png.py @@ -0,0 +1,355 @@ +""" +Portable Network Graphics (PNG) file format +Official spec: http://www.w3.org/TR/PNG + +Original code contributed by Robin Munn (rmunn at pobox dot com) +(although the code has been extensively reorganized to meet Construct's +coding conventions) +""" +from construct import * +import six + + +#=============================================================================== +# utils +#=============================================================================== +def Coord(name, field=UBInt8): + return Struct(name, + field("x"), + field("y"), + ) + +compression_method = Enum(UBInt8("compression_method"), + deflate = 0, + _default_ = Pass +) + + +#=============================================================================== +# 11.2.3: PLTE - Palette +#=============================================================================== +plte_info = Struct("plte_info", + Value("num_entries", lambda ctx: ctx._.length / 3), + Array(lambda ctx: ctx.num_entries, + Struct("palette_entries", + UBInt8("red"), + UBInt8("green"), + UBInt8("blue"), + ), + ), +) + +#=============================================================================== +# 11.2.4: IDAT - Image data +#=============================================================================== +idat_info = OnDemand( + Field("idat_info", lambda ctx: ctx.length), +) + +#=============================================================================== +# 11.3.2.1: tRNS - Transparency +#=============================================================================== +trns_info = Switch("trns_info", lambda ctx: ctx._.image_header.color_type, + { + "greyscale": Struct("data", + UBInt16("grey_sample") + ), + "truecolor": Struct("data", + UBInt16("red_sample"), + UBInt16("blue_sample"), + UBInt16("green_sample"), + ), + "indexed": Array(lambda ctx: ctx.length, + UBInt8("alpha"), + ), + } +) + +#=============================================================================== +# 11.3.3.1: cHRM - Primary chromacities and white point +#=============================================================================== +chrm_info = Struct("chrm_info", + Coord("white_point", UBInt32), + Coord("red", UBInt32), + Coord("green", UBInt32), + Coord("blue", UBInt32), +) + +#=============================================================================== +# 11.3.3.2: gAMA - Image gamma +#=============================================================================== +gama_info = Struct("gama_info", + UBInt32("gamma"), +) + +#=============================================================================== +# 11.3.3.3: iCCP - Embedded ICC profile +#=============================================================================== +iccp_info = Struct("iccp_info", + CString("name"), + compression_method, + Field("compressed_profile", + lambda ctx: ctx._.length - (len(ctx.name) + 2) + ), +) + +#=============================================================================== +# 11.3.3.4: sBIT - Significant bits +#=============================================================================== +sbit_info = Switch("sbit_info", lambda ctx: ctx._.image_header.color_type, + { + "greyscale": Struct("data", + UBInt8("significant_grey_bits"), + ), + "truecolor": Struct("data", + UBInt8("significant_red_bits"), + UBInt8("significant_green_bits"), + UBInt8("significant_blue_bits"), + ), + "indexed": Struct("data", + UBInt8("significant_red_bits"), + UBInt8("significant_green_bits"), + UBInt8("significant_blue_bits"), + ), + "greywithalpha": Struct("data", + UBInt8("significant_grey_bits"), + UBInt8("significant_alpha_bits"), + ), + "truewithalpha": Struct("data", + UBInt8("significant_red_bits"), + UBInt8("significant_green_bits"), + UBInt8("significant_blue_bits"), + UBInt8("significant_alpha_bits"), + ), + } +) + +#=============================================================================== +# 11.3.3.5: sRGB - Standard RPG color space +#=============================================================================== +srgb_info = Struct("srgb_info", + Enum(UBInt8("rendering_intent"), + perceptual = 0, + relative_colorimetric = 1, + saturation = 2, + absolute_colorimetric = 3, + _default_ = Pass, + ), +) + +#=============================================================================== +# 11.3.4.3: tEXt - Textual data +#=============================================================================== +text_info = Struct("text_info", + CString("keyword"), + Field("text", lambda ctx: ctx._.length - (len(ctx.keyword) + 1)), +) + +#=============================================================================== +# 11.3.4.4: zTXt - Compressed textual data +#=============================================================================== +ztxt_info = Struct("ztxt_info", + CString("keyword"), + compression_method, + OnDemand( + Field("compressed_text", + # As with iCCP, length is chunk length, minus length of + # keyword, minus two: one byte for the null terminator, + # and one byte for the compression method. + lambda ctx: ctx._.length - (len(ctx.keyword) + 2), + ), + ), +) + +#=============================================================================== +# 11.3.4.5: iTXt - International textual data +#=============================================================================== +itxt_info = Struct("itxt_info", + CString("keyword"), + UBInt8("compression_flag"), + compression_method, + CString("language_tag"), + CString("translated_keyword"), + OnDemand( + Field("text", + lambda ctx: ctx._.length - (len(ctx.keyword) + + len(ctx.language_tag) + len(ctx.translated_keyword) + 5), + ), + ), +) + +#=============================================================================== +# 11.3.5.1: bKGD - Background color +#=============================================================================== +bkgd_info = Switch("bkgd_info", lambda ctx: ctx._.image_header.color_type, + { + "greyscale": Struct("data", + UBInt16("background_greyscale_value"), + Alias("grey", "background_greyscale_value"), + ), + "greywithalpha": Struct("data", + UBInt16("background_greyscale_value"), + Alias("grey", "background_greyscale_value"), + ), + "truecolor": Struct("data", + UBInt16("background_red_value"), + UBInt16("background_green_value"), + UBInt16("background_blue_value"), + Alias("red", "background_red_value"), + Alias("green", "background_green_value"), + Alias("blue", "background_blue_value"), + ), + "truewithalpha": Struct("data", + UBInt16("background_red_value"), + UBInt16("background_green_value"), + UBInt16("background_blue_value"), + Alias("red", "background_red_value"), + Alias("green", "background_green_value"), + Alias("blue", "background_blue_value"), + ), + "indexed": Struct("data", + UBInt16("background_palette_index"), + Alias("index", "background_palette_index"), + ), + } +) + +#=============================================================================== +# 11.3.5.2: hIST - Image histogram +#=============================================================================== +hist_info = Array(lambda ctx: ctx._.length / 2, + UBInt16("frequency"), +) + +#=============================================================================== +# 11.3.5.3: pHYs - Physical pixel dimensions +#=============================================================================== +phys_info = Struct("phys_info", + UBInt32("pixels_per_unit_x"), + UBInt32("pixels_per_unit_y"), + Enum(UBInt8("unit"), + unknown = 0, + meter = 1, + _default_ = Pass + ), +) + +#=============================================================================== +# 11.3.5.4: sPLT - Suggested palette +#=============================================================================== +def splt_info_data_length(ctx): + if ctx.sample_depth == 8: + entry_size = 6 + else: + entry_size = 10 + return (ctx._.length - len(ctx.name) - 2) / entry_size + +splt_info = Struct("data", + CString("name"), + UBInt8("sample_depth"), + Array(lambda ctx: splt_info_data_length, + IfThenElse("table", lambda ctx: ctx.sample_depth == 8, + # Sample depth 8 + Struct("table", + UBInt8("red"), + UBInt8("green"), + UBInt8("blue"), + UBInt8("alpha"), + UBInt16("frequency"), + ), + # Sample depth 16 + Struct("table", + UBInt16("red"), + UBInt16("green"), + UBInt16("blue"), + UBInt16("alpha"), + UBInt16("frequency"), + ), + ), + ), +) + +#=============================================================================== +# 11.3.6.1: tIME - Image last-modification time +#=============================================================================== +time_info = Struct("data", + UBInt16("year"), + UBInt8("month"), + UBInt8("day"), + UBInt8("hour"), + UBInt8("minute"), + UBInt8("second"), +) + +#=============================================================================== +# chunks +#=============================================================================== +default_chunk_info = OnDemand( + HexDumpAdapter(Field(None, lambda ctx: ctx.length)) +) + +chunk = Struct("chunk", + UBInt32("length"), + String("type", 4), + Switch("data", lambda ctx: ctx.type, + { + "PLTE" : plte_info, + "IEND" : Pass, + "IDAT" : idat_info, + "tRNS" : trns_info, + "cHRM" : chrm_info, + "gAMA" : gama_info, + "iCCP" : iccp_info, + "sBIT" : sbit_info, + "sRGB" : srgb_info, + "tEXt" : text_info, + "zTXt" : ztxt_info, + "iTXt" : itxt_info, + "bKGD" : bkgd_info, + "hIST" : hist_info, + "pHYs" : phys_info, + "sPLT" : splt_info, + "tIME" : time_info, + }, + default = default_chunk_info, + ), + UBInt32("crc"), +) + +image_header_chunk = Struct("image_header", + UBInt32("length"), + Const(String("type", 4), "IHDR"), + UBInt32("width"), + UBInt32("height"), + UBInt8("bit_depth"), + Enum(UBInt8("color_type"), + greyscale = 0, + truecolor = 2, + indexed = 3, + greywithalpha = 4, + truewithalpha = 6, + _default_ = Pass, + ), + compression_method, + Enum(UBInt8("filter_method"), + # "adaptive filtering with five basic filter types" + adaptive5 = 0, + _default_ = Pass, + ), + Enum(UBInt8("interlace_method"), + none = 0, + adam7 = 1, + _default_ = Pass, + ), + UBInt32("crc"), +) + + +#=============================================================================== +# the complete PNG file +#=============================================================================== +png_file = Struct("png", + Magic(six.b("\x89PNG\r\n\x1a\n")), + image_header_chunk, + Rename("chunks", GreedyRange(chunk)), +) diff --git a/external/construct/formats/graphics/wmf.py b/external/construct/formats/graphics/wmf.py new file mode 100644 index 0000000..55e79dd --- /dev/null +++ b/external/construct/formats/graphics/wmf.py @@ -0,0 +1,129 @@ +""" +Windows Meta File +""" +from construct import * + + +wmf_record = Struct("records", + ULInt32("size"), # size in words, including the size, function and params + Enum(ULInt16("function"), + AbortDoc = 0x0052, + Aldus_Header = 0x0001, + AnimatePalette = 0x0436, + Arc = 0x0817, + BitBlt = 0x0922, + Chord = 0x0830, + CLP_Header16 = 0x0002, + CLP_Header32 = 0x0003, + CreateBitmap = 0x06FE, + CreateBitmapIndirect = 0x02FD, + CreateBrush = 0x00F8, + CreateBrushIndirect = 0x02FC, + CreateFontIndirect = 0x02FB, + CreatePalette = 0x00F7, + CreatePatternBrush = 0x01F9, + CreatePenIndirect = 0x02FA, + CreateRegion = 0x06FF, + DeleteObject = 0x01F0, + DibBitblt = 0x0940, + DibCreatePatternBrush = 0x0142, + DibStretchBlt = 0x0B41, + DrawText = 0x062F, + Ellipse = 0x0418, + EndDoc = 0x005E, + EndPage = 0x0050, + EOF = 0x0000, + Escape = 0x0626, + ExcludeClipRect = 0x0415, + ExtFloodFill = 0x0548, + ExtTextOut = 0x0A32, + FillRegion = 0x0228, + FloodFill = 0x0419, + FrameRegion = 0x0429, + Header = 0x0004, + IntersectClipRect = 0x0416, + InvertRegion = 0x012A, + LineTo = 0x0213, + MoveTo = 0x0214, + OffsetClipRgn = 0x0220, + OffsetViewportOrg = 0x0211, + OffsetWindowOrg = 0x020F, + PaintRegion = 0x012B, + PatBlt = 0x061D, + Pie = 0x081A, + Polygon = 0x0324, + Polyline = 0x0325, + PolyPolygon = 0x0538, + RealizePalette = 0x0035, + Rectangle = 0x041B, + ResetDC = 0x014C, + ResizePalette = 0x0139, + RestoreDC = 0x0127, + RoundRect = 0x061C, + SaveDC = 0x001E, + ScaleViewportExt = 0x0412, + ScaleWindowExt = 0x0410, + SelectClipRegion = 0x012C, + SelectObject = 0x012D, + SelectPalette = 0x0234, + SetBKColor = 0x0201, + SetBKMode = 0x0102, + SetDibToDev = 0x0D33, + SelLayout = 0x0149, + SetMapMode = 0x0103, + SetMapperFlags = 0x0231, + SetPalEntries = 0x0037, + SetPixel = 0x041F, + SetPolyFillMode = 0x0106, + SetReLabs = 0x0105, + SetROP2 = 0x0104, + SetStretchBltMode = 0x0107, + SetTextAlign = 0x012E, + SetTextCharExtra = 0x0108, + SetTextColor = 0x0209, + SetTextJustification = 0x020A, + SetViewportExt = 0x020E, + SetViewportOrg = 0x020D, + SetWindowExt = 0x020C, + SetWindowOrg = 0x020B, + StartDoc = 0x014D, + StartPage = 0x004F, + StretchBlt = 0x0B23, + StretchDIB = 0x0F43, + TextOut = 0x0521, + _default_ = Pass, + ), + Array(lambda ctx: ctx.size - 3, ULInt16("params")), +) + +wmf_placeable_header = Struct("placeable_header", + Const(ULInt32("key"), 0x9AC6CDD7), + ULInt16("handle"), + SLInt16("left"), + SLInt16("top"), + SLInt16("right"), + SLInt16("bottom"), + ULInt16("units_per_inch"), + Padding(4), + ULInt16("checksum") +) + +wmf_file = Struct("wmf_file", + # --- optional placeable header --- + Optional(wmf_placeable_header), + + # --- header --- + Enum(ULInt16("type"), + InMemory = 0, + File = 1, + ), + Const(ULInt16("header_size"), 9), + ULInt16("version"), + ULInt32("size"), # file size is in words + ULInt16("number_of_objects"), + ULInt32("size_of_largest_record"), + ULInt16("number_of_params"), + + # --- records --- + GreedyRange(wmf_record) +) |