# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild import kaitaistruct from kaitaistruct import KaitaiStruct, KaitaiStream, BytesIO from enum import Enum import zlib if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 9): raise Exception("Incompatible Kaitai Struct Python API: 0.9 or later is required, but you have %s" % (kaitaistruct.__version__)) class Png(KaitaiStruct): """Test files for APNG can be found at the following locations: * * """ class PhysUnit(Enum): unknown = 0 meter = 1 class BlendOpValues(Enum): source = 0 over = 1 class CompressionMethods(Enum): zlib = 0 class DisposeOpValues(Enum): none = 0 background = 1 previous = 2 class ColorType(Enum): greyscale = 0 truecolor = 2 indexed = 3 greyscale_alpha = 4 truecolor_alpha = 6 def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.magic = self._io.read_bytes(8) if not self.magic == b"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A": raise kaitaistruct.ValidationNotEqualError(b"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", self.magic, self._io, u"/seq/0") self.ihdr_len = self._io.read_u4be() if not self.ihdr_len == 13: raise kaitaistruct.ValidationNotEqualError(13, self.ihdr_len, self._io, u"/seq/1") self.ihdr_type = self._io.read_bytes(4) if not self.ihdr_type == b"\x49\x48\x44\x52": raise kaitaistruct.ValidationNotEqualError(b"\x49\x48\x44\x52", self.ihdr_type, self._io, u"/seq/2") self.ihdr = Png.IhdrChunk(self._io, self, self._root) self.ihdr_crc = self._io.read_bytes(4) self.chunks = [] i = 0 while True: _ = Png.Chunk(self._io, self, self._root) self.chunks.append(_) if ((_.type == u"IEND") or (self._io.is_eof())) : break i += 1 class Rgb(KaitaiStruct): def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.r = self._io.read_u1() self.g = self._io.read_u1() self.b = self._io.read_u1() class Chunk(KaitaiStruct): def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.len = self._io.read_u4be() self.type = (self._io.read_bytes(4)).decode(u"UTF-8") _on = self.type if _on == u"iTXt": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.InternationalTextChunk(_io__raw_body, self, self._root) elif _on == u"gAMA": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.GamaChunk(_io__raw_body, self, self._root) elif _on == u"tIME": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.TimeChunk(_io__raw_body, self, self._root) elif _on == u"PLTE": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.PlteChunk(_io__raw_body, self, self._root) elif _on == u"bKGD": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.BkgdChunk(_io__raw_body, self, self._root) elif _on == u"pHYs": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.PhysChunk(_io__raw_body, self, self._root) elif _on == u"fdAT": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.FrameDataChunk(_io__raw_body, self, self._root) elif _on == u"tEXt": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.TextChunk(_io__raw_body, self, self._root) elif _on == u"cHRM": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.ChrmChunk(_io__raw_body, self, self._root) elif _on == u"acTL": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.AnimationControlChunk(_io__raw_body, self, self._root) elif _on == u"sRGB": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.SrgbChunk(_io__raw_body, self, self._root) elif _on == u"zTXt": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.CompressedTextChunk(_io__raw_body, self, self._root) elif _on == u"fcTL": self._raw_body = self._io.read_bytes(self.len) _io__raw_body = KaitaiStream(BytesIO(self._raw_body)) self.body = Png.FrameControlChunk(_io__raw_body, self, self._root) else: self.body = self._io.read_bytes(self.len) self.crc = self._io.read_bytes(4) class BkgdIndexed(KaitaiStruct): """Background chunk for images with indexed palette.""" def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.palette_index = self._io.read_u1() class Point(KaitaiStruct): def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.x_int = self._io.read_u4be() self.y_int = self._io.read_u4be() @property def x(self): if hasattr(self, '_m_x'): return self._m_x self._m_x = (self.x_int / 100000.0) return getattr(self, '_m_x', None) @property def y(self): if hasattr(self, '_m_y'): return self._m_y self._m_y = (self.y_int / 100000.0) return getattr(self, '_m_y', None) class BkgdGreyscale(KaitaiStruct): """Background chunk for greyscale images.""" def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.value = self._io.read_u2be() class ChrmChunk(KaitaiStruct): """ .. seealso:: Source - https://www.w3.org/TR/PNG/#11cHRM """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.white_point = Png.Point(self._io, self, self._root) self.red = Png.Point(self._io, self, self._root) self.green = Png.Point(self._io, self, self._root) self.blue = Png.Point(self._io, self, self._root) class IhdrChunk(KaitaiStruct): """ .. seealso:: Source - https://www.w3.org/TR/PNG/#11IHDR """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.width = self._io.read_u4be() self.height = self._io.read_u4be() self.bit_depth = self._io.read_u1() self.color_type = KaitaiStream.resolve_enum(Png.ColorType, self._io.read_u1()) self.compression_method = self._io.read_u1() self.filter_method = self._io.read_u1() self.interlace_method = self._io.read_u1() class PlteChunk(KaitaiStruct): """ .. seealso:: Source - https://www.w3.org/TR/PNG/#11PLTE """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.entries = [] i = 0 while not self._io.is_eof(): self.entries.append(Png.Rgb(self._io, self, self._root)) i += 1 class SrgbChunk(KaitaiStruct): """ .. seealso:: Source - https://www.w3.org/TR/PNG/#11sRGB """ class Intent(Enum): perceptual = 0 relative_colorimetric = 1 saturation = 2 absolute_colorimetric = 3 def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.render_intent = KaitaiStream.resolve_enum(Png.SrgbChunk.Intent, self._io.read_u1()) class CompressedTextChunk(KaitaiStruct): """Compressed text chunk effectively allows to store key-value string pairs in PNG container, compressing "value" part (which can be quite lengthy) with zlib compression. .. seealso:: Source - https://www.w3.org/TR/PNG/#11zTXt """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.keyword = (self._io.read_bytes_term(0, False, True, True)).decode(u"UTF-8") self.compression_method = KaitaiStream.resolve_enum(Png.CompressionMethods, self._io.read_u1()) self._raw_text_datastream = self._io.read_bytes_full() self.text_datastream = zlib.decompress(self._raw_text_datastream) class FrameDataChunk(KaitaiStruct): """ .. seealso:: Source - https://wiki.mozilla.org/APNG_Specification#.60fdAT.60:_The_Frame_Data_Chunk """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.sequence_number = self._io.read_u4be() self.frame_data = self._io.read_bytes_full() class BkgdTruecolor(KaitaiStruct): """Background chunk for truecolor images.""" def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.red = self._io.read_u2be() self.green = self._io.read_u2be() self.blue = self._io.read_u2be() class GamaChunk(KaitaiStruct): """ .. seealso:: Source - https://www.w3.org/TR/PNG/#11gAMA """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.gamma_int = self._io.read_u4be() @property def gamma_ratio(self): if hasattr(self, '_m_gamma_ratio'): return self._m_gamma_ratio self._m_gamma_ratio = (100000.0 / self.gamma_int) return getattr(self, '_m_gamma_ratio', None) class BkgdChunk(KaitaiStruct): """Background chunk stores default background color to display this image against. Contents depend on `color_type` of the image. .. seealso:: Source - https://www.w3.org/TR/PNG/#11bKGD """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): _on = self._root.ihdr.color_type if _on == Png.ColorType.indexed: self.bkgd = Png.BkgdIndexed(self._io, self, self._root) elif _on == Png.ColorType.truecolor_alpha: self.bkgd = Png.BkgdTruecolor(self._io, self, self._root) elif _on == Png.ColorType.greyscale_alpha: self.bkgd = Png.BkgdGreyscale(self._io, self, self._root) elif _on == Png.ColorType.truecolor: self.bkgd = Png.BkgdTruecolor(self._io, self, self._root) elif _on == Png.ColorType.greyscale: self.bkgd = Png.BkgdGreyscale(self._io, self, self._root) class PhysChunk(KaitaiStruct): """"Physical size" chunk stores data that allows to translate logical pixels into physical units (meters, etc) and vice-versa. .. seealso:: Source - https://www.w3.org/TR/PNG/#11pHYs """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.pixels_per_unit_x = self._io.read_u4be() self.pixels_per_unit_y = self._io.read_u4be() self.unit = KaitaiStream.resolve_enum(Png.PhysUnit, self._io.read_u1()) class FrameControlChunk(KaitaiStruct): """ .. seealso:: Source - https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.sequence_number = self._io.read_u4be() self.width = self._io.read_u4be() if not self.width >= 1: raise kaitaistruct.ValidationLessThanError(1, self.width, self._io, u"/types/frame_control_chunk/seq/1") if not self.width <= self._root.ihdr.width: raise kaitaistruct.ValidationGreaterThanError(self._root.ihdr.width, self.width, self._io, u"/types/frame_control_chunk/seq/1") self.height = self._io.read_u4be() if not self.height >= 1: raise kaitaistruct.ValidationLessThanError(1, self.height, self._io, u"/types/frame_control_chunk/seq/2") if not self.height <= self._root.ihdr.height: raise kaitaistruct.ValidationGreaterThanError(self._root.ihdr.height, self.height, self._io, u"/types/frame_control_chunk/seq/2") self.x_offset = self._io.read_u4be() if not self.x_offset <= (self._root.ihdr.width - self.width): raise kaitaistruct.ValidationGreaterThanError((self._root.ihdr.width - self.width), self.x_offset, self._io, u"/types/frame_control_chunk/seq/3") self.y_offset = self._io.read_u4be() if not self.y_offset <= (self._root.ihdr.height - self.height): raise kaitaistruct.ValidationGreaterThanError((self._root.ihdr.height - self.height), self.y_offset, self._io, u"/types/frame_control_chunk/seq/4") self.delay_num = self._io.read_u2be() self.delay_den = self._io.read_u2be() self.dispose_op = KaitaiStream.resolve_enum(Png.DisposeOpValues, self._io.read_u1()) self.blend_op = KaitaiStream.resolve_enum(Png.BlendOpValues, self._io.read_u1()) @property def delay(self): """Time to display this frame, in seconds.""" if hasattr(self, '_m_delay'): return self._m_delay self._m_delay = (self.delay_num / (100.0 if self.delay_den == 0 else self.delay_den)) return getattr(self, '_m_delay', None) class InternationalTextChunk(KaitaiStruct): """International text chunk effectively allows to store key-value string pairs in PNG container. Both "key" (keyword) and "value" (text) parts are given in pre-defined subset of iso8859-1 without control characters. .. seealso:: Source - https://www.w3.org/TR/PNG/#11iTXt """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.keyword = (self._io.read_bytes_term(0, False, True, True)).decode(u"UTF-8") self.compression_flag = self._io.read_u1() self.compression_method = KaitaiStream.resolve_enum(Png.CompressionMethods, self._io.read_u1()) self.language_tag = (self._io.read_bytes_term(0, False, True, True)).decode(u"ASCII") self.translated_keyword = (self._io.read_bytes_term(0, False, True, True)).decode(u"UTF-8") self.text = (self._io.read_bytes_full()).decode(u"UTF-8") class TextChunk(KaitaiStruct): """Text chunk effectively allows to store key-value string pairs in PNG container. Both "key" (keyword) and "value" (text) parts are given in pre-defined subset of iso8859-1 without control characters. .. seealso:: Source - https://www.w3.org/TR/PNG/#11tEXt """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.keyword = (self._io.read_bytes_term(0, False, True, True)).decode(u"iso8859-1") self.text = (self._io.read_bytes_full()).decode(u"iso8859-1") class AnimationControlChunk(KaitaiStruct): """ .. seealso:: Source - https://wiki.mozilla.org/APNG_Specification#.60acTL.60:_The_Animation_Control_Chunk """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.num_frames = self._io.read_u4be() self.num_plays = self._io.read_u4be() class TimeChunk(KaitaiStruct): """Time chunk stores time stamp of last modification of this image, up to 1 second precision in UTC timezone. .. seealso:: Source - https://www.w3.org/TR/PNG/#11tIME """ def __init__(self, _io, _parent=None, _root=None): self._io = _io self._parent = _parent self._root = _root if _root else self self._read() def _read(self): self.year = self._io.read_u2be() self.month = self._io.read_u1() self.day = self._io.read_u1() self.hour = self._io.read_u1() self.minute = self._io.read_u1() self.second = self._io.read_u1()