move PaintFormat enum outside of Paint class nested scope

When a TTFont is loaded with lazy=True, the otTables are only loaded upon BaseTable.__getattr__
when the requested attribute is not found in the instance __dict__.
Since the Paint.Format enum was defined at class level, every Paint instance, even when loaded
lazily, will have a 'Format' attribute and the magic decompile-on-missing-attribute will not
trigger, since the class attribute will be returned when the instance is missing one.

For this reason, and to not add further special cases, it's better to simply move this Paint.Format
enum class outside to the module level scope, and rename it PaintFormat.
This commit is contained in:
Cosimo Lupo 2021-02-05 12:11:43 +00:00
parent 82c32cbf88
commit df672a7ae4
No known key found for this signature in database
GPG Key ID: 179A8F0895A02F4F
5 changed files with 92 additions and 91 deletions

View File

@ -492,7 +492,7 @@ class LayerV1ListBuilder:
self, paletteIndex: int, alpha: _ScalarInput = _DEFAULT_ALPHA
) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintSolid)
ot_paint.Format = int(ot.PaintFormat.PaintSolid)
ot_paint.Color = buildColorIndex(paletteIndex, alpha)
return ot_paint
@ -504,7 +504,7 @@ class LayerV1ListBuilder:
p2: Optional[_PointTuple] = None,
) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintLinearGradient)
ot_paint.Format = int(ot.PaintFormat.PaintLinearGradient)
ot_paint.ColorLine = _to_color_line(colorLine)
if p2 is None:
@ -525,7 +525,7 @@ class LayerV1ListBuilder:
) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintRadialGradient)
ot_paint.Format = int(ot.PaintFormat.PaintRadialGradient)
ot_paint.ColorLine = _to_color_line(colorLine)
# normalize input types (which may or may not specify a varIdx)
@ -558,7 +558,7 @@ class LayerV1ListBuilder:
endAngle: _ScalarInput,
) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintSweepGradient)
ot_paint.Format = int(ot.PaintFormat.PaintSweepGradient)
ot_paint.ColorLine = _to_color_line(colorLine)
ot_paint.centerX = _to_variable_int16(centerX)
ot_paint.centerY = _to_variable_int16(centerY)
@ -568,14 +568,14 @@ class LayerV1ListBuilder:
def buildPaintGlyph(self, glyph: str, paint: _PaintInput) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintGlyph)
ot_paint.Format = int(ot.PaintFormat.PaintGlyph)
ot_paint.Glyph = glyph
ot_paint.Paint = self.buildPaint(paint)
return ot_paint
def buildPaintColrGlyph(self, glyph: str) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintColrGlyph)
ot_paint.Format = int(ot.PaintFormat.PaintColrGlyph)
ot_paint.Glyph = glyph
return ot_paint
@ -583,7 +583,7 @@ class LayerV1ListBuilder:
self, transform: _AffineInput, paint: _PaintInput
) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintTransform)
ot_paint.Format = int(ot.PaintFormat.PaintTransform)
if not isinstance(transform, ot.Affine2x3):
transform = buildAffine2x3(transform)
ot_paint.Transform = transform
@ -594,7 +594,7 @@ class LayerV1ListBuilder:
self, paint: _PaintInput, dx: _ScalarInput, dy: _ScalarInput
):
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintTranslate)
ot_paint.Format = int(ot.PaintFormat.PaintTranslate)
ot_paint.Paint = self.buildPaint(paint)
ot_paint.dx = _to_variable_f16dot16_float(dx)
ot_paint.dy = _to_variable_f16dot16_float(dy)
@ -608,7 +608,7 @@ class LayerV1ListBuilder:
centerY: _ScalarInput,
) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintRotate)
ot_paint.Format = int(ot.PaintFormat.PaintRotate)
ot_paint.Paint = self.buildPaint(paint)
ot_paint.angle = _to_variable_f16dot16_float(angle)
ot_paint.centerX = _to_variable_f16dot16_float(centerX)
@ -624,7 +624,7 @@ class LayerV1ListBuilder:
centerY: _ScalarInput,
) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintSkew)
ot_paint.Format = int(ot.PaintFormat.PaintSkew)
ot_paint.Paint = self.buildPaint(paint)
ot_paint.xSkewAngle = _to_variable_f16dot16_float(xSkewAngle)
ot_paint.ySkewAngle = _to_variable_f16dot16_float(ySkewAngle)
@ -639,7 +639,7 @@ class LayerV1ListBuilder:
backdrop: _PaintInput,
):
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintComposite)
ot_paint.Format = int(ot.PaintFormat.PaintComposite)
ot_paint.SourcePaint = self.buildPaint(source)
ot_paint.CompositeMode = _to_composite_mode(mode)
ot_paint.BackdropPaint = self.buildPaint(backdrop)
@ -647,7 +647,7 @@ class LayerV1ListBuilder:
def buildColrLayers(self, paints: List[_PaintInput]) -> ot.Paint:
ot_paint = ot.Paint()
ot_paint.Format = int(ot.Paint.Format.PaintColrLayers)
ot_paint.Format = int(ot.PaintFormat.PaintColrLayers)
self.slices.append(ot_paint)
paints = [
@ -672,7 +672,7 @@ class LayerV1ListBuilder:
if reuse_lbound == -1:
continue
new_slice = ot.Paint()
new_slice.Format = int(ot.Paint.Format.PaintColrLayers)
new_slice.Format = int(ot.PaintFormat.PaintColrLayers)
new_slice.NumLayers = ubound - lbound
new_slice.FirstLayerIndex = reuse_lbound
paints = paints[:lbound] + [new_slice] + paints[ubound:]
@ -726,8 +726,8 @@ class LayerV1ListBuilder:
LayerV1ListBuilder._buildFunctions = {
pf.value: getattr(LayerV1ListBuilder, "build" + pf.name)
for pf in ot.Paint.Format
if pf != ot.Paint.Format.PaintColrLayers
for pf in ot.PaintFormat
if pf != ot.PaintFormat.PaintColrLayers
}

View File

@ -185,7 +185,7 @@ class LayerV1ListUnbuilder:
LayerV1ListUnbuilder._unbuildFunctions = {
pf.value: getattr(LayerV1ListUnbuilder, "unbuild" + pf.name)
for pf in ot.Paint.Format
for pf in ot.PaintFormat
}

View File

@ -1324,9 +1324,7 @@ class CompositeMode(IntEnum):
HSL_LUMINOSITY = 26
class Paint(getFormatSwitchingBaseTableClass("uint8")):
class Format(IntEnum):
class PaintFormat(IntEnum):
PaintColrLayers = 1
PaintSolid = 2
PaintLinearGradient = 3
@ -1340,9 +1338,12 @@ class Paint(getFormatSwitchingBaseTableClass("uint8")):
PaintSkew = 11
PaintComposite = 12
class Paint(getFormatSwitchingBaseTableClass("uint8")):
def getFormatName(self):
try:
return self.__class__.Format(self.Format).name
return PaintFormat(self.Format).name
except ValueError:
raise NotImplementedError(f"Unknown Paint format: {self.Format}")

View File

@ -241,13 +241,13 @@ def test_buildColorIndex():
def test_buildPaintSolid():
p = LayerV1ListBuilder().buildPaintSolid(0)
assert p.Format == ot.Paint.Format.PaintSolid
assert p.Format == ot.PaintFormat.PaintSolid
assert p.Color.PaletteIndex == 0
assert p.Color.Alpha.value == 1.0
assert p.Color.Alpha.varIdx == 0
p = LayerV1ListBuilder().buildPaintSolid(1, alpha=0.5)
assert p.Format == ot.Paint.Format.PaintSolid
assert p.Format == ot.PaintFormat.PaintSolid
assert p.Color.PaletteIndex == 1
assert p.Color.Alpha.value == 0.5
assert p.Color.Alpha.varIdx == 0
@ -255,7 +255,7 @@ def test_buildPaintSolid():
p = LayerV1ListBuilder().buildPaintSolid(
3, alpha=builder.VariableFloat(0.5, varIdx=2)
)
assert p.Format == ot.Paint.Format.PaintSolid
assert p.Format == ot.PaintFormat.PaintSolid
assert p.Color.PaletteIndex == 3
assert p.Color.Alpha.value == 0.5
assert p.Color.Alpha.varIdx == 2
@ -371,7 +371,7 @@ def test_buildPaintRadialGradient():
r1 = builder.VariableInt(5)
gradient = layerBuilder.buildPaintRadialGradient(color_line, c0, c1, r0, r1)
assert gradient.Format == ot.Paint.Format.PaintRadialGradient
assert gradient.Format == ot.PaintFormat.PaintRadialGradient
assert gradient.ColorLine == color_line
assert (gradient.x0, gradient.y0) == c0
assert (gradient.x1, gradient.y1) == c1
@ -401,7 +401,7 @@ def test_buildPaintSweepGradient():
endAngle=42,
)
assert paint.Format == ot.Paint.Format.PaintSweepGradient
assert paint.Format == ot.PaintFormat.PaintSweepGradient
assert paint.centerX.value == 127
assert paint.centerY.value == 129
assert paint.startAngle.value == 15
@ -412,11 +412,11 @@ def test_buildPaintGlyph_Solid():
layerBuilder = LayerV1ListBuilder()
layer = layerBuilder.buildPaintGlyph("a", 2)
assert layer.Glyph == "a"
assert layer.Paint.Format == ot.Paint.Format.PaintSolid
assert layer.Paint.Format == ot.PaintFormat.PaintSolid
assert layer.Paint.Color.PaletteIndex == 2
layer = layerBuilder.buildPaintGlyph("a", layerBuilder.buildPaintSolid(3, 0.9))
assert layer.Paint.Format == ot.Paint.Format.PaintSolid
assert layer.Paint.Format == ot.PaintFormat.PaintSolid
assert layer.Paint.Color.PaletteIndex == 3
assert layer.Paint.Color.Alpha.value == 0.9
@ -429,7 +429,7 @@ def test_buildPaintGlyph_LinearGradient():
{"stops": [(0.0, 3), (1.0, 4)]}, (100, 200), (150, 250)
),
)
assert layer.Paint.Format == ot.Paint.Format.PaintLinearGradient
assert layer.Paint.Format == ot.PaintFormat.PaintLinearGradient
assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0
assert layer.Paint.ColorLine.ColorStop[0].Color.PaletteIndex == 3
assert layer.Paint.ColorLine.ColorStop[1].StopOffset.value == 1.0
@ -458,7 +458,7 @@ def test_buildPaintGlyph_RadialGradient():
10,
),
)
assert layer.Paint.Format == ot.Paint.Format.PaintRadialGradient
assert layer.Paint.Format == ot.PaintFormat.PaintRadialGradient
assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0
assert layer.Paint.ColorLine.ColorStop[0].Color.PaletteIndex == 5
assert layer.Paint.ColorLine.ColorStop[1].StopOffset.value == 0.5
@ -478,7 +478,7 @@ def test_buildPaintGlyph_Dict_Solid():
layerBuilder = LayerV1ListBuilder()
layer = layerBuilder.buildPaintGlyph("a", {"format": 2, "paletteIndex": 0})
assert layer.Glyph == "a"
assert layer.Paint.Format == ot.Paint.Format.PaintSolid
assert layer.Paint.Format == ot.PaintFormat.PaintSolid
assert layer.Paint.Color.PaletteIndex == 0
@ -493,7 +493,7 @@ def test_buildPaintGlyph_Dict_LinearGradient():
"p1": (10, 10),
},
)
assert layer.Paint.Format == ot.Paint.Format.PaintLinearGradient
assert layer.Paint.Format == ot.PaintFormat.PaintLinearGradient
assert layer.Paint.ColorLine.ColorStop[0].StopOffset.value == 0.0
@ -510,13 +510,13 @@ def test_buildPaintGlyph_Dict_RadialGradient():
"r1": 0,
},
)
assert layer.Paint.Format == ot.Paint.Format.PaintRadialGradient
assert layer.Paint.Format == ot.PaintFormat.PaintRadialGradient
assert layer.Paint.r0.value == 4
def test_buildPaintColrGlyph():
paint = LayerV1ListBuilder().buildPaintColrGlyph("a")
assert paint.Format == ot.Paint.Format.PaintColrGlyph
assert paint.Format == ot.PaintFormat.PaintColrGlyph
assert paint.Glyph == "a"
@ -530,9 +530,9 @@ def test_buildPaintTransform():
),
)
assert paint.Format == ot.Paint.Format.PaintTransform
assert paint.Paint.Format == ot.Paint.Format.PaintGlyph
assert paint.Paint.Paint.Format == ot.Paint.Format.PaintSolid
assert paint.Format == ot.PaintFormat.PaintTransform
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
assert paint.Paint.Paint.Format == ot.PaintFormat.PaintSolid
assert paint.Transform.xx.value == 1.0
assert paint.Transform.yx.value == 2.0
@ -553,14 +553,14 @@ def test_buildPaintTransform():
},
)
assert paint.Format == ot.Paint.Format.PaintTransform
assert paint.Format == ot.PaintFormat.PaintTransform
assert paint.Transform.xx.value == 1.0
assert paint.Transform.yx.value == 0.0
assert paint.Transform.xy.value == 0.0
assert paint.Transform.yy.value == 0.3333
assert paint.Transform.dx.value == 10
assert paint.Transform.dy.value == 10
assert paint.Paint.Format == ot.Paint.Format.PaintRadialGradient
assert paint.Paint.Format == ot.PaintFormat.PaintRadialGradient
def test_buildPaintComposite():
@ -578,23 +578,23 @@ def test_buildPaintComposite():
),
)
assert composite.Format == ot.Paint.Format.PaintComposite
assert composite.SourcePaint.Format == ot.Paint.Format.PaintComposite
assert composite.SourcePaint.SourcePaint.Format == ot.Paint.Format.PaintGlyph
assert composite.Format == ot.PaintFormat.PaintComposite
assert composite.SourcePaint.Format == ot.PaintFormat.PaintComposite
assert composite.SourcePaint.SourcePaint.Format == ot.PaintFormat.PaintGlyph
assert composite.SourcePaint.SourcePaint.Glyph == "c"
assert composite.SourcePaint.SourcePaint.Paint.Format == ot.Paint.Format.PaintSolid
assert composite.SourcePaint.SourcePaint.Paint.Format == ot.PaintFormat.PaintSolid
assert composite.SourcePaint.SourcePaint.Paint.Color.PaletteIndex == 2
assert composite.SourcePaint.CompositeMode == ot.CompositeMode.SRC_OVER
assert composite.SourcePaint.BackdropPaint.Format == ot.Paint.Format.PaintGlyph
assert composite.SourcePaint.BackdropPaint.Format == ot.PaintFormat.PaintGlyph
assert composite.SourcePaint.BackdropPaint.Glyph == "b"
assert (
composite.SourcePaint.BackdropPaint.Paint.Format == ot.Paint.Format.PaintSolid
composite.SourcePaint.BackdropPaint.Paint.Format == ot.PaintFormat.PaintSolid
)
assert composite.SourcePaint.BackdropPaint.Paint.Color.PaletteIndex == 1
assert composite.CompositeMode == ot.CompositeMode.SRC_OVER
assert composite.BackdropPaint.Format == ot.Paint.Format.PaintGlyph
assert composite.BackdropPaint.Format == ot.PaintFormat.PaintGlyph
assert composite.BackdropPaint.Glyph == "a"
assert composite.BackdropPaint.Paint.Format == ot.Paint.Format.PaintSolid
assert composite.BackdropPaint.Paint.Format == ot.PaintFormat.PaintSolid
assert composite.BackdropPaint.Paint.Color.PaletteIndex == 0
@ -608,8 +608,8 @@ def test_buildPaintTranslate():
dy=-345,
)
assert paint.Format == ot.Paint.Format.PaintTranslate
assert paint.Paint.Format == ot.Paint.Format.PaintGlyph
assert paint.Format == ot.PaintFormat.PaintTranslate
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
assert paint.dx.value == 123
assert paint.dy.value == -345
@ -625,8 +625,8 @@ def test_buildPaintRotate():
centerY=129,
)
assert paint.Format == ot.Paint.Format.PaintRotate
assert paint.Paint.Format == ot.Paint.Format.PaintGlyph
assert paint.Format == ot.PaintFormat.PaintRotate
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
assert paint.angle.value == 15
assert paint.centerX.value == 127
assert paint.centerY.value == 129
@ -644,8 +644,8 @@ def test_buildPaintSkew():
centerY=129,
)
assert paint.Format == ot.Paint.Format.PaintSkew
assert paint.Paint.Format == ot.Paint.Format.PaintGlyph
assert paint.Format == ot.PaintFormat.PaintSkew
assert paint.Paint.Format == ot.PaintFormat.PaintGlyph
assert paint.xSkewAngle.value == 15
assert paint.ySkewAngle.value == 42
assert paint.centerX.value == 127
@ -714,21 +714,21 @@ def test_buildColrV1_more_than_255_paints():
assert len(paints) == num_paints + 1
assert all(paints[i].Format == ot.Paint.Format.PaintGlyph for i in range(255))
assert all(paints[i].Format == ot.PaintFormat.PaintGlyph for i in range(255))
assert paints[255].Format == ot.Paint.Format.PaintColrLayers
assert paints[255].Format == ot.PaintFormat.PaintColrLayers
assert paints[255].FirstLayerIndex == 0
assert paints[255].NumLayers == 255
assert all(
paints[i].Format == ot.Paint.Format.PaintGlyph
paints[i].Format == ot.PaintFormat.PaintGlyph
for i in range(256, num_paints + 1)
)
assert baseGlyphs.BaseGlyphCount == len(colorGlyphs)
assert baseGlyphs.BaseGlyphV1Record[0].BaseGlyph == "a"
assert (
baseGlyphs.BaseGlyphV1Record[0].Paint.Format == ot.Paint.Format.PaintColrLayers
baseGlyphs.BaseGlyphV1Record[0].Paint.Format == ot.PaintFormat.PaintColrLayers
)
assert baseGlyphs.BaseGlyphV1Record[0].Paint.FirstLayerIndex == 255
assert baseGlyphs.BaseGlyphV1Record[0].Paint.NumLayers == num_paints + 1 - 255
@ -841,9 +841,9 @@ def _paint_names(paints) -> List[str]:
# semi-readable assertions on a LayerV1List order.
result = []
for paint in paints:
if paint.Format == int(ot.Paint.Format.PaintGlyph):
if paint.Format == int(ot.PaintFormat.PaintGlyph):
result.append(paint.Glyph)
elif paint.Format == int(ot.Paint.Format.PaintColrLayers):
elif paint.Format == int(ot.PaintFormat.PaintColrLayers):
result.append(
f"Layers[{paint.FirstLayerIndex}:{paint.FirstLayerIndex+paint.NumLayers}]"
)

View File

@ -7,19 +7,19 @@ import pytest
TEST_COLOR_GLYPHS = {
"glyph00010": [
{
"format": int(ot.Paint.Format.PaintGlyph),
"format": int(ot.PaintFormat.PaintGlyph),
"glyph": "glyph00011",
"paint": {
"format": int(ot.Paint.Format.PaintSolid),
"format": int(ot.PaintFormat.PaintSolid),
"paletteIndex": 2,
"alpha": 0.5,
},
},
{
"format": int(ot.Paint.Format.PaintGlyph),
"format": int(ot.PaintFormat.PaintGlyph),
"glyph": "glyph00012",
"paint": {
"format": int(ot.Paint.Format.PaintLinearGradient),
"format": int(ot.PaintFormat.PaintLinearGradient),
"colorLine": {
"stops": [
{"offset": 0.0, "paletteIndex": 3, "alpha": 1.0},
@ -34,13 +34,13 @@ TEST_COLOR_GLYPHS = {
},
},
{
"format": int(ot.Paint.Format.PaintGlyph),
"format": int(ot.PaintFormat.PaintGlyph),
"glyph": "glyph00013",
"paint": {
"format": int(ot.Paint.Format.PaintTransform),
"format": int(ot.PaintFormat.PaintTransform),
"transform": (-13.0, 14.0, 15.0, -17.0, 18.0, 19.0),
"paint": {
"format": int(ot.Paint.Format.PaintRadialGradient),
"format": int(ot.PaintFormat.PaintRadialGradient),
"colorLine": {
"stops": [
{"offset": 0.0, "paletteIndex": 6, "alpha": 1.0},
@ -60,25 +60,25 @@ TEST_COLOR_GLYPHS = {
},
},
{
"format": int(ot.Paint.Format.PaintTranslate),
"format": int(ot.PaintFormat.PaintTranslate),
"dx": 257.0,
"dy": 258.0,
"paint": {
"format": int(ot.Paint.Format.PaintRotate),
"format": int(ot.PaintFormat.PaintRotate),
"angle": 45.0,
"centerX": 255.0,
"centerY": 256.0,
"paint": {
"format": int(ot.Paint.Format.PaintSkew),
"format": int(ot.PaintFormat.PaintSkew),
"xSkewAngle": -11.0,
"ySkewAngle": 5.0,
"centerX": 253.0,
"centerY": 254.0,
"paint": {
"format": int(ot.Paint.Format.PaintGlyph),
"format": int(ot.PaintFormat.PaintGlyph),
"glyph": "glyph00011",
"paint": {
"format": int(ot.Paint.Format.PaintSolid),
"format": int(ot.PaintFormat.PaintSolid),
"paletteIndex": 2,
"alpha": 0.5,
},
@ -88,26 +88,26 @@ TEST_COLOR_GLYPHS = {
},
],
"glyph00014": {
"format": int(ot.Paint.Format.PaintComposite),
"format": int(ot.PaintFormat.PaintComposite),
"mode": "src_over",
"source": {
"format": int(ot.Paint.Format.PaintColrGlyph),
"format": int(ot.PaintFormat.PaintColrGlyph),
"glyph": "glyph00010",
},
"backdrop": {
"format": int(ot.Paint.Format.PaintTransform),
"format": int(ot.PaintFormat.PaintTransform),
"transform": (1.0, 0.0, 0.0, 1.0, 300.0, 0.0),
"paint": {
"format": int(ot.Paint.Format.PaintColrGlyph),
"format": int(ot.PaintFormat.PaintColrGlyph),
"glyph": "glyph00010",
},
},
},
"glyph00015": {
"format": int(ot.Paint.Format.PaintGlyph),
"format": int(ot.PaintFormat.PaintGlyph),
"glyph": "glyph00011",
"paint": {
"format": int(ot.Paint.Format.PaintSweepGradient),
"format": int(ot.PaintFormat.PaintSweepGradient),
"colorLine": {
"stops": [
{"offset": 0.0, "paletteIndex": 3, "alpha": 1.0},
@ -123,19 +123,19 @@ TEST_COLOR_GLYPHS = {
},
"glyph00016": [
{
"format": int(ot.Paint.Format.PaintGlyph),
"format": int(ot.PaintFormat.PaintGlyph),
"glyph": "glyph00011",
"paint": {
"format": int(ot.Paint.Format.PaintSolid),
"format": int(ot.PaintFormat.PaintSolid),
"paletteIndex": 2,
"alpha": 0.5,
},
},
{
"format": int(ot.Paint.Format.PaintGlyph),
"format": int(ot.PaintFormat.PaintGlyph),
"glyph": "glyph00012",
"paint": {
"format": int(ot.Paint.Format.PaintLinearGradient),
"format": int(ot.PaintFormat.PaintLinearGradient),
"colorLine": {
"stops": [
{"offset": 0.0, "paletteIndex": 3, "alpha": 1.0},