class Color(bin.Structure): red = bin.Integer(size=1) green = bin.Integer(size=1) blue = bin.Integer(size=1) def __str__(self): return '#%x%x%x' % (self.red, self.green, self.blue)
class InternationalText(bin.Structure, encoding='utf8'): keyword = bin.String() is_compressed = bin.Integer(size=1) compression = bin.Integer(size=1, choices=COMPRESSION_CHOICES) language = bin.String() translated_keyword = bin.String() content = bin.Bytes(size=bin.Remainder) # TODO: decompress
class BMP(bin.Structure, endianness=bin.LittleEndian): signature = bin.FixedString('BM') filesize = bin.Integer('Total file size', size=4) reserved = bin.Reserved(size=4) data_offset = bin.Integer('Offset of the actual image data', size=4) header_size = bin.Integer(size=4, default_value=40) width = bin.Integer(size=4) height = bin.Integer(size=4)
class ImageDescriptor(bin.Structure): separator = bin.FixedString(b',') left = bin.Integer(size=2) top = bin.Integer(size=2) width = bin.Integer(size=2) height = bin.Integer(size=2) info = bin.SubStructure(ImageInfoBits) with info.has_color_map == True: color_map = bin.List(bin.SubStructure(Color), size=2**info.bits_per_pixel)
class TGA(bin.Structure, endianness=bin.LittleEndian): id_size = bin.Integer(size=1) color_map_type = bin.Integer(size=1, choices=COLOR_MAP_TYPES) image_type = bin.Integer(size=1, choices=IMAGE_TYPES) color_map_info = bin.SubStructure(ColorMap) x_origin = bin.Integer(size=2) y_origin = bin.Integer(size=2) width = bin.Integer(size=2) height = bin.Integer(size=2) bit_depth = bin.Integer(size=1) image_origin, alpha_depth = bin.SubStructure(AlphaOrigin) image_id = bin.Bytes(size=id_size) color_map_data = bin.List(bin.Integer(size=color_map_info.entry_size) / 8, size=color_map_info.length) image_data = bin.List(bin.Integer(size=1), size=width * height * bit_depth)
class ScreenDescriptor(bin.Structure, endianness=bin.LittleEndian): width = bin.Integer(size=2) height = bin.Integer(size=2) info = bin.SubStructure(ScreenInfoBits) background_color = bin.Integer(size=1) pixel_ratio = bin.Integer(size=1) with info.has_color_map == True: color_map = bin.List(bin.SubStructure(Color), size=2**info.bits_per_pixel) @property def aspect_ratio(self): if self.pixel_ratio == 0: return None return (self.pixel_ratio + 15) / 64
class Header(bin.Structure): width = bin.Integer(size=4) height = bin.Integer(size=4) bit_depth = bin.Integer(size=1, choices=(1, 2, 4, 8, 16)) color_type = bin.Integer(size=1, choices=(0, 2, 3, 4, 6)) compression_method = bin.Integer(size=1, choices=COMPRESSION_CHOICES) filter_method = bin.Integer(size=1, choices=FILTER_CHOICES) interlace_method = bin.Integer(size=1, choices=INTERLACE_CHOICES)
class Timestamp(bin.Structure): year = bin.Integer(size=2) month = bin.Integer(size=1) day = bin.Integer(size=1) hour = bin.Integer(size=1) minute = bin.Integer(size=1) second = bin.Integer(size=1)
def read(self, size=None): bit_buffer = self._bit_buffer if size > self._bits_left: # Read more bytes from the file read_size = int(((size - self._bits_left) + 7) / 8) field = bin.Integer(size=read_size) bytes = self._file.read(read_size) value = field.decode(bytes) bit_buffer = (bit_buffer << size) | value self._bits_left += read_size * 8 self._bits_left -= size % 8 bits = bit_buffer >> self._bits_left self._bit_buffer = bit_buffer & (1 << self._bits_left) - 1 return bits
class Header(bin.Structure): marker = bin.FixedString(b'JFIF\x00') major_version = bin.Integer(size=1) minor_version = bin.Integer(size=1) density_units = bin.Integer(size=1, choicse=DENSITY_UNITS) x_density = bin.Integer(size=2) y_density = bin.Integer(size=2) thumb_width = bin.Integer(size=1) thumb_height = bin.Integer(size=1) thumb_data = bin.Bytes(size=3 * thumb_width * thumb_height) @property def version(self): return '%i.%02i' % (self.major_version, self.minor_version)
class Chunk(bin.Chunk, encoding='ascii'): """ A special chunk for PNG, which puts the size before the type and includes a CRC field for verifying data integrity. """ size = bin.Integer(size=4) id = bin.String(size=4) payload = bin.Payload(size=size) crc = bin.CRC32(first=id) @property def is_critical(self): # Critical chunks will always have an uppercase letter for the # first character in the type. Ancillary will always be lower. return self.type[0].upper() == self.type[0] @property def is_public(self): # Public chunks will always have an uppercase letter for the # second character in the type. Private will always be lower. return self.type[1].upper() == self.type[1]
class ScanChunk(bin.Chunk): id = bin.Integer(size=2) size = bin.Integer(size=2) payload = bin.Payload(size=size - 2)
class EmptyChunk(bin.Chunk): id = bin.Integer(size=2) size = bin.Bytes(size=0) payload = bin.Payload(size=0)
class TestStructure(bin.Structure): integer = bin.Integer('number', size=1) string = bin.String(encoding='ascii')
class SuggestedPaletteEntry(bin.Structure): red = bin.Integer(size=2) green = bin.Integer(size=2) blue = bin.Integer(size=2) alpha = bin.Integer(size=2) frequency = bin.Integer(size=2)
class FineTune(bin.PackedStructure): Reserved(size=4) value = bin.Integer(size=4)
class PNG(bin.Structure): signature = bin.FixedString(b'\x89PNG\x0d\x0a\x1a\x0a') header_size = bin.Integer(size=4) header_id = bin.FixedString(b'IHDR') width = bin.Integer(size=4, min_value=1) height = bin.Integer(size=4, min_value=1)
class Form(bin.Chunk, encoding='ascii'): tag = bin.FixedString('FORM') size = bin.Integer(size=4) id = bin.String(size=4) payload = bin.Payload(size=size)
class Histogram(bin.Structure): frequencies = bin.List(bin.Integer(size=2), size=bin.Remainder)
class CompressedText(bin.Structure, encoding='latin-1'): keyword = bin.String() compression = bin.Integer(size=1, choices=COMPRESSION_CHOICES) content = bin.Bytes(size=bin.Remainder) # TODO: decompress
class SuggestedPalette(bin.Structure): name = bin.String(encoding='latin-1') sample_depth = bin.Integer(size=1) colors = bin.List(bin.SubStructure(SuggestedPaletteEntry), size=bin.Remainder)
class StartFrame(bin.Structure): precision = bin.Integer(size=1) width = bin.Integer(size=2) height = bin.Integer(size=2)
class sRGB(bin.Structure): rendering_intent = bin.Integer(size=1, choices=RENDERING_INTENT_CHOICES)
class PaletteColor(bin.Structure): red = bin.Integer(size=1) green = bin.Integer(size=1) blue = bin.Integer(size=1)
class GIF(bin.Structure, endianness=bin.LittleEndian, encoding='ascii'): tag = bin.FixedString('GIF') version = bin.String(size=3, choices=GIF_VERSIONS) width = bin.Integer(size=2) height = bin.Integer(size=2)
class TestStructure(bin.Structure): length = bin.Integer('number', size=1) content = bin.String(encoding='ascii', size=length)
class TestStructure(bin.Structure): forty_two = bin.Integer(size=2, endianness=bin.LittleEndian) sixty_six = bin.Integer(size=1) valid = bin.String(encoding='ascii') test = bin.String(encoding='ascii')
class PhysicalDimentions(bin.Structure): x = bin.Integer(size=4) y = bin.Integer(size=4) unit = bin.Integer(size=1, choices=PHYSICAL_UNIT_CHOICES)
class Chunk(bin.Chunk): id = bin.String(size=4, encoding='ascii') size = bin.Integer(size=4) payload = bin.Payload(size=size)
class ICCProfile(bin.Structure): name = bin.String(encoding='latin-1') compression = bin.Integer(size=1, choices=COMPRESSION_CHOICES) profile = bin.Bytes(size=bin.Remainder) # TODO: decompress