Port CLIM decoder to Construct 2.8; add more pixel formats

This commit is contained in:
Eevee (Lexy Munroe) 2016-12-20 19:24:59 -08:00
parent d7c20809e5
commit c111a56612

View file

@ -1,24 +1,23 @@
import math import math
import struct import struct
import attr
import construct as c import construct as c
clim_header_struct = c.Struct( clim_header_struct = c.Struct(
'clim_header', c.Const(b'FLIM'), # TODO 'FLIM' in SUMO
c.Magic(b'FLIM'), # TODO 'FLIM' in SUMO 'endianness' / c.Const(c.Int16ul, 0xfeff),
c.Const(c.ULInt16('endianness'), 0xfeff), 'header_length' / c.Const(c.Int16ul, 0x14),
c.Const(c.ULInt16('header_length'), 0x14), 'version' / c.Int32ul,
c.ULInt32('version'), 'file_size' / c.Int32ul,
c.ULInt32('file_size'), 'blocks_ct' / c.Int32ul,
c.ULInt32('blocks_ct'),
) )
imag_header_struct = c.Struct( imag_header_struct = c.Struct(
'imag_header', c.Const(b'imag'),
c.Magic(b'imag'), 'section_length' / c.Const(c.Int32ul, 0x10),
c.Const(c.ULInt32('section_length'), 0x10), 'width' / c.Int16ul,
c.ULInt16('width'), 'height' / c.Int16ul,
c.ULInt16('height'), 'format' / c.Int32ul,
c.ULInt32('format'),
# TODO this seems to have been expanded into several things in SUMO # TODO this seems to have been expanded into several things in SUMO
#c.Enum( #c.Enum(
# c.ULInt32('format'), # c.ULInt32('format'),
@ -41,17 +40,42 @@ imag_header_struct = c.Struct(
) )
# TODO probably move these to their own module, since they aren't just for
# CLIM. pixel deshuffler, too. (which should probably spit out pypng's native
# format)
COLOR_DECODERS = {} COLOR_DECODERS = {}
def _register_color_decoder(name, *, bpp, depth): @attr.s
class ColorFormat:
name = attr.ib('name')
decoder = attr.ib('decoder')
bits_per_pixel = attr.ib('bits_per_pixel')
bit_depth = attr.ib('bit_depth')
alpha = attr.ib('alpha')
def __call__(self, data):
return self.decoder(data)
def __iter__(self):
# TODO back compat until i fix the below code
return iter((self.decoder, self.bits_per_pixel, self.bit_depth))
def _register_color_decoder(name, *, bpp, depth, alpha):
def register(f): def register(f):
COLOR_DECODERS[name] = f, bpp, depth COLOR_DECODERS[name] = ColorFormat(name, f, bpp, depth, alpha)
return f return f
return register return register
@_register_color_decoder('RGBA4', bpp=2, depth=4) @_register_color_decoder('L8', bpp=1, depth=8, alpha=False)
def decode_l8(data):
for l in data:
yield l, l, l
@_register_color_decoder('RGBA4', bpp=2, depth=4, alpha=True)
def decode_rgba4(data): def decode_rgba4(data):
# The idea is that every uint16 is a packed rrrrggggbbbbaaaa, but when # The idea is that every uint16 is a packed rrrrggggbbbbaaaa, but when
# written out little-endian this becomes bbbbaaaarrrrgggg and there's just # written out little-endian this becomes bbbbaaaarrrrgggg and there's just
@ -66,7 +90,31 @@ def decode_rgba4(data):
yield r, g, b, a yield r, g, b, a
@_register_color_decoder('RGBA5551', bpp=2, depth=5) @_register_color_decoder('RGB8', bpp=3, depth=8, alpha=False)
def decode_rgb8(data):
for i in range(0, len(data), 3):
yield data[i:i + 3]
@_register_color_decoder('RGBA8', bpp=4, depth=8, alpha=True)
def decode_rgba8(data):
for i in range(0, len(data), 4):
yield data[i:i + 4]
@_register_color_decoder('BGR8', bpp=3, depth=8, alpha=False)
def decode_bgr8(data):
for i in range(0, len(data), 3):
yield data[i:i + 3][::-1]
@_register_color_decoder('ABGR8', bpp=4, depth=8, alpha=True)
def decode_abgr8(data):
for i in range(0, len(data), 4):
yield data[i:i + 4][::-1]
@_register_color_decoder('RGBA5551', bpp=2, depth=5, alpha=True)
def decode_rgba5551(data, *, start=0, count=None): def decode_rgba5551(data, *, start=0, count=None):
# I am extremely irritated that construct cannot parse this mess for me # I am extremely irritated that construct cannot parse this mess for me
# rrrrrgggggbbbbba # rrrrrgggggbbbbba