Merge pull request #1826 from anthrotype/colorLib

colorLib: add buildCOLR and buildCPAL
This commit is contained in:
Cosimo Lupo 2020-02-18 15:11:41 +00:00 committed by GitHub
commit 909be35e57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 399 additions and 32 deletions

View File

View File

@ -0,0 +1,147 @@
import enum
from typing import Dict, Iterable, List, Optional, Tuple, Union
from fontTools.ttLib.tables.C_O_L_R_ import LayerRecord, table_C_O_L_R_
from fontTools.ttLib.tables.C_P_A_L_ import Color, table_C_P_A_L_
from fontTools.ttLib.tables._n_a_m_e import table__n_a_m_e
from .errors import ColorLibError
def buildCOLR(colorLayers: Dict[str, List[Tuple[str, int]]]) -> table_C_O_L_R_:
"""Build COLR table from color layers mapping.
Args:
colorLayers: : map of base glyph names to lists of (layer glyph names,
palette indices) tuples.
Return:
A new COLRv0 table.
"""
colorLayerLists = {}
for baseGlyphName, layers in colorLayers.items():
colorLayerLists[baseGlyphName] = [
LayerRecord(layerGlyphName, colorID) for layerGlyphName, colorID in layers
]
colr = table_C_O_L_R_()
colr.version = 0
colr.ColorLayers = colorLayerLists
return colr
class ColorPaletteType(enum.IntFlag):
USABLE_WITH_LIGHT_BACKGROUND = 0x0001
USABLE_WITH_DARK_BACKGROUND = 0x0002
@classmethod
def _missing_(cls, value):
# enforce reserved bits
if isinstance(value, int) and (value < 0 or value & 0xFFFC != 0):
raise ValueError(f"{value} is not a valid {cls.__name__}")
return super()._missing_(value)
# None, 'abc' or {'en': 'abc', 'de': 'xyz'}
_OptionalLocalizedString = Union[None, str, Dict[str, str]]
def buildPaletteLabels(
labels: List[_OptionalLocalizedString], nameTable: table__n_a_m_e
) -> List[Optional[int]]:
return [
nameTable.addMultilingualName(l, mac=False)
if isinstance(l, dict)
else table_C_P_A_L_.NO_NAME_ID
if l is None
else nameTable.addMultilingualName({"en": l}, mac=False)
for l in labels
]
def buildCPAL(
palettes: List[List[Tuple[float, float, float, float]]],
paletteTypes: Optional[List[ColorPaletteType]] = None,
paletteLabels: Optional[List[_OptionalLocalizedString]] = None,
paletteEntryLabels: Optional[List[_OptionalLocalizedString]] = None,
nameTable: Optional[table__n_a_m_e] = None,
) -> table_C_P_A_L_:
"""Build CPAL table from list of color palettes.
Args:
palettes: list of lists of colors encoded as tuples of (R, G, B, A) floats
in the range [0..1].
paletteTypes: optional list of ColorPaletteType, one for each palette.
paletteLabels: optional list of palette labels. Each lable can be either:
None (no label), a string (for for default English labels), or a
localized string (as a dict keyed with BCP47 language codes).
paletteEntryLabels: optional list of palette entry labels, one for each
palette entry (see paletteLabels).
nameTable: optional name table where to store palette and palette entry
labels. Required if either paletteLabels or paletteEntryLabels is set.
Return:
A new CPAL v0 or v1 table, if custom palette types or labels are specified.
"""
if len({len(p) for p in palettes}) != 1:
raise ColorLibError("color palettes have different lengths")
if (paletteLabels or paletteEntryLabels) and not nameTable:
raise TypeError(
"nameTable is required if palette or palette entries have labels"
)
cpal = table_C_P_A_L_()
cpal.numPaletteEntries = len(palettes[0])
cpal.palettes = []
for i, palette in enumerate(palettes):
colors = []
for j, color in enumerate(palette):
if not isinstance(color, tuple) or len(color) != 4:
raise ColorLibError(
f"In palette[{i}][{j}]: expected (R, G, B, A) tuple, got {color!r}"
)
if any(v > 1 or v < 0 for v in color):
raise ColorLibError(
f"palette[{i}][{j}] has invalid out-of-range [0..1] color: {color!r}"
)
# input colors are RGBA, CPAL encodes them as BGRA
red, green, blue, alpha = color
colors.append(Color(*(round(v * 255) for v in (blue, green, red, alpha))))
cpal.palettes.append(colors)
if any(v is not None for v in (paletteTypes, paletteLabels, paletteEntryLabels)):
cpal.version = 1
if paletteTypes is not None:
if len(paletteTypes) != len(palettes):
raise ColorLibError(
f"Expected {len(palettes)} paletteTypes, got {len(paletteTypes)}"
)
cpal.paletteTypes = [ColorPaletteType(t).value for t in paletteTypes]
else:
cpal.paletteTypes = [table_C_P_A_L_.DEFAULT_PALETTE_TYPE] * len(palettes)
if paletteLabels is not None:
if len(paletteLabels) != len(palettes):
raise ColorLibError(
f"Expected {len(palettes)} paletteLabels, got {len(paletteLabels)}"
)
cpal.paletteLabels = buildPaletteLabels(paletteLabels, nameTable)
else:
cpal.paletteLabels = [table_C_P_A_L_.NO_NAME_ID] * len(palettes)
if paletteEntryLabels is not None:
if len(paletteEntryLabels) != cpal.numPaletteEntries:
raise ColorLibError(
f"Expected {cpal.numPaletteEntries} paletteEntryLabels, "
f"got {len(paletteEntryLabels)}"
)
cpal.paletteEntryLabels = buildPaletteLabels(paletteEntryLabels, nameTable)
else:
cpal.paletteEntryLabels = [
table_C_P_A_L_.NO_NAME_ID
] * cpal.numPaletteEntries
else:
cpal.version = 0
return cpal

View File

@ -0,0 +1,3 @@
class ColorLibError(Exception):
pass

View File

@ -768,6 +768,39 @@ class FontBuilder(object):
self.font, conditionalSubstitutions, featureTag=featureTag self.font, conditionalSubstitutions, featureTag=featureTag
) )
def setupCOLR(self, colorLayers):
"""Build new COLR table using color layers dictionary.
Cf. `fontTools.colorLib.builder.buildCOLR`.
"""
from fontTools.colorLib.builder import buildCOLR
self.font["COLR"] = buildCOLR(colorLayers)
def setupCPAL(
self,
palettes,
paletteTypes=None,
paletteLabels=None,
paletteEntryLabels=None,
):
"""Build new CPAL table using list of palettes.
Optionally build CPAL v1 table using paletteTypes, paletteLabels and
paletteEntryLabels.
Cf. `fontTools.colorLib.builder.buildCPAL`.
"""
from fontTools.colorLib.builder import buildCPAL
self.font["CPAL"] = buildCPAL(
palettes,
paletteTypes=paletteTypes,
paletteLabels=paletteLabels,
paletteEntryLabels=paletteEntryLabels,
nameTable=self.font.get("name")
)
def buildCmapSubTable(cmapping, format, platformID, platEncID): def buildCmapSubTable(cmapping, format, platformID, platEncID):
subTable = cmap_classes[format](format) subTable = cmap_classes[format](format)

View File

@ -13,6 +13,9 @@ import sys
class table_C_P_A_L_(DefaultTable.DefaultTable): class table_C_P_A_L_(DefaultTable.DefaultTable):
NO_NAME_ID = 0xFFFF
DEFAULT_PALETTE_TYPE = 0
def __init__(self, tag=None): def __init__(self, tag=None):
DefaultTable.DefaultTable.__init__(self, tag) DefaultTable.DefaultTable.__init__(self, tag)
self.palettes = [] self.palettes = []
@ -45,24 +48,25 @@ class table_C_P_A_L_(DefaultTable.DefaultTable):
offsetToPaletteEntryLabelArray) = ( offsetToPaletteEntryLabelArray) = (
struct.unpack(">LLL", data[pos:pos+12])) struct.unpack(">LLL", data[pos:pos+12]))
self.paletteTypes = self._decompileUInt32Array( self.paletteTypes = self._decompileUInt32Array(
data, offsetToPaletteTypeArray, numPalettes) data, offsetToPaletteTypeArray, numPalettes,
default=self.DEFAULT_PALETTE_TYPE)
self.paletteLabels = self._decompileUInt16Array( self.paletteLabels = self._decompileUInt16Array(
data, offsetToPaletteLabelArray, numPalettes) data, offsetToPaletteLabelArray, numPalettes, default=self.NO_NAME_ID)
self.paletteEntryLabels = self._decompileUInt16Array( self.paletteEntryLabels = self._decompileUInt16Array(
data, offsetToPaletteEntryLabelArray, data, offsetToPaletteEntryLabelArray,
self.numPaletteEntries) self.numPaletteEntries, default=self.NO_NAME_ID)
def _decompileUInt16Array(self, data, offset, numElements): def _decompileUInt16Array(self, data, offset, numElements, default=0):
if offset == 0: if offset == 0:
return [0] * numElements return [default] * numElements
result = array.array("H", data[offset : offset + 2 * numElements]) result = array.array("H", data[offset : offset + 2 * numElements])
if sys.byteorder != "big": result.byteswap() if sys.byteorder != "big": result.byteswap()
assert len(result) == numElements, result assert len(result) == numElements, result
return result.tolist() return result.tolist()
def _decompileUInt32Array(self, data, offset, numElements): def _decompileUInt32Array(self, data, offset, numElements, default=0):
if offset == 0: if offset == 0:
return [0] * numElements return [default] * numElements
result = array.array("I", data[offset : offset + 4 * numElements]) result = array.array("I", data[offset : offset + 4 * numElements])
if sys.byteorder != "big": result.byteswap() if sys.byteorder != "big": result.byteswap()
assert len(result) == numElements, result assert len(result) == numElements, result
@ -136,7 +140,7 @@ class table_C_P_A_L_(DefaultTable.DefaultTable):
return result return result
def _compilePaletteLabels(self): def _compilePaletteLabels(self):
if self.version == 0 or not any(self.paletteLabels): if self.version == 0 or all(l == self.NO_NAME_ID for l in self.paletteLabels):
return b'' return b''
assert len(self.paletteLabels) == len(self.palettes) assert len(self.paletteLabels) == len(self.palettes)
result = bytesjoin([struct.pack(">H", label) result = bytesjoin([struct.pack(">H", label)
@ -145,7 +149,7 @@ class table_C_P_A_L_(DefaultTable.DefaultTable):
return result return result
def _compilePaletteEntryLabels(self): def _compilePaletteEntryLabels(self):
if self.version == 0 or not any(self.paletteEntryLabels): if self.version == 0 or all(l == self.NO_NAME_ID for l in self.paletteEntryLabels):
return b'' return b''
assert len(self.paletteEntryLabels) == self.numPaletteEntries assert len(self.paletteEntryLabels) == self.numPaletteEntries
result = bytesjoin([struct.pack(">H", label) result = bytesjoin([struct.pack(">H", label)
@ -165,15 +169,15 @@ class table_C_P_A_L_(DefaultTable.DefaultTable):
writer.newline() writer.newline()
for index, palette in enumerate(self.palettes): for index, palette in enumerate(self.palettes):
attrs = {"index": index} attrs = {"index": index}
paletteType = paletteTypes.get(index) paletteType = paletteTypes.get(index, self.DEFAULT_PALETTE_TYPE)
paletteLabel = paletteLabels.get(index) paletteLabel = paletteLabels.get(index, self.NO_NAME_ID)
if self.version > 0 and paletteLabel is not None: if self.version > 0 and paletteLabel != self.NO_NAME_ID:
attrs["label"] = paletteLabel attrs["label"] = paletteLabel
if self.version > 0 and paletteType is not None: if self.version > 0 and paletteType != self.DEFAULT_PALETTE_TYPE:
attrs["type"] = paletteType attrs["type"] = paletteType
writer.begintag("palette", **attrs) writer.begintag("palette", **attrs)
writer.newline() writer.newline()
if (self.version > 0 and paletteLabel and if (self.version > 0 and paletteLabel != self.NO_NAME_ID and
ttFont and "name" in ttFont): ttFont and "name" in ttFont):
name = ttFont["name"].getDebugName(paletteLabel) name = ttFont["name"].getDebugName(paletteLabel)
if name is not None: if name is not None:
@ -184,11 +188,11 @@ class table_C_P_A_L_(DefaultTable.DefaultTable):
color.toXML(writer, ttFont, cindex) color.toXML(writer, ttFont, cindex)
writer.endtag("palette") writer.endtag("palette")
writer.newline() writer.newline()
if self.version > 0 and any(self.paletteEntryLabels): if self.version > 0 and not all(l == self.NO_NAME_ID for l in self.paletteEntryLabels):
writer.begintag("paletteEntryLabels") writer.begintag("paletteEntryLabels")
writer.newline() writer.newline()
for index, label in enumerate(self.paletteEntryLabels): for index, label in enumerate(self.paletteEntryLabels):
if label: if label != self.NO_NAME_ID:
writer.simpletag("label", index=index, value=label) writer.simpletag("label", index=index, value=label)
if (self.version > 0 and label and ttFont and "name" in ttFont): if (self.version > 0 and label and ttFont and "name" in ttFont):
name = ttFont["name"].getDebugName(label) name = ttFont["name"].getDebugName(label)
@ -200,8 +204,8 @@ class table_C_P_A_L_(DefaultTable.DefaultTable):
def fromXML(self, name, attrs, content, ttFont): def fromXML(self, name, attrs, content, ttFont):
if name == "palette": if name == "palette":
self.paletteLabels.append(int(attrs.get("label", "0"))) self.paletteLabels.append(int(attrs.get("label", self.NO_NAME_ID)))
self.paletteTypes.append(int(attrs.get("type", "0"))) self.paletteTypes.append(int(attrs.get("type", self.DEFAULT_PALETTE_TYPE)))
palette = [] palette = []
for element in content: for element in content:
if isinstance(element, basestring): if isinstance(element, basestring):
@ -221,13 +225,13 @@ class table_C_P_A_L_(DefaultTable.DefaultTable):
nameID = safeEval(elementAttr["value"]) nameID = safeEval(elementAttr["value"])
colorLabels[labelIndex] = nameID colorLabels[labelIndex] = nameID
self.paletteEntryLabels = [ self.paletteEntryLabels = [
colorLabels.get(i, 0) colorLabels.get(i, self.NO_NAME_ID)
for i in range(self.numPaletteEntries)] for i in range(self.numPaletteEntries)]
elif "value" in attrs: elif "value" in attrs:
value = safeEval(attrs["value"]) value = safeEval(attrs["value"])
setattr(self, name, value) setattr(self, name, value)
if name == "numPaletteEntries": if name == "numPaletteEntries":
self.paletteEntryLabels = [0] * self.numPaletteEntries self.paletteEntryLabels = [self.NO_NAME_ID] * self.numPaletteEntries
class Color(namedtuple("Color", "blue green red alpha")): class Color(namedtuple("Color", "blue green red alpha")):

View File

View File

@ -0,0 +1,187 @@
from fontTools.ttLib import newTable
from fontTools.colorLib import builder
from fontTools.colorLib.errors import ColorLibError
import pytest
def test_buildCOLR_v0():
color_layer_lists = {
"a": [("a.color0", 0), ("a.color1", 1)],
"b": [("b.color1", 1), ("b.color0", 0)],
}
colr = builder.buildCOLR(color_layer_lists)
assert colr.tableTag == "COLR"
assert colr.version == 0
assert colr.ColorLayers["a"][0].name == "a.color0"
assert colr.ColorLayers["a"][0].colorID == 0
assert colr.ColorLayers["a"][1].name == "a.color1"
assert colr.ColorLayers["a"][1].colorID == 1
assert colr.ColorLayers["b"][0].name == "b.color1"
assert colr.ColorLayers["b"][0].colorID == 1
assert colr.ColorLayers["b"][1].name == "b.color0"
assert colr.ColorLayers["b"][1].colorID == 0
def test_buildCPAL_v0():
palettes = [
[(0.68, 0.20, 0.32, 1.0), (0.45, 0.68, 0.21, 1.0)],
[(0.68, 0.20, 0.32, 0.6), (0.45, 0.68, 0.21, 0.6)],
[(0.68, 0.20, 0.32, 0.3), (0.45, 0.68, 0.21, 0.3)],
]
cpal = builder.buildCPAL(palettes)
assert cpal.tableTag == "CPAL"
assert cpal.version == 0
assert cpal.numPaletteEntries == 2
assert len(cpal.palettes) == 3
assert [tuple(c) for c in cpal.palettes[0]] == [
(82, 51, 173, 255),
(54, 173, 115, 255),
]
assert [tuple(c) for c in cpal.palettes[1]] == [
(82, 51, 173, 153),
(54, 173, 115, 153),
]
assert [tuple(c) for c in cpal.palettes[2]] == [
(82, 51, 173, 76),
(54, 173, 115, 76),
]
def test_buildCPAL_palettes_different_lengths():
with pytest.raises(ColorLibError, match="have different lengths"):
builder.buildCPAL([[(1, 1, 1, 1)], [(0, 0, 0, 1), (0.5, 0.5, 0.5, 1)]])
def test_buildPaletteLabels():
name_table = newTable("name")
name_table.names = []
name_ids = builder.buildPaletteLabels(
[None, "hi", {"en": "hello", "de": "hallo"}], name_table
)
assert name_ids == [0xFFFF, 256, 257]
assert len(name_table.names) == 3
assert str(name_table.names[0]) == "hi"
assert name_table.names[0].nameID == 256
assert str(name_table.names[1]) == "hallo"
assert name_table.names[1].nameID == 257
assert str(name_table.names[2]) == "hello"
assert name_table.names[2].nameID == 257
def test_build_CPAL_v1_types_no_labels():
palettes = [
[(0.1, 0.2, 0.3, 1.0), (0.4, 0.5, 0.6, 1.0)],
[(0.1, 0.2, 0.3, 0.6), (0.4, 0.5, 0.6, 0.6)],
[(0.1, 0.2, 0.3, 0.3), (0.4, 0.5, 0.6, 0.3)],
]
paletteTypes = [
builder.ColorPaletteType.USABLE_WITH_LIGHT_BACKGROUND,
builder.ColorPaletteType.USABLE_WITH_DARK_BACKGROUND,
builder.ColorPaletteType.USABLE_WITH_LIGHT_BACKGROUND
| builder.ColorPaletteType.USABLE_WITH_DARK_BACKGROUND,
]
cpal = builder.buildCPAL(palettes, paletteTypes=paletteTypes)
assert cpal.tableTag == "CPAL"
assert cpal.version == 1
assert cpal.numPaletteEntries == 2
assert len(cpal.palettes) == 3
assert cpal.paletteTypes == paletteTypes
assert cpal.paletteLabels == [cpal.NO_NAME_ID] * len(palettes)
assert cpal.paletteEntryLabels == [cpal.NO_NAME_ID] * cpal.numPaletteEntries
def test_build_CPAL_v1_labels():
palettes = [
[(0.1, 0.2, 0.3, 1.0), (0.4, 0.5, 0.6, 1.0)],
[(0.1, 0.2, 0.3, 0.6), (0.4, 0.5, 0.6, 0.6)],
[(0.1, 0.2, 0.3, 0.3), (0.4, 0.5, 0.6, 0.3)],
]
paletteLabels = ["First", {"en": "Second", "it": "Seconda"}, None]
paletteEntryLabels = ["Foo", "Bar"]
with pytest.raises(TypeError, match="nameTable is required"):
builder.buildCPAL(palettes, paletteLabels=paletteLabels)
with pytest.raises(TypeError, match="nameTable is required"):
builder.buildCPAL(palettes, paletteEntryLabels=paletteEntryLabels)
name_table = newTable("name")
name_table.names = []
cpal = builder.buildCPAL(
palettes,
paletteLabels=paletteLabels,
paletteEntryLabels=paletteEntryLabels,
nameTable=name_table,
)
assert cpal.tableTag == "CPAL"
assert cpal.version == 1
assert cpal.numPaletteEntries == 2
assert len(cpal.palettes) == 3
assert cpal.paletteTypes == [cpal.DEFAULT_PALETTE_TYPE] * len(palettes)
assert cpal.paletteLabels == [256, 257, cpal.NO_NAME_ID]
assert cpal.paletteEntryLabels == [258, 259]
assert name_table.getDebugName(256) == "First"
assert name_table.getDebugName(257) == "Second"
assert name_table.getDebugName(258) == "Foo"
assert name_table.getDebugName(259) == "Bar"
def test_invalid_ColorPaletteType():
with pytest.raises(ValueError, match="not a valid ColorPaletteType"):
builder.ColorPaletteType(-1)
with pytest.raises(ValueError, match="not a valid ColorPaletteType"):
builder.ColorPaletteType(4)
with pytest.raises(ValueError, match="not a valid ColorPaletteType"):
builder.ColorPaletteType("abc")
def test_buildCPAL_v1_invalid_args_length():
with pytest.raises(ColorLibError, match="Expected 2 paletteTypes, got 1"):
builder.buildCPAL([[(0, 0, 0, 0)], [(1, 1, 1, 1)]], paletteTypes=[1])
with pytest.raises(ColorLibError, match="Expected 2 paletteLabels, got 1"):
builder.buildCPAL(
[[(0, 0, 0, 0)], [(1, 1, 1, 1)]],
paletteLabels=["foo"],
nameTable=newTable("name"),
)
with pytest.raises(ColorLibError, match="Expected 1 paletteEntryLabels, got 0"):
cpal = builder.buildCPAL(
[[(0, 0, 0, 0)], [(1, 1, 1, 1)]],
paletteEntryLabels=[],
nameTable=newTable("name"),
)
def test_buildCPAL_invalid_color():
with pytest.raises(
ColorLibError,
match=r"In palette\[0\]\[1\]: expected \(R, G, B, A\) tuple, got \(1, 1, 1\)",
):
builder.buildCPAL([[(1, 1, 1, 1), (1, 1, 1)]])
with pytest.raises(
ColorLibError,
match=(
r"palette\[1\]\[0\] has invalid out-of-range "
r"\[0..1\] color: \(1, 1, -1, 2\)"
),
):
builder.buildCPAL([[(0, 0, 0, 0)], [(1, 1, -1, 2)]])

View File

@ -66,9 +66,6 @@ class CPALTest(unittest.TestCase):
self.assertEqual(cpal.numPaletteEntries, 2) self.assertEqual(cpal.numPaletteEntries, 2)
self.assertEqual(repr(cpal.palettes), self.assertEqual(repr(cpal.palettes),
'[[#000000FF, #66CCFFFF], [#000000FF, #800000FF]]') '[[#000000FF, #66CCFFFF], [#000000FF, #800000FF]]')
self.assertEqual(cpal.paletteLabels, [0, 0])
self.assertEqual(cpal.paletteTypes, [0, 0])
self.assertEqual(cpal.paletteEntryLabels, [0, 0])
def test_decompile_v0_sharingColors(self): def test_decompile_v0_sharingColors(self):
cpal = newTable('CPAL') cpal = newTable('CPAL')
@ -80,9 +77,6 @@ class CPALTest(unittest.TestCase):
'[#223344FF, #99887711, #55555555]', '[#223344FF, #99887711, #55555555]',
'[#223344FF, #99887711, #FFFFFFFF]', '[#223344FF, #99887711, #FFFFFFFF]',
'[#223344FF, #99887711, #55555555]']) '[#223344FF, #99887711, #55555555]'])
self.assertEqual(cpal.paletteLabels, [0, 0, 0, 0])
self.assertEqual(cpal.paletteTypes, [0, 0, 0, 0])
self.assertEqual(cpal.paletteEntryLabels, [0, 0, 0])
def test_decompile_v1_noLabelsNoTypes(self): def test_decompile_v1_noLabelsNoTypes(self):
cpal = newTable('CPAL') cpal = newTable('CPAL')
@ -92,9 +86,10 @@ class CPALTest(unittest.TestCase):
self.assertEqual([repr(p) for p in cpal.palettes], [ self.assertEqual([repr(p) for p in cpal.palettes], [
'[#CAFECAFE, #22110033, #66554477]', # RGBA '[#CAFECAFE, #22110033, #66554477]', # RGBA
'[#59413127, #42424242, #13330037]']) '[#59413127, #42424242, #13330037]'])
self.assertEqual(cpal.paletteLabels, [0, 0]) self.assertEqual(cpal.paletteLabels, [cpal.NO_NAME_ID] * len(cpal.palettes))
self.assertEqual(cpal.paletteTypes, [0, 0]) self.assertEqual(cpal.paletteTypes, [0, 0])
self.assertEqual(cpal.paletteEntryLabels, [0, 0, 0]) self.assertEqual(cpal.paletteEntryLabels,
[cpal.NO_NAME_ID] * cpal.numPaletteEntries)
def test_decompile_v1(self): def test_decompile_v1(self):
cpal = newTable('CPAL') cpal = newTable('CPAL')
@ -194,9 +189,6 @@ class CPALTest(unittest.TestCase):
self.assertEqual(cpal.version, 0) self.assertEqual(cpal.version, 0)
self.assertEqual(cpal.numPaletteEntries, 2) self.assertEqual(cpal.numPaletteEntries, 2)
self.assertEqual(repr(cpal.palettes), '[[#12345678, #FEDCBA98]]') self.assertEqual(repr(cpal.palettes), '[[#12345678, #FEDCBA98]]')
self.assertEqual(cpal.paletteLabels, [0])
self.assertEqual(cpal.paletteTypes, [0])
self.assertEqual(cpal.paletteEntryLabels, [0, 0])
def test_fromXML_v1(self): def test_fromXML_v1(self):
cpal = newTable('CPAL') cpal = newTable('CPAL')
@ -218,7 +210,8 @@ class CPALTest(unittest.TestCase):
'[[#12345678, #FEDCBA98, #CAFECAFE]]') '[[#12345678, #FEDCBA98, #CAFECAFE]]')
self.assertEqual(cpal.paletteLabels, [259]) self.assertEqual(cpal.paletteLabels, [259])
self.assertEqual(cpal.paletteTypes, [2]) self.assertEqual(cpal.paletteTypes, [2])
self.assertEqual(cpal.paletteEntryLabels, [0, 262, 0]) self.assertEqual(cpal.paletteEntryLabels,
[cpal.NO_NAME_ID, 262, cpal.NO_NAME_ID])
if __name__ == "__main__": if __name__ == "__main__":