Skip to content

Commit 3e39175

Browse files
committed
full support for emojis
1 parent e63bb35 commit 3e39175

3 files changed

Lines changed: 43 additions & 2 deletions

File tree

tests/test_svg_images_blender52.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import zlib
99

1010
import bpy
11+
from lxml import etree
1112
import pytest
1213

1314
from typst_importer.image_import import extract_svg_images
@@ -63,6 +64,32 @@ def test_preprocessing_extracts_embedded_use_image_with_viewport_geometry():
6364
assert max(ys) == pytest.approx(65.0)
6465

6566

67+
def test_preprocessing_preserves_visible_overflow_for_typst_image_symbols():
68+
data_uri = _data_uri()
69+
svg = f'''<svg xmlns="{SVG_NS}" width="100" height="20">
70+
<defs><symbol id="emoji" overflow="visible">
71+
<image transform="translate(0 -80)" width="100" height="100"
72+
preserveAspectRatio="none" href="{data_uri}"/>
73+
</symbol></defs>
74+
<use href="#emoji" transform="scale(0.2 -0.2)"/>
75+
</svg>'''
76+
77+
processed = preprocess_svg(svg)
78+
root = etree.fromstring(processed.encode("utf-8"))
79+
image = root.xpath("//*[local-name()='image']")[0]
80+
image_viewport = next(
81+
ancestor
82+
for ancestor in image.iterancestors()
83+
if etree.QName(ancestor).localname == "svg" and ancestor is not root
84+
)
85+
86+
# Typst positions the full bitmap outside the symbol's nominal viewport.
87+
# The symbol therefore relies on visible overflow; putting this property
88+
# only on an outer group clips the emoji to a thin horizontal strip.
89+
assert image_viewport.get("overflow") == "visible"
90+
assert image.get("href") == data_uri
91+
92+
6693
def test_external_images_are_contained_to_the_typst_source_folder(tmp_path: Path):
6794
source_dir = tmp_path / "source"
6895
source_dir.mkdir()
@@ -117,8 +144,12 @@ def test_typst_image_becomes_a_packed_textured_plane(tmp_path: Path):
117144
curves = [obj for obj in collection.objects if obj.type == "CURVE"]
118145
assert len(curves) == 1
119146
assert plane.get("svg_paint_index") > curves[0].get("svg_paint_index")
120-
assert plane.dimensions.x == pytest.approx(curves[0].dimensions.x, abs=2e-6)
121-
assert plane.dimensions.y == pytest.approx(curves[0].dimensions.y, abs=2e-6)
147+
# Curve geometry is rescaled in place. Updating the dependency graph keeps
148+
# Blender from returning its stale, pre-scale dimensions and ensures this
149+
# comparison catches image planes that miss the same import scale.
150+
bpy.context.view_layer.update()
151+
assert plane.dimensions.x == pytest.approx(curves[0].dimensions.x, rel=1e-3)
152+
assert plane.dimensions.y == pytest.approx(curves[0].dimensions.y, rel=1e-3)
122153
material = plane.data.materials[0]
123154
texture = next(
124155
node

typst_importer/svg_preprocessing.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ def flatten_svg(svg_content):
315315
"height",
316316
"viewBox",
317317
"preserveAspectRatio",
318+
"overflow",
318319
}:
319320
target_group.set(attr_name, attr_value)
320321

@@ -342,6 +343,14 @@ def flatten_svg(svg_content):
342343
target_viewport = etree.Element(f"{{{SVG_NS}}}svg")
343344
target_viewport.set("width", _number(width))
344345
target_viewport.set("height", _number(height))
346+
# ``overflow`` belongs to the viewport established when a
347+
# <symbol> or nested <svg> is instantiated. Leaving it on
348+
# the surrounding group makes the synthetic viewport use the
349+
# SVG default (hidden), which clips Typst's translated emoji
350+
# bitmaps down to a thin strip.
351+
overflow_value = target.get("overflow")
352+
if overflow_value is not None:
353+
target_viewport.set("overflow", overflow_value)
345354
viewbox_value = target.get("viewBox")
346355
if viewbox_value is not None:
347356
target_viewport.set("viewBox", viewbox_value)

typst_importer/typst_to_svg.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,7 @@ def typst_to_blender_curves(
723723
imported_collection,
724724
use_emission=True,
725725
warnings=image_warnings,
726+
scale_factor=scale_factor,
726727
)
727728
if marker_ids:
728729
finalize_paint_order(

0 commit comments

Comments
 (0)