1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
# Authors: see git history
#
# Copyright (c) 2010 Authors
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
import inkex
from ..i18n import _
from ..utils import cache
# modern versions of Inkscape use 96 pixels per inch as per the CSS standard
PIXELS_PER_MM = 96 / 25.4
def parse_length_with_units(str):
value, unit = inkex.units.parse_unit(str)
if not unit:
raise ValueError(_("parseLengthWithUnits: unknown unit %s") % str)
return value, unit
"""
'''
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.
'''
# cribbed from inkscape-silhouette
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:
v = float(s)
except BaseException:
raise ValueError(_("parseLengthWithUnits: unknown unit %s") % s)
return v, u
"""
def convert_length(length):
value, units = parse_length_with_units(length)
return inkex.units.convert_unit(str(value) + units, 'px')
"""
if not units or units == "px":
return value
if units == 'pt':
value /= 72
units = 'in'
if units == 'pc':
value /= 6
units = 'in'
if units == 'cm':
value *= 10
units = 'mm'
if units == 'mm':
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)
"""
@cache
def get_viewbox(svg):
viewbox = svg.get('viewBox')
if viewbox is None:
viewbox = "0 0 0 0"
return viewbox.strip().replace(',', ' ').split()
@cache
def get_doc_size(svg):
width = svg.get('width')
height = svg.get('height')
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
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)
return doc_width, doc_height
@cache
def get_viewbox_transform(node):
# somewhat cribbed from inkscape-silhouette
doc_width, doc_height = get_doc_size(node)
viewbox = get_viewbox(node)
dx = -float(viewbox[0])
dy = -float(viewbox[1])
transform = inkex.transforms.Transform("translate(%f, %f)" % (dx, dy))
try:
sx = doc_width / float(viewbox[2])
sy = doc_height / float(viewbox[3])
# preserve aspect ratio
aspect_ratio = node.get('preserveAspectRatio', 'xMidYMid meet')
if aspect_ratio != 'none':
sx = sy = max(sx, sy) if 'slice' in aspect_ratio else min(sx, sy)
scale_transform = inkex.transforms.Transform("scale(%f, %f)" % (sx, sy))
transform = transform @ scale_transform
except ZeroDivisionError:
pass
return transform
|