""" PCX picture filter. """ from hachoir.parser import Parser from hachoir.field import ( UInt8, UInt16, PaddingBytes, RawBytes, Enum) from hachoir.parser.image.common import PaletteRGB from hachoir.core.endian import LITTLE_ENDIAN class PcxFile(Parser): endian = LITTLE_ENDIAN PARSER_TAGS = { "id": "pcx", "category": "image", "file_ext": ("pcx",), "mime": ("image/x-pcx",), "min_size": 128 * 8, "description": "PC Paintbrush (PCX) picture" } compression_name = {1: "Run-length encoding (RLE)"} version_name = { 0: "Version 2.5 of PC Paintbrush", 2: "Version 2.8 with palette information", 3: "Version 2.8 without palette information", 4: "PC Paintbrush for Windows", 5: "Version 3.0 (or greater) of PC Paintbrush" } def validate(self): if self["id"].value != 10: return "Wrong signature" if self["version"].value not in self.version_name: return "Unknown format version" if self["bpp"].value not in (1, 2, 4, 8, 24, 32): return "Unknown bits/pixel" if self["reserved[0]"].value != b"\0": return "Invalid reserved value" return True def createFields(self): yield UInt8(self, "id", "PCX identifier (10)") yield Enum(UInt8(self, "version", "PCX version"), self.version_name) yield Enum(UInt8(self, "compression", "Compression method"), self.compression_name) yield UInt8(self, "bpp", "Bits / pixel") yield UInt16(self, "xmin", "Minimum X") yield UInt16(self, "ymin", "Minimum Y") yield UInt16(self, "xmax", "Width minus one") # value + 1 yield UInt16(self, "ymax", "Height minus one") # value + 1 yield UInt16(self, "horiz_dpi", "Horizontal DPI") yield UInt16(self, "vert_dpi", "Vertical DPI") yield PaletteRGB(self, "palette_4bits", 16, "Palette (4 bits)") yield PaddingBytes(self, "reserved[]", 1) yield UInt8(self, "nb_color_plan", "Number of color plans") yield UInt16(self, "bytes_per_line", "Bytes per line") yield UInt16(self, "color_mode", "Color mode") yield PaddingBytes(self, "reserved[]", 58) if self._size is None: # TODO: is it possible to handle piped input? raise NotImplementedError nb_colors = 256 size = (self._size - self.current_size) // 8 has_palette = self["bpp"].value == 8 if has_palette: size -= nb_colors * 3 yield RawBytes(self, "image_data", size, "Image data") if has_palette: yield PaletteRGB(self, "palette_8bits", nb_colors, "Palette (8 bit)")