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

Configurable exported viewbox #351

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
29 changes: 19 additions & 10 deletions cairosvg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__:
Expand Down
6 changes: 5 additions & 1 deletion cairosvg/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand All @@ -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'] = (
Expand Down
13 changes: 13 additions & 0 deletions cairosvg/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
21 changes: 18 additions & 3 deletions cairosvg/surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand All @@ -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:

Expand All @@ -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()
Expand All @@ -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,
Expand Down Expand Up @@ -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)

Expand Down