Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix cropping of SVGs #113

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Flip sign of translation factor so it can be added rather...
...than subtracted from the original bounding rect. This seems to be
more conventional.
  • Loading branch information
jams2 committed Jun 22, 2023
commit 7c772c905d45d8471c3539c3705757c652bb0677
48 changes: 24 additions & 24 deletions tests/test_svg_coordinate_transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ def test_portrait_view_box(self):
("xMinYMin meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 0)),
("xMinYMid meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 0)),
("xMinYMax meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 0)),
("xMidYMin meet", ViewportToUserSpaceTransform(1.25, 1.25, 18.75, 0)),
("xMidYMid meet", ViewportToUserSpaceTransform(1.25, 1.25, 18.75, 0)),
("xMidYMax meet", ViewportToUserSpaceTransform(1.25, 1.25, 18.75, 0)),
("xMaxYMin meet", ViewportToUserSpaceTransform(1.25, 1.25, 37.5, 0)),
("xMaxYMid meet", ViewportToUserSpaceTransform(1.25, 1.25, 37.5, 0)),
("xMaxYMax meet", ViewportToUserSpaceTransform(1.25, 1.25, 37.5, 0)),
("xMidYMin meet", ViewportToUserSpaceTransform(1.25, 1.25, -18.75, 0)),
("xMidYMid meet", ViewportToUserSpaceTransform(1.25, 1.25, -18.75, 0)),
("xMidYMax meet", ViewportToUserSpaceTransform(1.25, 1.25, -18.75, 0)),
("xMaxYMin meet", ViewportToUserSpaceTransform(1.25, 1.25, -37.5, 0)),
("xMaxYMid meet", ViewportToUserSpaceTransform(1.25, 1.25, -37.5, 0)),
("xMaxYMax meet", ViewportToUserSpaceTransform(1.25, 1.25, -37.5, 0)),
]
for preserve_aspect_ratio, expected_result in params:
with self.subTest(preserve_aspect_ratio=preserve_aspect_ratio):
Expand All @@ -78,12 +78,12 @@ def test_landscape_view_box(self):
("xMinYMin meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 0)),
("xMidYMin meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 0)),
("xMaxYMin meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 0)),
("xMinYMid meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 18.75)),
("xMidYMid meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 18.75)),
("xMaxYMid meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 18.75)),
("xMinYMax meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 37.5)),
("xMidYMax meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 37.5)),
("xMaxYMax meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, 37.5)),
("xMinYMid meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, -18.75)),
("xMidYMid meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, -18.75)),
("xMaxYMid meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, -18.75)),
("xMinYMax meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, -37.5)),
("xMidYMax meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, -37.5)),
("xMaxYMax meet", ViewportToUserSpaceTransform(1.25, 1.25, 0, -37.5)),
]
for preserve_aspect_ratio, expected_result in params:
with self.subTest(preserve_aspect_ratio=preserve_aspect_ratio):
Expand All @@ -105,12 +105,12 @@ def test_portrait_view_box(self):
("xMinYMin slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 0)),
("xMidYMin slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 0)),
("xMaxYMin slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 0)),
("xMinYMid slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, -50)),
("xMidYMid slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, -50)),
("xMaxYMid slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, -50)),
("xMinYMax slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, -100)),
("xMidYMax slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, -100)),
("xMaxYMax slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, -100)),
("xMinYMid slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 50)),
("xMidYMid slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 50)),
("xMaxYMid slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 50)),
("xMinYMax slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 100)),
("xMidYMax slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 100)),
("xMaxYMax slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 100)),
]
for preserve_aspect_ratio, expected_result in params:
with self.subTest(preserve_aspect_ratio=preserve_aspect_ratio):
Expand All @@ -129,12 +129,12 @@ def test_landscape_view_box(self):
("xMinYMin slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 0)),
("xMinYMid slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 0)),
("xMinYMax slice", ViewportToUserSpaceTransform(2.5, 2.5, 0, 0)),
("xMidYMin slice", ViewportToUserSpaceTransform(2.5, 2.5, -50, 0)),
("xMidYMid slice", ViewportToUserSpaceTransform(2.5, 2.5, -50, 0)),
("xMidYMax slice", ViewportToUserSpaceTransform(2.5, 2.5, -50, 0)),
("xMaxYMin slice", ViewportToUserSpaceTransform(2.5, 2.5, -100, 0)),
("xMaxYMid slice", ViewportToUserSpaceTransform(2.5, 2.5, -100, 0)),
("xMaxYMax slice", ViewportToUserSpaceTransform(2.5, 2.5, -100, 0)),
("xMidYMin slice", ViewportToUserSpaceTransform(2.5, 2.5, 50, 0)),
("xMidYMid slice", ViewportToUserSpaceTransform(2.5, 2.5, 50, 0)),
("xMidYMax slice", ViewportToUserSpaceTransform(2.5, 2.5, 50, 0)),
("xMaxYMin slice", ViewportToUserSpaceTransform(2.5, 2.5, 100, 0)),
("xMaxYMid slice", ViewportToUserSpaceTransform(2.5, 2.5, 100, 0)),
("xMaxYMax slice", ViewportToUserSpaceTransform(2.5, 2.5, 100, 0)),
]
for preserve_aspect_ratio, expected_result in params:
with self.subTest(preserve_aspect_ratio=preserve_aspect_ratio):
Expand Down
31 changes: 21 additions & 10 deletions willow/svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ def __init__(self, scale_x, scale_y, translate_x, translate_y):
self.translate_x = translate_x
self.translate_y = translate_y

def __repr__(self):
return (
f"{self.__class__.__name__}(scale_x={self.scale_x}, scale_y="
f"{self.scale_y}, translate_x={self.translate_x}, "
f"translate_y={self.translate_y})"
)

def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
Expand All @@ -49,10 +56,10 @@ def __eq__(self, other):
def __call__(self, rect):
left, top, right, bottom = rect
return (
(left - self.translate_x) / self.scale_x,
(top - self.translate_y) / self.scale_y,
(right - self.translate_x) / self.scale_x,
(bottom - self.translate_y) / self.scale_y,
(left + self.translate_x) / self.scale_x,
(top + self.translate_y) / self.scale_y,
(right + self.translate_x) / self.scale_x,
(bottom + self.translate_y) / self.scale_y,
)


Expand Down Expand Up @@ -86,17 +93,21 @@ def get_viewport_to_user_space_transform(
# use it for scaling both axes
scale_x = scale_y = choose_coefficient(scale_x, scale_y)

translate_x = -view_box.min_x * scale_x
# initial offsets to account for non-zero viewBox min-x and min-y
translate_x = view_box.min_x * scale_x
translate_y = view_box.min_y * scale_y

# adjust the offsets by the amount the viewBox has been translated
# to fit into the viewport (if any)
if x_position == "mid":
translate_x += (svg.image.width - view_box.width * scale_x) / 2
translate_x -= (svg.image.width - view_box.width * scale_x) / 2
elif x_position == "max":
translate_x += svg.image.width - view_box.width * scale_x
translate_x -= svg.image.width - view_box.width * scale_x

translate_y = -view_box.min_y * scale_y
if y_position == "mid":
translate_y += (svg.image.height - view_box.height * scale_y) / 2
translate_y -= (svg.image.height - view_box.height * scale_y) / 2
elif y_position == "max":
translate_y += svg.image.height - view_box.height * scale_y
translate_y -= svg.image.height - view_box.height * scale_y

return ViewportToUserSpaceTransform(scale_x, scale_y, translate_x, translate_y)

Expand Down