Module refinery.lib.png
Shared PNG parsing library. Provides structure definitions and constants for parsing Portable Network Graphics (PNG) files, used by both the format extractor unit and the PNG carver.
Expand source code Browse git
"""
Shared PNG parsing library. Provides structure definitions and constants for parsing
Portable Network Graphics (PNG) files, used by both the format extractor unit and the
PNG carver.
"""
from __future__ import annotations
import enum
import zlib
from refinery.lib.structures import Struct, StructReader
PNG_SIGNATURE = b'\x89PNG\r\n\x1A\n'
class PngChunkType(bytes, enum.Enum):
IHDR = b'IHDR'
PLTE = b'PLTE'
IDAT = b'IDAT'
IEND = b'IEND'
bKGD = b'bKGD'
cHRM = b'cHRM'
cICP = b'cICP'
dSIG = b'dSIG'
eXIf = b'eXIf'
gAMA = b'gAMA'
hIST = b'hIST'
iCCP = b'iCCP'
iTXt = b'iTXt'
pHYs = b'pHYs'
sBIT = b'sBIT'
sPLT = b'sPLT'
sRGB = b'sRGB'
sTER = b'sTER'
tEXt = b'tEXt'
tIME = b'tIME'
tRNS = b'tRNS'
zTXt = b'zTXt'
PNG_CHUNK_TYPES = frozenset(t.value for t in PngChunkType)
class PngChunk(Struct[memoryview]):
def __init__(self, reader: StructReader[memoryview]):
self.offset = reader.tell()
self.size = reader.u32()
self.type_tag = bytes(reader.read_exactly(4))
try:
self.type = PngChunkType(self.type_tag)
except ValueError:
self.type = None
self.data = reader.read_exactly(self.size)
self.crc = reader.u32()
@property
def valid(self) -> bool:
cs = zlib.crc32(self.type_tag)
cs = zlib.crc32(self.data, cs)
return cs & 0xFFFFFFFF == self.crc
@property
def type_name(self) -> str:
if isinstance(self.type, PngChunkType):
return self.type.name
return self.type_tag.decode('ascii', errors='replace')
class PngIHDR(Struct):
def __init__(self, reader: StructReader):
reader.bigendian = True
self.width = reader.u32()
self.height = reader.u32()
self.bit_depth = reader.u8()
self.color_type = reader.u8()
self.compression = reader.u8()
self.filter = reader.u8()
self.interlace = reader.u8()
class Png(Struct[memoryview]):
def __init__(self, reader: StructReader[memoryview]):
reader.bigendian = True
signature = reader.read_exactly(8)
if bytes(signature) != PNG_SIGNATURE:
raise ValueError('Invalid PNG signature.')
self.ihdr: PngIHDR | None = None
self.chunks: list[PngChunk] = []
self.text_chunks: list[PngChunk] = []
self.meta_chunks: list[PngChunk] = []
while not reader.eof:
chunk = PngChunk(reader)
self.chunks.append(chunk)
if chunk.type == PngChunkType.IHDR:
if self.ihdr is not None:
raise ValueError('Duplicate IHDR chunk in PNG file.')
self.ihdr = PngIHDR.Parse(chunk.data)
elif chunk.type in (PngChunkType.tEXt, PngChunkType.zTXt, PngChunkType.iTXt):
self.text_chunks.append(chunk)
elif isinstance(chunk.type, PngChunkType) and chunk.type not in (
PngChunkType.IHDR,
PngChunkType.PLTE,
PngChunkType.IDAT,
PngChunkType.IEND,
):
self.meta_chunks.append(chunk)
if chunk.type == PngChunkType.IEND:
break
Classes
class PngChunkType (*args, **kwds)-
bytes(iterable_of_ints) -> bytes bytes(string, encoding[, errors]) -> bytes bytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer bytes(int) -> bytes object of size given by the parameter initialized with null bytes bytes() -> empty bytes object
Construct an immutable array of bytes from: - an iterable yielding integers in range(256) - a text string encoded using the specified encoding - any object implementing the buffer API. - an integer
Expand source code Browse git
class PngChunkType(bytes, enum.Enum): IHDR = b'IHDR' PLTE = b'PLTE' IDAT = b'IDAT' IEND = b'IEND' bKGD = b'bKGD' cHRM = b'cHRM' cICP = b'cICP' dSIG = b'dSIG' eXIf = b'eXIf' gAMA = b'gAMA' hIST = b'hIST' iCCP = b'iCCP' iTXt = b'iTXt' pHYs = b'pHYs' sBIT = b'sBIT' sPLT = b'sPLT' sRGB = b'sRGB' sTER = b'sTER' tEXt = b'tEXt' tIME = b'tIME' tRNS = b'tRNS' zTXt = b'zTXt'Ancestors
- builtins.bytes
- enum.Enum
Class variables
var IHDR-
The type of the None singleton.
var PLTE-
The type of the None singleton.
var IDAT-
The type of the None singleton.
var IEND-
The type of the None singleton.
var bKGD-
The type of the None singleton.
var cHRM-
The type of the None singleton.
var cICP-
The type of the None singleton.
var dSIG-
The type of the None singleton.
var eXIf-
The type of the None singleton.
var gAMA-
The type of the None singleton.
var hIST-
The type of the None singleton.
var iCCP-
The type of the None singleton.
var iTXt-
The type of the None singleton.
var pHYs-
The type of the None singleton.
var sBIT-
The type of the None singleton.
var sPLT-
The type of the None singleton.
var sRGB-
The type of the None singleton.
var sTER-
The type of the None singleton.
var tEXt-
The type of the None singleton.
var tIME-
The type of the None singleton.
var tRNS-
The type of the None singleton.
var zTXt-
The type of the None singleton.
class PngChunk (reader)-
A class to parse structured data. A
Structclass can be instantiated as follows:foo = Struct(data, bar=29)The initialization routine of the structure will be called with a single argument
reader. If the objectdatais already aStructReader, then it will be passed asreader. Otherwise, the argument will be wrapped in aStructReader. Additional arguments to the struct are passed through.Expand source code Browse git
class PngChunk(Struct[memoryview]): def __init__(self, reader: StructReader[memoryview]): self.offset = reader.tell() self.size = reader.u32() self.type_tag = bytes(reader.read_exactly(4)) try: self.type = PngChunkType(self.type_tag) except ValueError: self.type = None self.data = reader.read_exactly(self.size) self.crc = reader.u32() @property def valid(self) -> bool: cs = zlib.crc32(self.type_tag) cs = zlib.crc32(self.data, cs) return cs & 0xFFFFFFFF == self.crc @property def type_name(self) -> str: if isinstance(self.type, PngChunkType): return self.type.name return self.type_tag.decode('ascii', errors='replace')Ancestors
- Struct
- typing.Generic
- collections.abc.Buffer
Static methods
def Parse(reader, *args, **kwargs)
Instance variables
var valid-
Expand source code Browse git
@property def valid(self) -> bool: cs = zlib.crc32(self.type_tag) cs = zlib.crc32(self.data, cs) return cs & 0xFFFFFFFF == self.crc var type_name-
Expand source code Browse git
@property def type_name(self) -> str: if isinstance(self.type, PngChunkType): return self.type.name return self.type_tag.decode('ascii', errors='replace')
class PngIHDR (reader)-
A class to parse structured data. A
Structclass can be instantiated as follows:foo = Struct(data, bar=29)The initialization routine of the structure will be called with a single argument
reader. If the objectdatais already aStructReader, then it will be passed asreader. Otherwise, the argument will be wrapped in aStructReader. Additional arguments to the struct are passed through.Expand source code Browse git
class PngIHDR(Struct): def __init__(self, reader: StructReader): reader.bigendian = True self.width = reader.u32() self.height = reader.u32() self.bit_depth = reader.u8() self.color_type = reader.u8() self.compression = reader.u8() self.filter = reader.u8() self.interlace = reader.u8()Ancestors
- Struct
- typing.Generic
- collections.abc.Buffer
Static methods
def Parse(reader, *args, **kwargs)
class Png (reader)-
A class to parse structured data. A
Structclass can be instantiated as follows:foo = Struct(data, bar=29)The initialization routine of the structure will be called with a single argument
reader. If the objectdatais already aStructReader, then it will be passed asreader. Otherwise, the argument will be wrapped in aStructReader. Additional arguments to the struct are passed through.Expand source code Browse git
class Png(Struct[memoryview]): def __init__(self, reader: StructReader[memoryview]): reader.bigendian = True signature = reader.read_exactly(8) if bytes(signature) != PNG_SIGNATURE: raise ValueError('Invalid PNG signature.') self.ihdr: PngIHDR | None = None self.chunks: list[PngChunk] = [] self.text_chunks: list[PngChunk] = [] self.meta_chunks: list[PngChunk] = [] while not reader.eof: chunk = PngChunk(reader) self.chunks.append(chunk) if chunk.type == PngChunkType.IHDR: if self.ihdr is not None: raise ValueError('Duplicate IHDR chunk in PNG file.') self.ihdr = PngIHDR.Parse(chunk.data) elif chunk.type in (PngChunkType.tEXt, PngChunkType.zTXt, PngChunkType.iTXt): self.text_chunks.append(chunk) elif isinstance(chunk.type, PngChunkType) and chunk.type not in ( PngChunkType.IHDR, PngChunkType.PLTE, PngChunkType.IDAT, PngChunkType.IEND, ): self.meta_chunks.append(chunk) if chunk.type == PngChunkType.IEND: breakAncestors
- Struct
- typing.Generic
- collections.abc.Buffer
Static methods
def Parse(reader, *args, **kwargs)