Skip to content

Commit

Permalink
Don't duplicate the preserve ratio code between svg tag and surface
Browse files Browse the repository at this point in the history
  • Loading branch information
liZe committed May 18, 2019
1 parent 11ee777 commit 0d71521
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 68 deletions.
10 changes: 1 addition & 9 deletions cairosvg/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,24 +113,16 @@ def point_angle(cx, cy, px, py):
return atan2(py - cy, px - cx)


def preserved_ratio(node):
"""Return whether we must preserve the ratio."""
return node.get('preserveAspectRatio', 'xMidYMid').split(' ')[0] != 'none'


def preserve_ratio(surface, node):
"""Manage the ratio preservation."""
if node.tag == 'marker':
width = size(surface, node.get('markerWidth', '3'), 'x')
height = size(surface, node.get('markerHeight', '3'), 'y')
_, _, viewbox = node_format(surface, node)
viewbox_width, viewbox_height = viewbox[2:]
elif node.tag in ('svg', 'image'):
elif node.tag in ('svg', 'image', 'g'):
width, height, _ = node_format(surface, node)
viewbox_width, viewbox_height = node.image_width, node.image_height
else:
# Safety measure
return 1, 1, 0, 0

translate_x = 0
translate_y = 0
Expand Down
13 changes: 7 additions & 6 deletions cairosvg/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

from PIL import Image

from .helpers import node_format, preserve_ratio, preserved_ratio, size
from .helpers import node_format, preserve_ratio, size
from .parser import Tree
from .surface import cairo
from .url import parse_url
Expand Down Expand Up @@ -64,9 +64,13 @@ def image(surface, node):
unsafe=node.unsafe)
tree_width, tree_height, viewbox = node_format(
surface, tree, reference=False)
if not viewbox:
if viewbox:
tree_scale_x = tree_width / viewbox[2]
tree_scale_y = tree_height / viewbox[3]
else:
tree_width = tree['width'] = width
tree_height = tree['height'] = height
tree_scale_x = tree_scale_y = 1
node.image_width = tree_width or width
node.image_height = tree_height or height
scale_x, scale_y, translate_x, translate_y = preserve_ratio(
Expand All @@ -79,11 +83,8 @@ def image(surface, node):
# Draw image
surface.context.save()
surface.context.translate(x, y)
surface.set_context_size(
*node_format(surface, tree, reference=False), scale=1,
preserved_ratio=preserved_ratio(tree))
surface.context.translate(*surface.context.get_current_point())
surface.context.scale(scale_x, scale_y)
surface.context.scale(scale_x * tree_scale_x, scale_y * tree_scale_y)
surface.context.translate(translate_x, translate_y)
surface.draw(tree)
surface.context.restore()
Expand Down
54 changes: 26 additions & 28 deletions cairosvg/surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
parse_all_defs, pattern, prepare_filter, radial_gradient, use)
from .helpers import (
UNITS, PointError, apply_matrix_transform, clip_rect, node_format,
normalize, paint, preserved_ratio, size, transform)
normalize, paint, preserve_ratio, size, transform)
from .image import image
from .parser import Tree
from .path import draw_markers, path
Expand Down Expand Up @@ -211,12 +211,7 @@ def __init__(self, tree, output, dpi, parent_surface=None,
self.context.scale(
self.device_units_per_user_units, self.device_units_per_user_units)
# Initial, non-rounded dimensions
if output_width and output_height:
self.set_context_size(
width, height, viewbox, scale, tree)
else:
self.set_context_size(
width, height, viewbox, scale, preserved_ratio(tree))
self.set_context_size(width, height, viewbox, scale, tree)
self.context.move_to(0, 0)
self.draw(tree)

Expand All @@ -240,31 +235,34 @@ def _create_surface(self, width, height):
cairo_surface = self.surface_class(self.output, width, height)
return cairo_surface, width, height

def set_context_size(self, width, height, viewbox, scale, preserved_ratio):
def set_context_size(self, width, height, viewbox, scale, tree):
"""Set the Cairo context size, set the SVG viewport size."""
if viewbox:
x, y, x_size, y_size = viewbox
self.context_width, self.context_height = x_size, y_size
x_ratio, y_ratio = width / x_size, height / y_size
rect_x, rect_y = viewbox[0:2]
tree.image_width = viewbox[2]
tree.image_height = viewbox[3]
else:
rect_x, rect_y = 0, 0
tree.image_width = width
tree.image_height = height

scale_x, scale_y, translate_x, translate_y = preserve_ratio(self, tree)
rect_x, rect_y = rect_x * scale_x, rect_y * scale_y
rect_width, rect_height = width, height
self.context.translate(*self.context.get_current_point())
self.context.translate(-rect_x, -rect_y)
if tree.get('overflow', 'hidden') != 'visible':
self.context.rectangle(rect_x, rect_y, rect_width, rect_height)
self.context.clip()
self.context.scale(scale_x, scale_y)
self.context.translate(translate_x, translate_y)
self.context_width = rect_width / scale_x
self.context_height = rect_height / scale_y

if scale != 1:
matrix = cairo.Matrix()
if preserved_ratio and x_ratio > y_ratio:
matrix.translate((width - x_size * y_ratio) / 2, 0)
matrix.scale(y_ratio, y_ratio)
matrix.translate(-x / x_ratio * y_ratio, -y)
elif preserved_ratio and x_ratio < y_ratio:
matrix.translate(0, (height - y_size * x_ratio) / 2)
matrix.scale(x_ratio, x_ratio)
matrix.translate(-x, -y / y_ratio * x_ratio)
else:
matrix.scale(x_ratio, y_ratio)
matrix.translate(-x, -y)
matrix.scale(scale, scale)
apply_matrix_transform(self, matrix)
else:
self.context_width, self.context_height = width, height
if scale != 1:
matrix = cairo.Matrix()
matrix.scale(scale, scale)
apply_matrix_transform(self, matrix)

def finish(self):
"""Read the surface content."""
Expand Down
29 changes: 4 additions & 25 deletions cairosvg/svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,11 @@
"""

from .helpers import node_format, preserve_ratio
from .helpers import node_format


def svg(surface, node):
"""Draw a svg ``node``."""
width, height, viewbox = node_format(surface, node)
if viewbox:
rect_x, rect_y = viewbox[0:2]
node.image_width = viewbox[2]
node.image_height = viewbox[3]
else:
rect_x, rect_y = 0, 0
node.image_width = width
node.image_height = height

if node.parent is None:
return

scale_x, scale_y, translate_x, translate_y = preserve_ratio(surface, node)
rect_x, rect_y = rect_x * scale_x, rect_y * scale_y
rect_width, rect_height = width, height
surface.context.translate(*surface.context.get_current_point())
surface.context.translate(-rect_x, -rect_y)
if node.get('overflow', 'hidden') != 'visible':
surface.context.rectangle(rect_x, rect_y, rect_width, rect_height)
surface.context.clip()
surface.context.scale(scale_x, scale_y)
surface.context.translate(translate_x, translate_y)
surface.context_width, surface.context_height = rect_width, rect_height
if node.parent is not None:
width, height, viewbox = node_format(surface, node)
surface.set_context_size(width, height, viewbox, 1, node)

0 comments on commit 0d71521

Please sign in to comment.