diff options
Diffstat (limited to 'external/construct/formats/graphics/gif.py')
-rw-r--r-- | external/construct/formats/graphics/gif.py | 151 |
1 files changed, 151 insertions, 0 deletions
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)) |