2018-05-02 01:21:07 +00:00
|
|
|
import simpletransform
|
|
|
|
|
2018-08-22 01:43:09 +00:00
|
|
|
from ..i18n import _
|
2019-06-22 22:10:05 +00:00
|
|
|
from ..utils import cache
|
|
|
|
|
2018-05-02 01:21:07 +00:00
|
|
|
|
|
|
|
# modern versions of Inkscape use 96 pixels per inch as per the CSS standard
|
|
|
|
PIXELS_PER_MM = 96 / 25.4
|
|
|
|
|
|
|
|
# cribbed from inkscape-silhouette
|
|
|
|
|
2018-08-22 00:32:50 +00:00
|
|
|
|
|
|
|
def parse_length_with_units(str):
|
2018-05-02 01:21:07 +00:00
|
|
|
'''
|
|
|
|
Parse an SVG value which may or may not have units attached
|
|
|
|
This version is greatly simplified in that it only allows: no units,
|
|
|
|
units of px, mm, and %. Everything else, it returns None for.
|
|
|
|
There is a more general routine to consider in scour.py if more
|
|
|
|
generality is ever needed.
|
|
|
|
'''
|
|
|
|
|
|
|
|
u = 'px'
|
|
|
|
s = str.strip()
|
|
|
|
if s[-2:] == 'px':
|
|
|
|
s = s[:-2]
|
|
|
|
elif s[-2:] == 'mm':
|
|
|
|
u = 'mm'
|
|
|
|
s = s[:-2]
|
|
|
|
elif s[-2:] == 'pt':
|
|
|
|
u = 'pt'
|
|
|
|
s = s[:-2]
|
|
|
|
elif s[-2:] == 'pc':
|
|
|
|
u = 'pc'
|
|
|
|
s = s[:-2]
|
|
|
|
elif s[-2:] == 'cm':
|
|
|
|
u = 'cm'
|
|
|
|
s = s[:-2]
|
|
|
|
elif s[-2:] == 'in':
|
|
|
|
u = 'in'
|
|
|
|
s = s[:-2]
|
|
|
|
elif s[-1:] == '%':
|
|
|
|
u = '%'
|
|
|
|
s = s[:-1]
|
|
|
|
try:
|
2018-08-22 00:32:50 +00:00
|
|
|
v = float(s)
|
|
|
|
except BaseException:
|
2018-05-02 01:21:07 +00:00
|
|
|
raise ValueError(_("parseLengthWithUnits: unknown unit %s") % s)
|
|
|
|
|
|
|
|
return v, u
|
|
|
|
|
|
|
|
|
|
|
|
def convert_length(length):
|
|
|
|
value, units = parse_length_with_units(length)
|
|
|
|
|
|
|
|
if not units or units == "px":
|
|
|
|
return value
|
|
|
|
|
|
|
|
if units == 'pt':
|
2018-08-22 00:32:50 +00:00
|
|
|
value /= 72
|
|
|
|
units = 'in'
|
2018-05-02 01:21:07 +00:00
|
|
|
|
|
|
|
if units == 'pc':
|
2018-08-22 00:32:50 +00:00
|
|
|
value /= 6
|
|
|
|
units = 'in'
|
2018-05-02 01:21:07 +00:00
|
|
|
|
|
|
|
if units == 'cm':
|
2018-08-22 00:32:50 +00:00
|
|
|
value *= 10
|
|
|
|
units = 'mm'
|
2018-05-02 01:21:07 +00:00
|
|
|
|
|
|
|
if units == 'mm':
|
|
|
|
value = value / 25.4
|
|
|
|
units = 'in'
|
|
|
|
|
|
|
|
if units == 'in':
|
|
|
|
# modern versions of Inkscape use CSS's 96 pixels per inch. When you
|
|
|
|
# open an old document, inkscape will add a viewbox for you.
|
|
|
|
return value * 96
|
|
|
|
|
|
|
|
raise ValueError(_("Unknown unit: %s") % units)
|
|
|
|
|
2018-08-22 00:32:50 +00:00
|
|
|
|
2018-06-10 19:31:10 +00:00
|
|
|
@cache
|
|
|
|
def get_viewbox(svg):
|
2018-09-16 01:03:42 +00:00
|
|
|
viewbox = svg.get('viewBox')
|
|
|
|
if viewbox is None:
|
|
|
|
viewbox = "0 0 0 0"
|
|
|
|
return viewbox.strip().replace(',', ' ').split()
|
2018-06-10 19:31:10 +00:00
|
|
|
|
2018-05-02 01:21:07 +00:00
|
|
|
|
|
|
|
@cache
|
|
|
|
def get_doc_size(svg):
|
2018-06-10 19:31:10 +00:00
|
|
|
width = svg.get('width')
|
|
|
|
height = svg.get('height')
|
|
|
|
|
2019-06-22 22:10:05 +00:00
|
|
|
if width == "100%" and height == "100%":
|
|
|
|
# Some SVG editors set width and height to "100%". I can't find any
|
|
|
|
# solid documentation on how one is supposed to interpret that, so
|
|
|
|
# just ignore it and use the viewBox. That seems to have the intended
|
|
|
|
# result anyway.
|
|
|
|
|
|
|
|
width = None
|
|
|
|
height = None
|
|
|
|
|
2018-06-10 19:31:10 +00:00
|
|
|
if width is None or height is None:
|
|
|
|
# fall back to the dimensions from the viewBox
|
|
|
|
viewbox = get_viewbox(svg)
|
|
|
|
width = viewbox[2]
|
|
|
|
height = viewbox[3]
|
|
|
|
|
|
|
|
doc_width = convert_length(width)
|
|
|
|
doc_height = convert_length(height)
|
2018-05-02 01:21:07 +00:00
|
|
|
|
|
|
|
return doc_width, doc_height
|
|
|
|
|
2018-08-22 00:32:50 +00:00
|
|
|
|
2018-05-02 01:21:07 +00:00
|
|
|
@cache
|
|
|
|
def get_viewbox_transform(node):
|
|
|
|
# somewhat cribbed from inkscape-silhouette
|
|
|
|
doc_width, doc_height = get_doc_size(node)
|
|
|
|
|
2018-06-10 19:31:10 +00:00
|
|
|
viewbox = get_viewbox(node)
|
2018-05-02 01:21:07 +00:00
|
|
|
|
|
|
|
dx = -float(viewbox[0])
|
|
|
|
dy = -float(viewbox[1])
|
|
|
|
transform = simpletransform.parseTransform("translate(%f, %f)" % (dx, dy))
|
|
|
|
|
|
|
|
try:
|
|
|
|
sx = doc_width / float(viewbox[2])
|
|
|
|
sy = doc_height / float(viewbox[3])
|
|
|
|
scale_transform = simpletransform.parseTransform("scale(%f, %f)" % (sx, sy))
|
|
|
|
transform = simpletransform.composeTransform(transform, scale_transform)
|
|
|
|
except ZeroDivisionError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
return transform
|