colorLib: update builders to latest COLRv1 draft
LayerV1Record and Affine2x2 are gone. LayerV1List now contains a list of Paint DAGs Added 4 new Paint formats: PaintGlyph, PaintColorGlyph, PaintTransform and PaintComposite
This commit is contained in:
parent
7f6a05b007
commit
fdf6a5c1fc
@ -6,13 +6,26 @@ import collections
|
|||||||
import copy
|
import copy
|
||||||
import enum
|
import enum
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Any, Dict, Iterable, List, Mapping, Optional, Sequence, Tuple, Union
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Dict,
|
||||||
|
Iterable,
|
||||||
|
List,
|
||||||
|
Mapping,
|
||||||
|
Optional,
|
||||||
|
Sequence,
|
||||||
|
Tuple,
|
||||||
|
Type,
|
||||||
|
TypeVar,
|
||||||
|
Union,
|
||||||
|
)
|
||||||
from fontTools.ttLib.tables import C_O_L_R_
|
from fontTools.ttLib.tables import C_O_L_R_
|
||||||
from fontTools.ttLib.tables import C_P_A_L_
|
from fontTools.ttLib.tables import C_P_A_L_
|
||||||
from fontTools.ttLib.tables import _n_a_m_e
|
from fontTools.ttLib.tables import _n_a_m_e
|
||||||
from fontTools.ttLib.tables import otTables as ot
|
from fontTools.ttLib.tables import otTables as ot
|
||||||
from fontTools.ttLib.tables.otTables import (
|
from fontTools.ttLib.tables.otTables import (
|
||||||
ExtendMode,
|
ExtendMode,
|
||||||
|
CompositeMode,
|
||||||
VariableValue,
|
VariableValue,
|
||||||
VariableFloat,
|
VariableFloat,
|
||||||
VariableInt,
|
VariableInt,
|
||||||
@ -21,11 +34,11 @@ from .errors import ColorLibError
|
|||||||
|
|
||||||
|
|
||||||
# TODO move type aliases to colorLib.types?
|
# TODO move type aliases to colorLib.types?
|
||||||
|
T = TypeVar("T")
|
||||||
_Kwargs = Mapping[str, Any]
|
_Kwargs = Mapping[str, Any]
|
||||||
_PaintInput = Union[int, _Kwargs, ot.Paint]
|
_PaintInput = Union[int, _Kwargs, ot.Paint, Tuple[str, "_PaintInput"]]
|
||||||
_LayerTuple = Tuple[str, _PaintInput]
|
_PaintInputList = Sequence[_PaintInput]
|
||||||
_LayersList = Sequence[_LayerTuple]
|
_ColorGlyphsDict = Dict[str, Union[_PaintInputList, ot.LayerV1List]]
|
||||||
_ColorGlyphsDict = Dict[str, _LayersList]
|
|
||||||
_ColorGlyphsV0Dict = Dict[str, Sequence[Tuple[str, int]]]
|
_ColorGlyphsV0Dict = Dict[str, Sequence[Tuple[str, int]]]
|
||||||
_Number = Union[int, float]
|
_Number = Union[int, float]
|
||||||
_ScalarInput = Union[_Number, VariableValue, Tuple[_Number, int]]
|
_ScalarInput = Union[_Number, VariableValue, Tuple[_Number, int]]
|
||||||
@ -33,10 +46,13 @@ _ColorStopTuple = Tuple[_ScalarInput, int]
|
|||||||
_ColorStopInput = Union[_ColorStopTuple, _Kwargs, ot.ColorStop]
|
_ColorStopInput = Union[_ColorStopTuple, _Kwargs, ot.ColorStop]
|
||||||
_ColorStopsList = Sequence[_ColorStopInput]
|
_ColorStopsList = Sequence[_ColorStopInput]
|
||||||
_ExtendInput = Union[int, str, ExtendMode]
|
_ExtendInput = Union[int, str, ExtendMode]
|
||||||
|
_CompositeInput = Union[int, str, CompositeMode]
|
||||||
_ColorLineInput = Union[_Kwargs, ot.ColorLine]
|
_ColorLineInput = Union[_Kwargs, ot.ColorLine]
|
||||||
_PointTuple = Tuple[_ScalarInput, _ScalarInput]
|
_PointTuple = Tuple[_ScalarInput, _ScalarInput]
|
||||||
_AffineTuple = Tuple[_ScalarInput, _ScalarInput, _ScalarInput, _ScalarInput]
|
_AffineTuple = Tuple[
|
||||||
_AffineInput = Union[_AffineTuple, ot.Affine2x2]
|
_ScalarInput, _ScalarInput, _ScalarInput, _ScalarInput, _ScalarInput, _ScalarInput
|
||||||
|
]
|
||||||
|
_AffineInput = Union[_AffineTuple, ot.Affine2x3]
|
||||||
|
|
||||||
|
|
||||||
def populateCOLRv0(
|
def populateCOLRv0(
|
||||||
@ -91,14 +107,13 @@ def buildCOLR(
|
|||||||
"""Build COLR table from color layers mapping.
|
"""Build COLR table from color layers mapping.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
colorGlyphs: map of base glyph names to lists of (layer glyph names,
|
colorGlyphs: map of base glyph name to, either list of (layer glyph name,
|
||||||
Paint) tuples. For COLRv0, a paint is simply the color palette index
|
color palette index) tuples for COLRv0; or list of Paints (dicts)
|
||||||
(int); for COLRv1, paint can be either solid colors (with variable
|
for COLRv1.
|
||||||
opacity), linear gradients or radial gradients.
|
|
||||||
version: the version of COLR table. If None, the version is determined
|
version: the version of COLR table. If None, the version is determined
|
||||||
by the presence of gradients or variation data (varStore), which
|
by the presence of COLRv1 paints or variation data (varStore), which
|
||||||
require version 1; otherwise, if there are only simple colors, version
|
require version 1; otherwise, if all base glyphs use only simple color
|
||||||
0 is used.
|
layers, version 0 is used.
|
||||||
glyphMap: a map from glyph names to glyph indices, as returned from
|
glyphMap: a map from glyph names to glyph indices, as returned from
|
||||||
TTFont.getReverseGlyphMap(), to optionally sort base records by GID.
|
TTFont.getReverseGlyphMap(), to optionally sort base records by GID.
|
||||||
varStore: Optional ItemVarationStore for deltas associated with v1 layer.
|
varStore: Optional ItemVarationStore for deltas associated with v1 layer.
|
||||||
@ -113,10 +128,9 @@ def buildCOLR(
|
|||||||
|
|
||||||
if version in (None, 0) and not varStore:
|
if version in (None, 0) and not varStore:
|
||||||
# split color glyphs into v0 and v1 and encode separately
|
# split color glyphs into v0 and v1 and encode separately
|
||||||
colorGlyphsV0, colorGlyphsV1 = _splitSolidAndGradientGlyphs(colorGlyphs)
|
colorGlyphsV0, colorGlyphsV1 = _split_color_glyphs_by_version(colorGlyphs)
|
||||||
if version == 0 and colorGlyphsV1:
|
if version == 0 and colorGlyphsV1:
|
||||||
# TODO Derive "average" solid color from gradients?
|
raise ValueError("Can't encode COLRv1 glyphs in COLRv0")
|
||||||
raise ValueError("Can't encode gradients in COLRv0")
|
|
||||||
else:
|
else:
|
||||||
# unless explicitly requested for v1 or have variations, in which case
|
# unless explicitly requested for v1 or have variations, in which case
|
||||||
# we encode all color glyph as v1
|
# we encode all color glyph as v1
|
||||||
@ -277,29 +291,16 @@ def buildCPAL(
|
|||||||
_DEFAULT_ALPHA = VariableFloat(1.0)
|
_DEFAULT_ALPHA = VariableFloat(1.0)
|
||||||
|
|
||||||
|
|
||||||
def _splitSolidAndGradientGlyphs(
|
def _split_color_glyphs_by_version(
|
||||||
colorGlyphs: _ColorGlyphsDict,
|
colorGlyphs: _ColorGlyphsDict,
|
||||||
) -> Tuple[Dict[str, List[Tuple[str, int]]], Dict[str, List[Tuple[str, ot.Paint]]]]:
|
) -> Tuple[_ColorGlyphsV0Dict, _ColorGlyphsDict]:
|
||||||
colorGlyphsV0 = {}
|
colorGlyphsV0 = {}
|
||||||
colorGlyphsV1 = {}
|
colorGlyphsV1 = {}
|
||||||
for baseGlyph, layers in colorGlyphs.items():
|
for baseGlyph, layers in colorGlyphs.items():
|
||||||
newLayers = []
|
if all(isinstance(l, tuple) and isinstance(l[1], int) for l in layers):
|
||||||
allSolidColors = True
|
colorGlyphsV0[baseGlyph] = layers
|
||||||
for layerGlyph, paint in layers:
|
|
||||||
paint = _to_ot_paint(paint)
|
|
||||||
if (
|
|
||||||
paint.Format != 1
|
|
||||||
or paint.Color.Alpha.value != _DEFAULT_ALPHA.value
|
|
||||||
):
|
|
||||||
allSolidColors = False
|
|
||||||
newLayers.append((layerGlyph, paint))
|
|
||||||
if allSolidColors:
|
|
||||||
colorGlyphsV0[baseGlyph] = [
|
|
||||||
(layerGlyph, paint.Color.PaletteIndex)
|
|
||||||
for layerGlyph, paint in newLayers
|
|
||||||
]
|
|
||||||
else:
|
else:
|
||||||
colorGlyphsV1[baseGlyph] = newLayers
|
colorGlyphsV1[baseGlyph] = layers
|
||||||
|
|
||||||
# sanity check
|
# sanity check
|
||||||
assert set(colorGlyphs) == (set(colorGlyphsV0) | set(colorGlyphsV1))
|
assert set(colorGlyphs) == (set(colorGlyphsV0) | set(colorGlyphsV1))
|
||||||
@ -351,15 +352,23 @@ def buildColorStop(
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
def _to_extend_mode(v: _ExtendInput) -> ExtendMode:
|
def _to_enum_value(v: Union[str, int, T], enumClass: Type[T]) -> T:
|
||||||
if isinstance(v, ExtendMode):
|
if isinstance(v, enumClass):
|
||||||
return v
|
return v
|
||||||
elif isinstance(v, str):
|
elif isinstance(v, str):
|
||||||
try:
|
try:
|
||||||
return getattr(ExtendMode, v.upper())
|
return getattr(enumClass, v.upper())
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise ValueError(f"{v!r} is not a valid ExtendMode")
|
raise ValueError(f"{v!r} is not a valid {enumClass.__name__}")
|
||||||
return ExtendMode(v)
|
return enumClass(v)
|
||||||
|
|
||||||
|
|
||||||
|
def _to_extend_mode(v: _ExtendInput) -> ExtendMode:
|
||||||
|
return _to_enum_value(v, ExtendMode)
|
||||||
|
|
||||||
|
|
||||||
|
def _to_composite_mode(v: _CompositeInput) -> CompositeMode:
|
||||||
|
return _to_enum_value(v, CompositeMode)
|
||||||
|
|
||||||
|
|
||||||
def buildColorLine(
|
def buildColorLine(
|
||||||
@ -406,12 +415,17 @@ def buildLinearGradientPaint(
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
def buildAffine2x2(
|
def buildAffine2x3(
|
||||||
xx: _ScalarInput, xy: _ScalarInput, yx: _ScalarInput, yy: _ScalarInput
|
xx: _ScalarInput,
|
||||||
) -> ot.Affine2x2:
|
xy: _ScalarInput,
|
||||||
self = ot.Affine2x2()
|
yx: _ScalarInput,
|
||||||
|
yy: _ScalarInput,
|
||||||
|
dx: _ScalarInput,
|
||||||
|
dy: _ScalarInput,
|
||||||
|
) -> ot.Affine2x3:
|
||||||
|
self = ot.Affine2x3()
|
||||||
locs = locals()
|
locs = locals()
|
||||||
for attr in ("xx", "xy", "yx", "yy"):
|
for attr in ("xx", "xy", "yx", "yy", "dx", "dy"):
|
||||||
value = locs[attr]
|
value = locs[attr]
|
||||||
setattr(self, attr, _to_variable_float(value))
|
setattr(self, attr, _to_variable_float(value))
|
||||||
return self
|
return self
|
||||||
@ -423,7 +437,6 @@ def buildRadialGradientPaint(
|
|||||||
c1: _PointTuple,
|
c1: _PointTuple,
|
||||||
r0: _ScalarInput,
|
r0: _ScalarInput,
|
||||||
r1: _ScalarInput,
|
r1: _ScalarInput,
|
||||||
transform: Optional[_AffineInput] = None,
|
|
||||||
) -> ot.Paint:
|
) -> ot.Paint:
|
||||||
|
|
||||||
self = ot.Paint()
|
self = ot.Paint()
|
||||||
@ -435,50 +448,86 @@ def buildRadialGradientPaint(
|
|||||||
setattr(self, f"y{i}", _to_variable_int(y))
|
setattr(self, f"y{i}", _to_variable_int(y))
|
||||||
setattr(self, f"r{i}", _to_variable_int(r))
|
setattr(self, f"r{i}", _to_variable_int(r))
|
||||||
|
|
||||||
if transform is not None and not isinstance(transform, ot.Affine2x2):
|
|
||||||
transform = buildAffine2x2(*transform)
|
|
||||||
self.Transform = transform
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
def _to_ot_paint(paint: _PaintInput) -> ot.Paint:
|
def buildPaintGlyph(glyph: str, paint: _PaintInput) -> ot.Paint:
|
||||||
|
self = ot.Paint()
|
||||||
|
self.Format = 4
|
||||||
|
self.Glyph = glyph
|
||||||
|
self.Paint = buildPaint(paint)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
def buildPaintColorGlyph(glyph: str) -> ot.Paint:
|
||||||
|
self = ot.Paint()
|
||||||
|
self.Format = 5
|
||||||
|
self.Glyph = glyph
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
def buildPaintTransform(transform: _AffineInput, paint: _PaintInput) -> ot.Paint:
|
||||||
|
self = ot.Paint()
|
||||||
|
self.Format = 6
|
||||||
|
if not isinstance(transform, ot.Affine2x3):
|
||||||
|
transform = buildAffine2x3(*transform)
|
||||||
|
self.Transform = transform
|
||||||
|
self.Paint = buildPaint(paint)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
def buildPaintComposite(
|
||||||
|
mode: _CompositeInput, source: _PaintInput, backdrop: _PaintInput
|
||||||
|
):
|
||||||
|
self = ot.Paint()
|
||||||
|
self.Format = 7
|
||||||
|
self.SourcePaint = buildPaint(source)
|
||||||
|
self.CompositeMode = _to_composite_mode(mode)
|
||||||
|
self.BackdropPaint = buildPaint(backdrop)
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
_PAINT_BUILDERS = {
|
||||||
|
1: buildSolidColorPaint,
|
||||||
|
2: buildLinearGradientPaint,
|
||||||
|
3: buildRadialGradientPaint,
|
||||||
|
4: buildPaintGlyph,
|
||||||
|
5: buildPaintColorGlyph,
|
||||||
|
6: buildPaintTransform,
|
||||||
|
7: buildPaintComposite,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def buildPaint(paint: _PaintInput) -> ot.Paint:
|
||||||
if isinstance(paint, ot.Paint):
|
if isinstance(paint, ot.Paint):
|
||||||
return paint
|
return paint
|
||||||
elif isinstance(paint, int):
|
elif isinstance(paint, int):
|
||||||
paletteIndex = paint
|
paletteIndex = paint
|
||||||
return buildSolidColorPaint(paletteIndex)
|
return buildSolidColorPaint(paletteIndex)
|
||||||
|
elif isinstance(paint, tuple):
|
||||||
|
layerGlyph, paint = paint
|
||||||
|
return buildPaintGlyph(layerGlyph, paint)
|
||||||
elif isinstance(paint, collections.abc.Mapping):
|
elif isinstance(paint, collections.abc.Mapping):
|
||||||
return buildPaint(**paint)
|
kwargs = dict(paint)
|
||||||
raise TypeError(f"expected int, Mapping or ot.Paint, found {type(paint.__name__)}")
|
fmt = kwargs.pop("format")
|
||||||
|
try:
|
||||||
|
return _PAINT_BUILDERS[fmt](**kwargs)
|
||||||
|
except KeyError:
|
||||||
|
raise NotImplementedError(fmt)
|
||||||
|
raise TypeError(
|
||||||
|
f"expected int, Mapping or ot.Paint, found {type(paint).__name__}: {paint!r}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def buildLayerV1Record(layerGlyph: str, paint: _PaintInput) -> ot.LayerV1Record:
|
def buildLayerV1List(layers: _PaintInputList) -> ot.LayerV1List:
|
||||||
self = ot.LayerV1Record()
|
|
||||||
self.LayerGlyph = layerGlyph
|
|
||||||
self.Paint = _to_ot_paint(paint)
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
def buildLayerV1List(
|
|
||||||
layers: Sequence[Union[_LayerTuple, ot.LayerV1Record]]
|
|
||||||
) -> ot.LayerV1List:
|
|
||||||
self = ot.LayerV1List()
|
self = ot.LayerV1List()
|
||||||
self.LayerCount = len(layers)
|
self.LayerCount = len(layers)
|
||||||
records = []
|
self.Paint = [buildPaint(layer) for layer in layers]
|
||||||
for layer in layers:
|
|
||||||
if isinstance(layer, ot.LayerV1Record):
|
|
||||||
record = layer
|
|
||||||
else:
|
|
||||||
layerGlyph, paint = layer
|
|
||||||
record = buildLayerV1Record(layerGlyph, paint)
|
|
||||||
records.append(record)
|
|
||||||
self.LayerV1Record = records
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
def buildBaseGlyphV1Record(
|
def buildBaseGlyphV1Record(
|
||||||
baseGlyph: str, layers: Union[_LayersList, ot.LayerV1List]
|
baseGlyph: str, layers: Union[_PaintInputList, ot.LayerV1List]
|
||||||
) -> ot.BaseGlyphV1List:
|
) -> ot.BaseGlyphV1List:
|
||||||
self = ot.BaseGlyphV1Record()
|
self = ot.BaseGlyphV1Record()
|
||||||
self.BaseGlyph = baseGlyph
|
self.BaseGlyph = baseGlyph
|
||||||
@ -489,7 +538,7 @@ def buildBaseGlyphV1Record(
|
|||||||
|
|
||||||
|
|
||||||
def buildBaseGlyphV1List(
|
def buildBaseGlyphV1List(
|
||||||
colorGlyphs: Union[_ColorGlyphsDict, Dict[str, ot.LayerV1List]],
|
colorGlyphs: _ColorGlyphsDict,
|
||||||
glyphMap: Optional[Mapping[str, int]] = None,
|
glyphMap: Optional[Mapping[str, int]] = None,
|
||||||
) -> ot.BaseGlyphV1List:
|
) -> ot.BaseGlyphV1List:
|
||||||
if glyphMap is not None:
|
if glyphMap is not None:
|
||||||
@ -506,17 +555,3 @@ def buildBaseGlyphV1List(
|
|||||||
self.BaseGlyphCount = len(records)
|
self.BaseGlyphCount = len(records)
|
||||||
self.BaseGlyphV1Record = records
|
self.BaseGlyphV1Record = records
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
_PAINT_BUILDERS = {
|
|
||||||
1: buildSolidColorPaint,
|
|
||||||
2: buildLinearGradientPaint,
|
|
||||||
3: buildRadialGradientPaint,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def buildPaint(format: int, **kwargs) -> ot.Paint:
|
|
||||||
try:
|
|
||||||
return _PAINT_BUILDERS[format](**kwargs)
|
|
||||||
except KeyError:
|
|
||||||
raise NotImplementedError(format)
|
|
||||||
|
@ -284,12 +284,14 @@ def test_buildColorLine():
|
|||||||
] == stops
|
] == stops
|
||||||
|
|
||||||
|
|
||||||
def test_buildAffine2x2():
|
def test_buildAffine2x3():
|
||||||
matrix = builder.buildAffine2x2(1.5, 0, 0.5, 2.0)
|
matrix = builder.buildAffine2x3(1.5, 0, 0.5, 2.0, 1.0, -3.0)
|
||||||
assert matrix.xx == builder.VariableFloat(1.5)
|
assert matrix.xx == builder.VariableFloat(1.5)
|
||||||
assert matrix.xy == builder.VariableFloat(0.0)
|
assert matrix.xy == builder.VariableFloat(0.0)
|
||||||
assert matrix.yx == builder.VariableFloat(0.5)
|
assert matrix.yx == builder.VariableFloat(0.5)
|
||||||
assert matrix.yy == builder.VariableFloat(2.0)
|
assert matrix.yy == builder.VariableFloat(2.0)
|
||||||
|
assert matrix.dx == builder.VariableFloat(1.0)
|
||||||
|
assert matrix.dy == builder.VariableFloat(-3.0)
|
||||||
|
|
||||||
|
|
||||||
def test_buildLinearGradientPaint():
|
def test_buildLinearGradientPaint():
|
||||||
@ -337,36 +339,24 @@ def test_buildRadialGradientPaint():
|
|||||||
assert (gradient.x1, gradient.y1) == c1
|
assert (gradient.x1, gradient.y1) == c1
|
||||||
assert gradient.r0 == r0
|
assert gradient.r0 == r0
|
||||||
assert gradient.r1 == r1
|
assert gradient.r1 == r1
|
||||||
assert gradient.Transform is None
|
|
||||||
|
|
||||||
gradient = builder.buildRadialGradientPaint({"stops": color_stops}, c0, c1, r0, r1)
|
gradient = builder.buildRadialGradientPaint({"stops": color_stops}, c0, c1, r0, r1)
|
||||||
assert gradient.ColorLine.Extend == builder.ExtendMode.PAD
|
assert gradient.ColorLine.Extend == builder.ExtendMode.PAD
|
||||||
assert gradient.ColorLine.ColorStop == color_stops
|
assert gradient.ColorLine.ColorStop == color_stops
|
||||||
|
|
||||||
matrix = builder.buildAffine2x2(2.0, 0.0, 0.0, 2.0)
|
|
||||||
gradient = builder.buildRadialGradientPaint(
|
|
||||||
color_line, c0, c1, r0, r1, transform=matrix
|
|
||||||
)
|
|
||||||
assert gradient.Transform == matrix
|
|
||||||
|
|
||||||
gradient = builder.buildRadialGradientPaint(
|
def test_buildPaintGlyph():
|
||||||
color_line, c0, c1, r0, r1, transform=(2.0, 0.0, 0.0, 2.0)
|
layer = builder.buildPaintGlyph("a", 2)
|
||||||
)
|
assert layer.Glyph == "a"
|
||||||
assert gradient.Transform == matrix
|
|
||||||
|
|
||||||
|
|
||||||
def test_buildLayerV1Record():
|
|
||||||
layer = builder.buildLayerV1Record("a", 2)
|
|
||||||
assert layer.LayerGlyph == "a"
|
|
||||||
assert layer.Paint.Format == 1
|
assert layer.Paint.Format == 1
|
||||||
assert layer.Paint.Color.PaletteIndex == 2
|
assert layer.Paint.Color.PaletteIndex == 2
|
||||||
|
|
||||||
layer = builder.buildLayerV1Record("a", builder.buildSolidColorPaint(3, 0.9))
|
layer = builder.buildPaintGlyph("a", builder.buildSolidColorPaint(3, 0.9))
|
||||||
assert layer.Paint.Format == 1
|
assert layer.Paint.Format == 1
|
||||||
assert layer.Paint.Color.PaletteIndex == 3
|
assert layer.Paint.Color.PaletteIndex == 3
|
||||||
assert layer.Paint.Color.Alpha.value == 0.9
|
assert layer.Paint.Color.Alpha.value == 0.9
|
||||||
|
|
||||||
layer = builder.buildLayerV1Record(
|
layer = builder.buildPaintGlyph(
|
||||||
"a",
|
"a",
|
||||||
builder.buildLinearGradientPaint(
|
builder.buildLinearGradientPaint(
|
||||||
{"stops": [(0.0, 3), (1.0, 4)]}, (100, 200), (150, 250)
|
{"stops": [(0.0, 3), (1.0, 4)]}, (100, 200), (150, 250)
|
||||||
@ -382,7 +372,7 @@ def test_buildLayerV1Record():
|
|||||||
assert layer.Paint.x1.value == 150
|
assert layer.Paint.x1.value == 150
|
||||||
assert layer.Paint.y1.value == 250
|
assert layer.Paint.y1.value == 250
|
||||||
|
|
||||||
layer = builder.buildLayerV1Record(
|
layer = builder.buildPaintGlyph(
|
||||||
"a",
|
"a",
|
||||||
builder.buildRadialGradientPaint(
|
builder.buildRadialGradientPaint(
|
||||||
{
|
{
|
||||||
@ -414,13 +404,13 @@ def test_buildLayerV1Record():
|
|||||||
assert layer.Paint.r1.value == 10
|
assert layer.Paint.r1.value == 10
|
||||||
|
|
||||||
|
|
||||||
def test_buildLayerV1Record_from_dict():
|
def test_buildPaintGlyph_from_dict():
|
||||||
layer = builder.buildLayerV1Record("a", {"format": 1, "paletteIndex": 0})
|
layer = builder.buildPaintGlyph("a", {"format": 1, "paletteIndex": 0})
|
||||||
assert layer.LayerGlyph == "a"
|
assert layer.Glyph == "a"
|
||||||
assert layer.Paint.Format == 1
|
assert layer.Paint.Format == 1
|
||||||
assert layer.Paint.Color.PaletteIndex == 0
|
assert layer.Paint.Color.PaletteIndex == 0
|
||||||
|
|
||||||
layer = builder.buildLayerV1Record(
|
layer = builder.buildPaintGlyph(
|
||||||
"a",
|
"a",
|
||||||
{
|
{
|
||||||
"format": 2,
|
"format": 2,
|
||||||
@ -432,7 +422,7 @@ def test_buildLayerV1Record_from_dict():
|
|||||||
assert layer.Paint.Format == 2
|
assert layer.Paint.Format == 2
|
||||||
assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0
|
assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0
|
||||||
|
|
||||||
layer = builder.buildLayerV1Record(
|
layer = builder.buildPaintGlyph(
|
||||||
"a",
|
"a",
|
||||||
{
|
{
|
||||||
"format": 3,
|
"format": 3,
|
||||||
@ -477,12 +467,12 @@ def test_buildLayerV1List():
|
|||||||
"r1": 10,
|
"r1": 10,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
builder.buildLayerV1Record("e", builder.buildSolidColorPaint(8)),
|
builder.buildPaintGlyph("e", builder.buildSolidColorPaint(8)),
|
||||||
]
|
]
|
||||||
layers = builder.buildLayerV1List(layers)
|
layers = builder.buildLayerV1List(layers)
|
||||||
|
|
||||||
assert layers.LayerCount == len(layers.LayerV1Record)
|
assert layers.LayerCount == len(layers.Paint)
|
||||||
assert all(isinstance(l, ot.LayerV1Record) for l in layers.LayerV1Record)
|
assert all(isinstance(l, ot.Paint) for l in layers.Paint)
|
||||||
|
|
||||||
|
|
||||||
def test_buildBaseGlyphV1Record():
|
def test_buildBaseGlyphV1Record():
|
||||||
@ -540,17 +530,17 @@ def test_buildBaseGlyphV1List():
|
|||||||
assert baseGlyphs.BaseGlyphV1Record[2].BaseGlyph == "g"
|
assert baseGlyphs.BaseGlyphV1Record[2].BaseGlyph == "g"
|
||||||
|
|
||||||
|
|
||||||
def test_splitSolidAndGradientGlyphs():
|
def test_split_color_glyphs_by_version():
|
||||||
colorGlyphs = {
|
colorGlyphs = {
|
||||||
"a": [
|
"a": [
|
||||||
("b", 0),
|
("b", 0),
|
||||||
("c", 1),
|
("c", 1),
|
||||||
("d", {"format": 1, "paletteIndex": 2}),
|
("d", 2),
|
||||||
("e", builder.buildSolidColorPaint(paletteIndex=3)),
|
("e", 3),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
colorGlyphsV0, colorGlyphsV1 = builder._splitSolidAndGradientGlyphs(colorGlyphs)
|
colorGlyphsV0, colorGlyphsV1 = builder._split_color_glyphs_by_version(colorGlyphs)
|
||||||
|
|
||||||
assert colorGlyphsV0 == {"a": [("b", 0), ("c", 1), ("d", 2), ("e", 3)]}
|
assert colorGlyphsV0 == {"a": [("b", 0), ("c", 1), ("d", 2), ("e", 3)]}
|
||||||
assert not colorGlyphsV1
|
assert not colorGlyphsV1
|
||||||
@ -559,7 +549,7 @@ def test_splitSolidAndGradientGlyphs():
|
|||||||
"a": [("b", builder.buildSolidColorPaint(paletteIndex=0, alpha=0.0))]
|
"a": [("b", builder.buildSolidColorPaint(paletteIndex=0, alpha=0.0))]
|
||||||
}
|
}
|
||||||
|
|
||||||
colorGlyphsV0, colorGlyphsV1 = builder._splitSolidAndGradientGlyphs(colorGlyphs)
|
colorGlyphsV0, colorGlyphsV1 = builder._split_color_glyphs_by_version(colorGlyphs)
|
||||||
|
|
||||||
assert not colorGlyphsV0
|
assert not colorGlyphsV0
|
||||||
assert colorGlyphsV1 == colorGlyphs
|
assert colorGlyphsV1 == colorGlyphs
|
||||||
@ -580,23 +570,13 @@ def test_splitSolidAndGradientGlyphs():
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
colorGlyphsV0, colorGlyphsV1 = builder._splitSolidAndGradientGlyphs(colorGlyphs)
|
colorGlyphsV0, colorGlyphsV1 = builder._split_color_glyphs_by_version(colorGlyphs)
|
||||||
|
|
||||||
assert colorGlyphsV0 == {"a": [("b", 0)]}
|
assert colorGlyphsV0 == {"a": [("b", 0)]}
|
||||||
assert "a" not in colorGlyphsV1
|
assert "a" not in colorGlyphsV1
|
||||||
assert "c" in colorGlyphsV1
|
assert "c" in colorGlyphsV1
|
||||||
assert len(colorGlyphsV1["c"]) == 2
|
assert len(colorGlyphsV1["c"]) == 2
|
||||||
|
|
||||||
layer_d = colorGlyphsV1["c"][0]
|
|
||||||
assert layer_d[0] == "d"
|
|
||||||
assert isinstance(layer_d[1], ot.Paint)
|
|
||||||
assert layer_d[1].Format == 1
|
|
||||||
|
|
||||||
layer_e = colorGlyphsV1["c"][1]
|
|
||||||
assert layer_e[0] == "e"
|
|
||||||
assert isinstance(layer_e[1], ot.Paint)
|
|
||||||
assert layer_e[1].Format == 2
|
|
||||||
|
|
||||||
|
|
||||||
class BuildCOLRTest(object):
|
class BuildCOLRTest(object):
|
||||||
def test_automatic_version_all_solid_color_glyphs(self):
|
def test_automatic_version_all_solid_color_glyphs(self):
|
||||||
@ -691,9 +671,7 @@ class BuildCOLRTest(object):
|
|||||||
colr.table.BaseGlyphV1List.BaseGlyphV1Record[0].LayerV1List, ot.LayerV1List
|
colr.table.BaseGlyphV1List.BaseGlyphV1Record[0].LayerV1List, ot.LayerV1List
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
colr.table.BaseGlyphV1List.BaseGlyphV1Record[0]
|
colr.table.BaseGlyphV1List.BaseGlyphV1Record[0].LayerV1List.Paint[0].Glyph
|
||||||
.LayerV1List.LayerV1Record[0]
|
|
||||||
.LayerGlyph
|
|
||||||
== "e"
|
== "e"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user