2014-03-10 05:18:05 +00:00
|
|
|
"""
|
|
|
|
Truevision Targa Graphic (TGA) picture parser.
|
|
|
|
|
|
|
|
Author: Victor Stinner
|
|
|
|
Creation: 18 december 2006
|
|
|
|
"""
|
|
|
|
|
2015-08-15 14:22:29 +00:00
|
|
|
from hachoir_parser import Parser
|
|
|
|
from hachoir_core.field import FieldSet, UInt8, UInt16, Enum, RawBytes
|
|
|
|
from hachoir_core.endian import LITTLE_ENDIAN
|
|
|
|
from hachoir_parser.image.common import PaletteRGB
|
2014-03-10 05:18:05 +00:00
|
|
|
|
|
|
|
class Line(FieldSet):
|
|
|
|
def __init__(self, *args):
|
|
|
|
FieldSet.__init__(self, *args)
|
|
|
|
self._size = self["/width"].value * self["/bpp"].value
|
|
|
|
|
|
|
|
def createFields(self):
|
|
|
|
for x in xrange(self["/width"].value):
|
|
|
|
yield UInt8(self, "pixel[]")
|
|
|
|
|
|
|
|
class Pixels(FieldSet):
|
|
|
|
def __init__(self, *args):
|
|
|
|
FieldSet.__init__(self, *args)
|
|
|
|
self._size = self["/width"].value * self["/height"].value * self["/bpp"].value
|
|
|
|
|
|
|
|
def createFields(self):
|
|
|
|
if self["/options"].value == 0:
|
|
|
|
RANGE = xrange(self["/height"].value-1,-1,-1)
|
|
|
|
else:
|
|
|
|
RANGE = xrange(self["/height"].value)
|
|
|
|
for y in RANGE:
|
|
|
|
yield Line(self, "line[%u]" % y)
|
|
|
|
|
|
|
|
class TargaFile(Parser):
|
|
|
|
PARSER_TAGS = {
|
|
|
|
"id": "targa",
|
|
|
|
"category": "image",
|
|
|
|
"file_ext": ("tga",),
|
|
|
|
"mime": (u"image/targa", u"image/tga", u"image/x-tga"),
|
|
|
|
"min_size": 18*8,
|
|
|
|
"description": u"Truevision Targa Graphic (TGA)"
|
|
|
|
}
|
|
|
|
CODEC_NAME = {
|
|
|
|
1: u"8-bit uncompressed",
|
|
|
|
2: u"24-bit uncompressed",
|
|
|
|
9: u"8-bit RLE",
|
|
|
|
10: u"24-bit RLE",
|
|
|
|
}
|
|
|
|
endian = LITTLE_ENDIAN
|
|
|
|
|
|
|
|
def validate(self):
|
|
|
|
if self["version"].value != 1:
|
|
|
|
return "Unknown version"
|
|
|
|
if self["codec"].value not in self.CODEC_NAME:
|
|
|
|
return "Unknown codec"
|
|
|
|
if self["x_min"].value != 0 or self["y_min"].value != 0:
|
|
|
|
return "(x_min, y_min) is not (0,0)"
|
|
|
|
if self["bpp"].value not in (8, 24):
|
|
|
|
return "Unknown bits/pixel value"
|
|
|
|
return True
|
|
|
|
|
|
|
|
def createFields(self):
|
|
|
|
yield UInt8(self, "hdr_size", "Header size in bytes")
|
|
|
|
yield UInt8(self, "version", "Targa version (always one)")
|
|
|
|
yield Enum(UInt8(self, "codec", "Pixels encoding"), self.CODEC_NAME)
|
|
|
|
yield UInt16(self, "palette_ofs", "Palette absolute file offset")
|
|
|
|
yield UInt16(self, "nb_color", "Number of color")
|
|
|
|
yield UInt8(self, "color_map_size", "Color map entry size")
|
|
|
|
yield UInt16(self, "x_min")
|
|
|
|
yield UInt16(self, "y_min")
|
|
|
|
yield UInt16(self, "width")
|
|
|
|
yield UInt16(self, "height")
|
|
|
|
yield UInt8(self, "bpp", "Bits per pixel")
|
|
|
|
yield UInt8(self, "options", "Options (0: vertical mirror)")
|
|
|
|
if self["bpp"].value == 8:
|
|
|
|
yield PaletteRGB(self, "palette", 256)
|
|
|
|
if self["codec"].value == 1:
|
|
|
|
yield Pixels(self, "pixels")
|
|
|
|
else:
|
|
|
|
size = (self.size - self.current_size) // 8
|
|
|
|
if size:
|
|
|
|
yield RawBytes(self, "raw_pixels", size)
|
|
|
|
|
|
|
|
|