diff --git a/Lib/blackrenderer/__main__.py b/Lib/blackrenderer/__main__.py
index 49335eb..8e6e56b 100644
--- a/Lib/blackrenderer/__main__.py
+++ b/Lib/blackrenderer/__main__.py
@@ -31,6 +31,7 @@ def main():
parser.add_argument("--features", type=parseFeatures)
parser.add_argument("--variations", type=parseVariations)
parser.add_argument("--margin", type=float, default=20)
+ parser.add_argument("--palette-index", type=int, default=0)
parser.add_argument(
"--backend",
default=None,
@@ -47,6 +48,7 @@ def main():
margin=args.margin,
features=args.features,
variations=args.variations,
+ paletteIndex=args.palette_index,
backendName=args.backend,
)
diff --git a/Lib/blackrenderer/font.py b/Lib/blackrenderer/font.py
index 6c772c9..15efa0a 100644
--- a/Lib/blackrenderer/font.py
+++ b/Lib/blackrenderer/font.py
@@ -97,6 +97,13 @@ def __init__(self, path=None, *, fontNumber=0, lazy=True, ttFont=None, hbFont=No
def unitsPerEm(self):
return self.hbFont.face.upem
+ def getPalette(self, paletteIndex):
+ if not self.palettes:
+ return None
+ # clamp index
+ paletteIndex = max(0, min(paletteIndex, len(self.palettes) - 1))
+ return self.palettes[paletteIndex]
+
def setLocation(self, location):
if location is None:
location = {}
diff --git a/Lib/blackrenderer/render.py b/Lib/blackrenderer/render.py
index fecf515..4455311 100644
--- a/Lib/blackrenderer/render.py
+++ b/Lib/blackrenderer/render.py
@@ -25,6 +25,7 @@ def renderText(
margin=20,
features=None,
variations=None,
+ paletteIndex=0,
backendName=None,
lang=None,
script=None,
@@ -44,6 +45,7 @@ def renderText(
buf.language = lang
if variations:
font.setLocation(variations)
+ palette = font.getPalette(paletteIndex)
hb.shape(font.hbFont, buf, features)
@@ -73,7 +75,7 @@ def renderText(
for glyph in glyphLine:
with canvas.savedState():
canvas.translate(glyph.xOffset, glyph.yOffset)
- font.drawGlyph(glyph.name, canvas)
+ font.drawGlyph(glyph.name, canvas, palette=palette)
canvas.translate(glyph.xAdvance, glyph.yAdvance)
if outputPath is not None:
diff --git a/Tests/data/Nabla.subset.ttf b/Tests/data/Nabla.subset.ttf
new file mode 100644
index 0000000..d6356fe
Binary files /dev/null and b/Tests/data/Nabla.subset.ttf differ
diff --git a/Tests/expectedOutput/glyph_nabla_A_1_cairo.png b/Tests/expectedOutput/glyph_nabla_A_1_cairo.png
new file mode 100644
index 0000000..454a1da
Binary files /dev/null and b/Tests/expectedOutput/glyph_nabla_A_1_cairo.png differ
diff --git a/Tests/expectedOutput/glyph_nabla_A_1_coregraphics.png b/Tests/expectedOutput/glyph_nabla_A_1_coregraphics.png
new file mode 100644
index 0000000..258bdb6
Binary files /dev/null and b/Tests/expectedOutput/glyph_nabla_A_1_coregraphics.png differ
diff --git a/Tests/expectedOutput/glyph_nabla_A_1_skia.png b/Tests/expectedOutput/glyph_nabla_A_1_skia.png
new file mode 100644
index 0000000..fbaa6d9
Binary files /dev/null and b/Tests/expectedOutput/glyph_nabla_A_1_skia.png differ
diff --git a/Tests/expectedOutput/glyph_nabla_A_1_svg.svg b/Tests/expectedOutput/glyph_nabla_A_1_svg.svg
new file mode 100644
index 0000000..21e136a
--- /dev/null
+++ b/Tests/expectedOutput/glyph_nabla_A_1_svg.svg
@@ -0,0 +1,34 @@
+
+
diff --git a/Tests/expectedOutput/glyph_nabla_A_cairo.png b/Tests/expectedOutput/glyph_nabla_A_cairo.png
new file mode 100644
index 0000000..64032a3
Binary files /dev/null and b/Tests/expectedOutput/glyph_nabla_A_cairo.png differ
diff --git a/Tests/expectedOutput/glyph_nabla_A_coregraphics.png b/Tests/expectedOutput/glyph_nabla_A_coregraphics.png
new file mode 100644
index 0000000..4fa0ee7
Binary files /dev/null and b/Tests/expectedOutput/glyph_nabla_A_coregraphics.png differ
diff --git a/Tests/expectedOutput/glyph_nabla_A_skia.png b/Tests/expectedOutput/glyph_nabla_A_skia.png
new file mode 100644
index 0000000..32eb1e6
Binary files /dev/null and b/Tests/expectedOutput/glyph_nabla_A_skia.png differ
diff --git a/Tests/expectedOutput/glyph_nabla_A_svg.svg b/Tests/expectedOutput/glyph_nabla_A_svg.svg
new file mode 100644
index 0000000..6707c07
--- /dev/null
+++ b/Tests/expectedOutput/glyph_nabla_A_svg.svg
@@ -0,0 +1,34 @@
+
+
diff --git a/Tests/test_glyph_render.py b/Tests/test_glyph_render.py
index cfaebc1..168daaf 100644
--- a/Tests/test_glyph_render.py
+++ b/Tests/test_glyph_render.py
@@ -29,81 +29,85 @@
"crash": dataDir / "crash.subset.otf",
"nested_paintglyph": dataDir / "nested-paintglyph.ttf",
"ftvartest": dataDir / "TestVariableCOLR-VF.ttf",
+ "nabla": dataDir / "Nabla.subset.ttf",
}
test_glyphs = [
- ("noto", "uni2693", None),
- ("noto", "uni2694", None),
- ("noto", "u1F30A", None),
- ("noto", "u1F943", None),
- ("mutator", "B", None),
- ("mutator", "D", {"wdth": 1000}),
- ("twemoji", "uni3299", None),
- ("more_samples", "cross_glyph", None),
- ("more_samples", "skew_0_15_center_500.0_500.0", None),
- ("more_samples", "skew_-10_20_center_500.0_500.0", None),
- ("more_samples", "skew_-10_20_center_1000_1000", None),
- ("more_samples", "transform_matrix_1_0_0_1_125_125", None),
- ("more_samples", "transform_matrix_1.5_0_0_1.5_0_0", None),
- ("more_samples", "transform_matrix_0.9659_0.2588_-0.2588_0.9659_0_0", None),
- ("more_samples", "transform_matrix_1.0_0.0_0.6_1.0_-300.0_0.0", None),
- ("more_samples", "clip_box_top_left", None),
- ("more_samples", "clip_box_bottom_left", None),
- ("more_samples", "clip_box_bottom_right", None),
- ("more_samples", "clip_box_top_right", None),
- ("more_samples", "clip_box_center", None),
- ("more_samples", "composite_DEST_OVER", None),
- ("more_samples", "composite_XOR", None),
- ("more_samples", "composite_OVERLAY", None),
- ("more_samples", "composite_SRC_IN", None),
- ("more_samples", "composite_PLUS", None),
- ("more_samples", "composite_LIGHTEN", None),
- ("more_samples", "composite_MULTIPLY", None),
- ("more_samples", "clip_shade_center", None),
- ("more_samples", "clip_shade_top_left", None),
- ("more_samples", "clip_shade_bottom_left", None),
- ("more_samples", "clip_shade_bottom_right", None),
- ("more_samples", "clip_shade_top_right", None),
- ("more_samples", "inset_clipped_radial_reflect", None),
- # ("more_samples", "sweep", None),
- ("more_samples", "transformed_sweep", None),
- ("more_samples", "composite_colr_glyph", None),
- ("more_samples", "linear_repeat_0_1", None),
- ("more_samples", "linear_repeat_0.2_0.8", None),
- ("more_samples", "linear_repeat_0_1.5", None),
- ("more_samples", "linear_repeat_0.5_1.5", None),
- ("more_samples", "scale_0.5_1.5_center_500.0_500.0", None),
- ("more_samples", "scale_1.5_1.5_center_500.0_500.0", None),
- ("more_samples", "scale_0.5_1.5_center_0_0", None),
- ("more_samples", "scale_1.5_1.5_center_0_0", None),
- ("more_samples", "scale_0.5_1.5_center_1000_1000", None),
- ("more_samples", "scale_1.5_1.5_center_1000_1000", None),
- ("more_samples", "linear_gradient_extend_mode_pad", None),
- ("more_samples", "linear_gradient_extend_mode_repeat", None),
- ("more_samples", "linear_gradient_extend_mode_reflect", None),
- ("more_samples", "radial_gradient_extend_mode_pad", None),
- ("more_samples", "radial_gradient_extend_mode_repeat", None),
- ("more_samples", "radial_gradient_extend_mode_reflect", None),
- ("more_samples", "rotate_10_center_0_0", None),
- ("more_samples", "rotate_-10_center_1000_1000", None),
- ("more_samples", "rotate_25_center_500.0_500.0", None),
- ("more_samples", "rotate_-15_center_500.0_500.0", None),
- ("more_samples", "skew_25_0_center_0_0", None),
- ("more_samples", "skew_25_0_center_500.0_500.0", None),
- ("more_samples", "skew_0_15_center_0_0", None),
- ("more_samples", "upem_box_glyph", None),
- ("nested_paintglyph", "A", None),
- ("ftvartest", "A", {"wght": 400}),
- ("ftvartest", "A", {"wght": 700}),
- ("ftvartest", "B", {"wght": 400}),
- ("ftvartest", "B", {"wght": 700}),
+ ("noto", "uni2693", None, 0),
+ ("noto", "uni2694", None, 0),
+ ("noto", "u1F30A", None, 0),
+ ("noto", "u1F943", None, 0),
+ ("mutator", "B", None, 0),
+ ("mutator", "D", {"wdth": 1000}, 0),
+ ("twemoji", "uni3299", None, 0),
+ ("more_samples", "cross_glyph", None, 0),
+ ("more_samples", "skew_0_15_center_500.0_500.0", None, 0),
+ ("more_samples", "skew_-10_20_center_500.0_500.0", None, 0),
+ ("more_samples", "skew_-10_20_center_1000_1000", None, 0),
+ ("more_samples", "transform_matrix_1_0_0_1_125_125", None, 0),
+ ("more_samples", "transform_matrix_1.5_0_0_1.5_0_0", None, 0),
+ ("more_samples", "transform_matrix_0.9659_0.2588_-0.2588_0.9659_0_0", None, 0),
+ ("more_samples", "transform_matrix_1.0_0.0_0.6_1.0_-300.0_0.0", None, 0),
+ ("more_samples", "clip_box_top_left", None, 0),
+ ("more_samples", "clip_box_bottom_left", None, 0),
+ ("more_samples", "clip_box_bottom_right", None, 0),
+ ("more_samples", "clip_box_top_right", None, 0),
+ ("more_samples", "clip_box_center", None, 0),
+ ("more_samples", "composite_DEST_OVER", None, 0),
+ ("more_samples", "composite_XOR", None, 0),
+ ("more_samples", "composite_OVERLAY", None, 0),
+ ("more_samples", "composite_SRC_IN", None, 0),
+ ("more_samples", "composite_PLUS", None, 0),
+ ("more_samples", "composite_LIGHTEN", None, 0),
+ ("more_samples", "composite_MULTIPLY", None, 0),
+ ("more_samples", "clip_shade_center", None, 0),
+ ("more_samples", "clip_shade_top_left", None, 0),
+ ("more_samples", "clip_shade_bottom_left", None, 0),
+ ("more_samples", "clip_shade_bottom_right", None, 0),
+ ("more_samples", "clip_shade_top_right", None, 0),
+ ("more_samples", "inset_clipped_radial_reflect", None, 0),
+ ("more_samples", "transformed_sweep", None, 0),
+ ("more_samples", "composite_colr_glyph", None, 0),
+ ("more_samples", "linear_repeat_0_1", None, 0),
+ ("more_samples", "linear_repeat_0.2_0.8", None, 0),
+ ("more_samples", "linear_repeat_0_1.5", None, 0),
+ ("more_samples", "linear_repeat_0.5_1.5", None, 0),
+ ("more_samples", "scale_0.5_1.5_center_500.0_500.0", None, 0),
+ ("more_samples", "scale_1.5_1.5_center_500.0_500.0", None, 0),
+ ("more_samples", "scale_0.5_1.5_center_0_0", None, 0),
+ ("more_samples", "scale_1.5_1.5_center_0_0", None, 0),
+ ("more_samples", "scale_0.5_1.5_center_1000_1000", None, 0),
+ ("more_samples", "scale_1.5_1.5_center_1000_1000", None, 0),
+ ("more_samples", "linear_gradient_extend_mode_pad", None, 0),
+ ("more_samples", "linear_gradient_extend_mode_repeat", None, 0),
+ ("more_samples", "linear_gradient_extend_mode_reflect", None, 0),
+ ("more_samples", "radial_gradient_extend_mode_pad", None, 0),
+ ("more_samples", "radial_gradient_extend_mode_repeat", None, 0),
+ ("more_samples", "radial_gradient_extend_mode_reflect", None, 0),
+ ("more_samples", "rotate_10_center_0_0", None, 0),
+ ("more_samples", "rotate_-10_center_1000_1000", None, 0),
+ ("more_samples", "rotate_25_center_500.0_500.0", None, 0),
+ ("more_samples", "rotate_-15_center_500.0_500.0", None, 0),
+ ("more_samples", "skew_25_0_center_0_0", None, 0),
+ ("more_samples", "skew_25_0_center_500.0_500.0", None, 0),
+ ("more_samples", "skew_0_15_center_0_0", None, 0),
+ ("more_samples", "upem_box_glyph", None, 0),
+ ("nested_paintglyph", "A", None, 0),
+ ("ftvartest", "A", {"wght": 400}, 0),
+ ("ftvartest", "A", {"wght": 700}, 0),
+ ("ftvartest", "B", {"wght": 400}, 0),
+ ("ftvartest", "B", {"wght": 700}, 0),
+ ("nabla", "A", None, 0),
+ ("nabla", "A", None, 1),
]
-@pytest.mark.parametrize("fontName, glyphName, location", test_glyphs)
+@pytest.mark.parametrize("fontName, glyphName, location, paletteIndex", test_glyphs)
@pytest.mark.parametrize("backendName, surfaceClass", backends)
-def test_renderGlyph(backendName, surfaceClass, fontName, glyphName, location):
+def test_renderGlyph(
+ backendName, surfaceClass, fontName, glyphName, location, paletteIndex
+):
font = BlackRendererFont(testFonts[fontName])
font.setLocation(location)
@@ -111,15 +115,20 @@ def test_renderGlyph(backendName, surfaceClass, fontName, glyphName, location):
boundingBox = font.getGlyphBounds(glyphName)
boundingBox = scaleRect(boundingBox, scaleFactor, scaleFactor)
boundingBox = intRect(boundingBox)
+ palette = font.getPalette(paletteIndex)
surface = surfaceClass()
ext = surface.fileExtension
with surface.canvas(boundingBox) as canvas:
canvas.scale(scaleFactor)
- font.drawGlyph(glyphName, canvas)
+ font.drawGlyph(glyphName, canvas, palette=palette)
locationString = "_" + _locationToString(location) if location else ""
- fileName = f"glyph_{fontName}_{glyphName}{locationString}_{backendName}{ext}"
+ paletteString = "_" + str(paletteIndex) if paletteIndex else ""
+ fileName = (
+ f"glyph_{fontName}_{glyphName}{locationString}{paletteString}"
+ f"_{backendName}{ext}"
+ )
expectedPath = expectedOutputDir / fileName
outputPath = tmpOutputDir / fileName
surface.saveImage(outputPath)