diff --git a/cairosvg/helpers.py b/cairosvg/helpers.py index 2112497b..ec254c49 100644 --- a/cairosvg/helpers.py +++ b/cairosvg/helpers.py @@ -113,11 +113,6 @@ 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': @@ -125,12 +120,9 @@ def preserve_ratio(surface, node): 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 diff --git a/cairosvg/image.py b/cairosvg/image.py index 44448b7c..38279f8e 100644 --- a/cairosvg/image.py +++ b/cairosvg/image.py @@ -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 @@ -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( @@ -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() diff --git a/cairosvg/surface.py b/cairosvg/surface.py index bfe3d26d..69b08bbb 100644 --- a/cairosvg/surface.py +++ b/cairosvg/surface.py @@ -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 @@ -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) @@ -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.""" diff --git a/cairosvg/svg.py b/cairosvg/svg.py index bdebdc5c..52871603 100644 --- a/cairosvg/svg.py +++ b/cairosvg/svg.py @@ -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)