diff --git a/cairosvg/__init__.py b/cairosvg/__init__.py index 1ce5b344..88703dc4 100644 --- a/cairosvg/__init__.py +++ b/cairosvg/__init__.py @@ -38,62 +38,71 @@ def svg2svg(bytestring=None, *, file_obj=None, url=None, dpi=96, parent_width=None, parent_height=None, scale=1, unsafe=False, background_color=None, negate_colors=False, invert_images=False, - write_to=None, output_width=None, output_height=None): + write_to=None, output_width=None, output_height=None, + viewbox_id=None): return surface.SVGSurface.convert( bytestring=bytestring, file_obj=file_obj, url=url, dpi=dpi, parent_width=parent_width, parent_height=parent_height, scale=scale, background_color=background_color, negate_colors=negate_colors, invert_images=invert_images, unsafe=unsafe, write_to=write_to, output_width=output_width, - output_height=output_height) + output_height=output_height, viewbox_id=viewbox_id) def svg2png(bytestring=None, *, file_obj=None, url=None, dpi=96, parent_width=None, parent_height=None, scale=1, unsafe=False, background_color=None, negate_colors=False, invert_images=False, - write_to=None, output_width=None, output_height=None): + write_to=None, output_width=None, output_height=None, + viewbox_id=None): return surface.PNGSurface.convert( bytestring=bytestring, file_obj=file_obj, url=url, dpi=dpi, parent_width=parent_width, parent_height=parent_height, scale=scale, background_color=background_color, negate_colors=negate_colors, invert_images=invert_images, unsafe=unsafe, write_to=write_to, - output_width=output_width, output_height=output_height) + output_width=output_width, output_height=output_height, + viewbox_id=viewbox_id) def svg2pdf(bytestring=None, *, file_obj=None, url=None, dpi=96, parent_width=None, parent_height=None, scale=1, unsafe=False, background_color=None, negate_colors=False, invert_images=False, - write_to=None, output_width=None, output_height=None): + write_to=None, output_width=None, output_height=None, + viewbox_id=None): return surface.PDFSurface.convert( bytestring=bytestring, file_obj=file_obj, url=url, dpi=dpi, parent_width=parent_width, parent_height=parent_height, scale=scale, background_color=background_color, negate_colors=negate_colors, invert_images=invert_images, unsafe=unsafe, write_to=write_to, - output_width=output_width, output_height=output_height) + output_width=output_width, output_height=output_height, + viewbox_id=viewbox_id) def svg2ps(bytestring=None, *, file_obj=None, url=None, dpi=96, parent_width=None, parent_height=None, scale=1, unsafe=False, background_color=None, negate_colors=False, invert_images=False, - write_to=None, output_width=None, output_height=None): + write_to=None, output_width=None, output_height=None, + viewbox_id=None): return surface.PSSurface.convert( bytestring=bytestring, file_obj=file_obj, url=url, dpi=dpi, parent_width=parent_width, parent_height=parent_height, scale=scale, background_color=background_color, negate_colors=negate_colors, invert_images=invert_images, unsafe=unsafe, write_to=write_to, - output_width=output_width, output_height=output_height) + output_width=output_width, output_height=output_height, + viewbox_id=viewbox_id) def svg2eps(bytestring=None, *, file_obj=None, url=None, dpi=96, parent_width=None, parent_height=None, scale=1, unsafe=False, background_color=None, negate_colors=False, invert_images=False, - write_to=None, output_width=None, output_height=None): + write_to=None, output_width=None, output_height=None, + viewbox_id=None): return surface.EPSSurface.convert( bytestring=bytestring, file_obj=file_obj, url=url, dpi=dpi, parent_width=parent_width, parent_height=parent_height, scale=scale, background_color=background_color, negate_colors=negate_colors, invert_images=invert_images, unsafe=unsafe, write_to=write_to, - output_width=output_width, output_height=output_height) + output_width=output_width, output_height=output_height, + viewbox_id=viewbox_id) if __debug__: diff --git a/cairosvg/__main__.py b/cairosvg/__main__.py index 3ff6b5d1..9d776abd 100644 --- a/cairosvg/__main__.py +++ b/cairosvg/__main__.py @@ -50,6 +50,9 @@ def main(argv=None, stdout=None, stdin=None): parser.add_argument( '--output-height', default=None, type=float, help='desired output height in pixels') + parser.add_argument( + '--viewbox-id', default=None, + help='export viewbox defined by the element with the given id') parser.add_argument('-o', '--output', default='-', help='output filename') @@ -61,7 +64,8 @@ def main(argv=None, stdout=None, stdin=None): 'negate_colors': options.negate_colors, 'invert_images': options.invert_images, 'output_width': options.output_width, - 'output_height': options.output_height} + 'output_height': options.output_height, + 'viewbox_id': options.viewbox_id} stdin = stdin or sys.stdin stdout = stdout or sys.stdout kwargs['write_to'] = ( diff --git a/cairosvg/helpers.py b/cairosvg/helpers.py index c3fea7f8..e29c16ed 100644 --- a/cairosvg/helpers.py +++ b/cairosvg/helpers.py @@ -386,3 +386,16 @@ def size(surface, string, reference='xy'): # Unknown size return 0 + + +def find_child(node, element_id, default=None): + if element_id is not None: + if node.element.id == element_id: + return node + + for child in node.children: + found = find_child(child, element_id) + if found is not None: + return found + + return default diff --git a/cairosvg/surface.py b/cairosvg/surface.py index c5569e76..7206135e 100644 --- a/cairosvg/surface.py +++ b/cairosvg/surface.py @@ -8,13 +8,14 @@ import cairocffi as cairo +from .bounding_box import calculate_bounding_box from .colors import color, negate_color from .defs import ( apply_filter_after_painting, apply_filter_before_painting, clip_path, filter_, gradient_or_pattern, linear_gradient, marker, mask, paint_mask, parse_all_defs, pattern, prepare_filter, radial_gradient, use) from .helpers import ( - UNITS, PointError, clip_rect, node_format, normalize, paint, + UNITS, PointError, clip_rect, find_child, node_format, normalize, paint, preserve_ratio, size, transform) from .image import image, invert_image from .parser import Tree @@ -96,6 +97,7 @@ class Surface(object): @classmethod def convert(cls, bytestring=None, *, file_obj=None, url=None, dpi=96, parent_width=None, parent_height=None, scale=1, unsafe=False, + viewbox_id=None, background_color=None, negate_colors=False, invert_images=False, write_to=None, output_width=None, output_height=None, **kwargs): @@ -115,6 +117,7 @@ def convert(cls, bytestring=None, *, file_obj=None, url=None, dpi=96, :param scale: The ouptut scaling factor. :param unsafe: A boolean allowing XML entities and very large files (WARNING: vulnerable to XXE attacks and various DoS). + :param viewbox_id: SVG element id defining the area to export. Specifiy the output with: @@ -132,6 +135,7 @@ def convert(cls, bytestring=None, *, file_obj=None, url=None, dpi=96, instance = cls( tree, output, dpi, None, parent_width, parent_height, scale, output_width, output_height, background_color, + viewbox_id=viewbox_id if viewbox_id else None, map_rgba=negate_color if negate_colors else None, map_image=invert_image if invert_images else None) instance.finish() @@ -141,7 +145,8 @@ def convert(cls, bytestring=None, *, file_obj=None, url=None, dpi=96, def __init__(self, tree, output, dpi, parent_surface=None, parent_width=None, parent_height=None, scale=1, output_width=None, output_height=None, - background_color=None, map_rgba=None, map_image=None): + background_color=None, map_rgba=None, map_image=None, + viewbox_id=None): """Create the surface from a filename or a file-like object. The rendered content is written to ``output`` which can be a filename, @@ -179,7 +184,17 @@ def __init__(self, tree, output, dpi, parent_surface=None, self.dpi = dpi self.font_size = size(self, '12pt') self.stroke_and_fill = True - width, height, viewbox = node_format(self, tree) + + width, height, viewbox = (0, 0, None) + viewbox_node = find_child(tree, viewbox_id) + if viewbox_node: + viewbox = calculate_bounding_box(self, viewbox_node) + if viewbox: + width, height = viewbox[2:] + + if viewbox is None: + width, height, viewbox = node_format(self, tree) + if viewbox is None: viewbox = (0, 0, width, height)