summaryrefslogtreecommitdiff
path: root/external/construct/formats/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'external/construct/formats/graphics')
-rw-r--r--external/construct/formats/graphics/__init__.py4
-rw-r--r--external/construct/formats/graphics/bmp.py113
-rw-r--r--external/construct/formats/graphics/emf.py198
-rw-r--r--external/construct/formats/graphics/gif.py151
-rw-r--r--external/construct/formats/graphics/png.py355
-rw-r--r--external/construct/formats/graphics/wmf.py129
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)
+)