Implement new backend without cairo
by providing SVGSurface, PSSurface and Context classes Disable post processing as we want to create proper files right away
This commit is contained in:
parent
da0e390789
commit
fd48e57f33
|
@ -14,13 +14,6 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
import cairocffi
|
||||
|
||||
cairocffi.install_as_pycairo()
|
||||
except ImportError:
|
||||
pass
|
||||
import cairo
|
||||
import math
|
||||
import sys
|
||||
import argparse
|
||||
|
@ -614,7 +607,9 @@ class Boxes:
|
|||
return
|
||||
|
||||
self.ctx.stroke()
|
||||
|
||||
self.ctx = None
|
||||
|
||||
self.surface.flush()
|
||||
self.surface.finish()
|
||||
|
||||
|
@ -1093,6 +1088,9 @@ class Boxes:
|
|||
self.moveTo(x, 0)
|
||||
self.ctx.scale(-1, 1)
|
||||
self.moveTo(self.spacing / 2.0, self.spacing / 2.0)
|
||||
|
||||
self.ctx.new_part()
|
||||
|
||||
return dontdraw
|
||||
|
||||
@restore
|
||||
|
|
|
@ -0,0 +1,520 @@
|
|||
import math
|
||||
from affine import Affine
|
||||
from boxes.extents import Extents
|
||||
|
||||
EPS = 1e-4
|
||||
PADDING = 10
|
||||
|
||||
RANDOMIZE_COLORS = False # enable to ease check for continuity of pathes
|
||||
|
||||
|
||||
def points_equal(x1, y1, x2, y2):
|
||||
return abs(x1 - x2) < EPS and abs(y1 - y2) < EPS
|
||||
|
||||
|
||||
def pdiff(p1, p2):
|
||||
x1, y1 = p1
|
||||
x2, y2 = p2
|
||||
return (x1 - x2, y1 - y2)
|
||||
|
||||
|
||||
class Surface:
|
||||
def __init__(self, fname, width, height):
|
||||
self._fname = fname
|
||||
self.parts = []
|
||||
self._p = self.new_part("default")
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
def finish(self):
|
||||
pass
|
||||
|
||||
def render(self, renderer):
|
||||
renderer.init(**self.args)
|
||||
for p in self.parts:
|
||||
p.render(renderer)
|
||||
renderer.finish()
|
||||
|
||||
def move_offset(self, dx, dy):
|
||||
for p in self.parts:
|
||||
p.move_offset(dx, dy)
|
||||
|
||||
def new_part(self, name="part"):
|
||||
if self.parts and len(self.parts[-1].pathes) == 0:
|
||||
return self._p
|
||||
p = Part(name)
|
||||
self.parts.append(p)
|
||||
self._p = p
|
||||
return p
|
||||
|
||||
def append(self, *path):
|
||||
self._p.append(*path)
|
||||
|
||||
def stroke(self, **params):
|
||||
return self._p.stroke(**params)
|
||||
|
||||
def move_to(self, *xy):
|
||||
self._p.move_to(*xy)
|
||||
|
||||
def extents(self):
|
||||
if not self.parts:
|
||||
return Extents()
|
||||
return sum([p.extents() for p in self.parts])
|
||||
|
||||
|
||||
class Part:
|
||||
def __init__(self, name):
|
||||
self.pathes = []
|
||||
self.path = []
|
||||
|
||||
def extents(self):
|
||||
if not self.pathes:
|
||||
return Extents()
|
||||
return sum([p.extents() for p in self.pathes])
|
||||
|
||||
def move_offset(self, dx, dy):
|
||||
assert(not self.path)
|
||||
for p in self.pathes:
|
||||
p.move_offset(dx, dy)
|
||||
|
||||
def append(self, *path):
|
||||
self.path.append(list(path))
|
||||
|
||||
def stroke(self, **params):
|
||||
if len(self.path) == 0:
|
||||
return
|
||||
# search for path ending at new start coordinates to append this path to
|
||||
xy0 = self.path[0][1:3]
|
||||
for p in reversed(self.pathes):
|
||||
if self.path[0][0] == "T":
|
||||
break
|
||||
xy1 = p.path[-1][1:3]
|
||||
if points_equal(*xy0, *xy1):
|
||||
# todo: check for same color and linewidth
|
||||
p.path.extend(self.path[1:])
|
||||
self.path = []
|
||||
return p
|
||||
p = Path(self.path, params)
|
||||
self.pathes.append(p)
|
||||
self.path = []
|
||||
return p
|
||||
|
||||
def move_to(self, *xy):
|
||||
if len(self.path) == 0:
|
||||
self.path.append(["M", *xy])
|
||||
elif self.path[-1][0] == "M":
|
||||
self.path[-1] = ["M", *xy]
|
||||
else:
|
||||
xy0 = self.path[-1][1:3]
|
||||
if not points_equal(*xy0, *xy):
|
||||
self.path.append(["M", *xy])
|
||||
|
||||
|
||||
class Path:
|
||||
def __init__(self, path, params):
|
||||
self.path = path
|
||||
self.params = params
|
||||
# self._extents = None
|
||||
|
||||
def __repr__(self):
|
||||
l = len(self.path)
|
||||
# x1,y1 = self.path[0][1:3]
|
||||
x2, y2 = self.path[-1][1:3]
|
||||
return f"Path[{l}] to ({x2:.2f},{y2:.2f})"
|
||||
|
||||
def extents(self):
|
||||
# if self._extents is not None: return self._extents
|
||||
e = Extents()
|
||||
for p in self.path:
|
||||
e.add(*p[1:3])
|
||||
return e
|
||||
|
||||
def move_offset(self, dx, dy):
|
||||
for c in self.path:
|
||||
C = c[0]
|
||||
c[1] += dx
|
||||
c[2] += dy
|
||||
if C == 'C':
|
||||
c[3] += dx
|
||||
c[4] += dy
|
||||
c[5] += dx
|
||||
c[6] += dy
|
||||
|
||||
def faster_edges(self):
|
||||
for (i, p) in enumerate(self.path):
|
||||
if p[0] == "C" and i > 1 and i < len(self.path) - 1:
|
||||
if self.path[i - 1][0] == "L" and self.path[i + 1][0] == "L":
|
||||
p11 = self.path[i - 2][1:3]
|
||||
p12 = self.path[i - 1][1:3]
|
||||
p21 = p[1:3]
|
||||
p22 = self.path[i + 1][1:3]
|
||||
if (((p12[0]-p21[0])**2 + (p12[1]-p21[1])**2) >
|
||||
self.params["lw"]**2):
|
||||
continue
|
||||
lines_intersect, x, y = line_intersection((p11, p12), (p21, p22))
|
||||
if lines_intersect:
|
||||
self.path[i - 1] = ("L", x, y)
|
||||
self.path[i] = ("C", x, y, *p12, *p21)
|
||||
|
||||
|
||||
class Context:
|
||||
def __init__(self, surface, *al, **ad):
|
||||
self._renderer = self._dwg = surface
|
||||
|
||||
self._bounds = Extents()
|
||||
self._padding = PADDING
|
||||
|
||||
self._stack = []
|
||||
self._m = Affine.translation(0, 0)
|
||||
self._xy = (0, 0)
|
||||
self._mxy = self._m * self._xy
|
||||
self._lw = 0
|
||||
self._rgb = (0, 0, 0)
|
||||
self._ff = "sans-serif"
|
||||
self._last_path = None
|
||||
|
||||
def _update_bounds_(self, mx, my):
|
||||
self._bounds.update(mx, my)
|
||||
|
||||
def save(self):
|
||||
self._stack.append(
|
||||
(self._m, self._xy, self._lw, self._rgb, self._mxy, self._last_path)
|
||||
)
|
||||
self._xy = (0, 0)
|
||||
|
||||
def restore(self):
|
||||
(
|
||||
self._m,
|
||||
self._xy,
|
||||
self._lw,
|
||||
self._rgb,
|
||||
self._mxy,
|
||||
self._last_path,
|
||||
) = self._stack.pop()
|
||||
|
||||
## transformations
|
||||
|
||||
def translate(self, x, y):
|
||||
self._m *= Affine.translation(x, y)
|
||||
self._xy = (0, 0)
|
||||
|
||||
def scale(self, sx, sy):
|
||||
self._m *= Affine.scale(sx, sy)
|
||||
|
||||
def rotate(self, r):
|
||||
self._m *= Affine.rotation(180 * r / math.pi)
|
||||
|
||||
def set_line_width(self, lw):
|
||||
self._lw = lw
|
||||
|
||||
def set_source_rgb(self, r, g, b):
|
||||
self._rgb = (r, g, b)
|
||||
|
||||
## path methods
|
||||
|
||||
def _line_to(self, x, y):
|
||||
self._add_move()
|
||||
x1, y1 = self._mxy
|
||||
self._xy = x, y
|
||||
x2, y2 = self._mxy = self._m * self._xy
|
||||
if not points_equal(x1, y1, x2, y2):
|
||||
self._dwg.append("L", x2, y2)
|
||||
|
||||
def _add_move(self):
|
||||
self._dwg.move_to(*self._mxy)
|
||||
|
||||
def move_to(self, x, y):
|
||||
self._xy = (x, y)
|
||||
self._mxy = self._m * self._xy
|
||||
|
||||
def line_to(self, x, y):
|
||||
self._line_to(x, y)
|
||||
|
||||
def _arc(self, xc, yc, radius, angle1, angle2, direction):
|
||||
x1, y1 = radius * math.cos(angle1) + xc, radius * math.sin(angle1) + yc
|
||||
x4, y4 = radius * math.cos(angle2) + xc, radius * math.sin(angle2) + yc
|
||||
|
||||
# XXX direction seems not needed for small arcs
|
||||
ax = x1 - xc
|
||||
ay = y1 - yc
|
||||
bx = x4 - xc
|
||||
by = y4 - yc
|
||||
q1 = ax * ax + ay * ay
|
||||
q2 = q1 + ax * bx + ay * by
|
||||
k2 = 4/3 * ((2 * q1 * q2)**0.5 - q2) / (ax * by - ay * bx)
|
||||
|
||||
x2 = xc + ax - k2 * ay
|
||||
y2 = yc + ay + k2 * ax
|
||||
x3 = xc + bx + k2 * by
|
||||
y3 = yc + by - k2 * bx
|
||||
|
||||
mx1, my1 = self._m * (x1, y1)
|
||||
mx2, my2 = self._m * (x2, y2)
|
||||
mx3, my3 = self._m * (x3, y3)
|
||||
mx4, my4 = self._m * (x4, y4)
|
||||
mxc, myc = self._m * (xc, yc)
|
||||
|
||||
self._add_move()
|
||||
self._dwg.append("C", mx4, my4, mx2, my2, mx3, my3)
|
||||
self._xy = (x4, y4)
|
||||
self._mxy = (mx4, my4)
|
||||
|
||||
def arc(self, xc, yc, radius, angle1, angle2):
|
||||
self._arc(xc, yc, radius, angle1, angle2, 1)
|
||||
|
||||
def arc_negative(self, xc, yc, radius, angle1, angle2):
|
||||
self._arc(xc, yc, radius, angle1, angle2, -1)
|
||||
|
||||
def curve_to(self, x1, y1, x2, y2, x3, y3):
|
||||
# mx0,my0 = self._m*self._xy
|
||||
mx1, my1 = self._m * (x1, y1)
|
||||
mx2, my2 = self._m * (x2, y2)
|
||||
mx3, my3 = self._m * (x3, y3)
|
||||
self._add_move()
|
||||
self._dwg.append("C", mx3, my3, mx1, my1, mx2, my2) # destination first!
|
||||
self._xy = (x3, y3)
|
||||
|
||||
def stroke(self):
|
||||
# print('stroke stack-level=',len(self._stack),'lastpath=',self._last_path,)
|
||||
self._last_path = self._dwg.stroke(rgb=self._rgb, lw=self._lw)
|
||||
self._xy = (0, 0)
|
||||
|
||||
def fill(self):
|
||||
self._xy = (0, 0)
|
||||
raise NotImplementedError()
|
||||
|
||||
def select_font_face(self, ff):
|
||||
self._ff = ff
|
||||
|
||||
def set_font_size(self, fs):
|
||||
self._fs = fs
|
||||
|
||||
def show_text(self, text, **args):
|
||||
params = {"ff": self._ff, "fs": self._fs, "lw": self._lw, "rgb": self._rgb}
|
||||
params.update(args)
|
||||
mx0, my0 = self._m * self._xy
|
||||
self._dwg.append("T", mx0, my0, text, params)
|
||||
|
||||
def text_extents(self, text):
|
||||
fs = self._fs
|
||||
# XXX ugly hack! Fix Boxes.text() !
|
||||
return (0, 0, 0.6 * fs * len(text), 0.65 * fs, fs * 0.1, 0)
|
||||
|
||||
def rectangle(self, x, y, width, height):
|
||||
|
||||
# todo: better check for empty path?
|
||||
self.stroke()
|
||||
|
||||
self.move_to(x, y)
|
||||
self.line_to(x + width, y)
|
||||
self.line_to(x + width, y + height)
|
||||
self.line_to(x, y + height)
|
||||
self.line_to(x, y)
|
||||
self.stroke()
|
||||
|
||||
def get_current_point(self):
|
||||
return self._xy
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
# todo: check, if needed
|
||||
# self.stroke()
|
||||
|
||||
## additional methods
|
||||
def new_part(self):
|
||||
self._dwg.new_part()
|
||||
|
||||
|
||||
class SVGSurface(Surface):
|
||||
def finish(self):
|
||||
import svgwrite
|
||||
|
||||
extents = self.extents()
|
||||
|
||||
self.move_offset(-extents.xmin + PADDING,
|
||||
-extents.ymin + PADDING)
|
||||
w = extents.width + 2 * PADDING
|
||||
h = extents.height + 2 * PADDING
|
||||
|
||||
dwg = svgwrite.Drawing(filename=self._fname, debug=False)
|
||||
# dwg.debug = False
|
||||
|
||||
dwg["width"] = f"{w:.2f}mm"
|
||||
dwg["height"] = f"{h:.2f}mm"
|
||||
dwg["viewBox"] = f"0.0 0.0 {w:.2f} {h:.2f}"
|
||||
|
||||
for i, part in enumerate(self.parts):
|
||||
if not part.pathes:
|
||||
continue
|
||||
g = dwg.add(
|
||||
dwg.g(
|
||||
id=f"p-{i}",
|
||||
style="fill:none;stroke-linecap:round;stroke-linejoin:round;",
|
||||
)
|
||||
)
|
||||
for j, path in enumerate(part.pathes):
|
||||
p = []
|
||||
x, y = 0, 0
|
||||
path.faster_edges()
|
||||
for c in path.path:
|
||||
x0, y0 = x, y
|
||||
C, x, y = c[0:3]
|
||||
if C == "M":
|
||||
p.append(f"M {x:.3f} {y:.3f}")
|
||||
elif C == "L":
|
||||
p.append(f"L {x:.3f} {y:.3f}")
|
||||
elif C == "C":
|
||||
x1, y1, x2, y2 = c[3:]
|
||||
p.append(
|
||||
f"C {x1:.3f} {y1:.3f} {x2:.3f} {y2:.3f} {x:.3f} {y:.3f}"
|
||||
)
|
||||
elif C == "T":
|
||||
text, params = c[3:]
|
||||
style = f"font: {params['ff']} ; fill: {rgb_to_svg_color(*params['rgb'])}"
|
||||
g.add(
|
||||
dwg.text(
|
||||
text,
|
||||
x=[x],
|
||||
y=[y],
|
||||
font_size=f"{params['fs']}px",
|
||||
style=style,
|
||||
)
|
||||
)
|
||||
else:
|
||||
print("Unknown", c)
|
||||
color = (
|
||||
random_svg_color()
|
||||
if RANDOMIZE_COLORS
|
||||
else rgb_to_svg_color(*path.params["rgb"])
|
||||
)
|
||||
if p: # todo: might be empty since text is not implemented yet
|
||||
g.add(
|
||||
dwg.path(
|
||||
d=" ".join(p), stroke=color, stroke_width=path.params["lw"]
|
||||
)
|
||||
)
|
||||
dwg.save(pretty=True)
|
||||
|
||||
|
||||
class PSSurface(Surface):
|
||||
|
||||
def finish(self):
|
||||
|
||||
extents = self.extents()
|
||||
|
||||
self.move_offset(-extents.xmin + PADDING,
|
||||
-extents.ymin + PADDING)
|
||||
|
||||
w = extents.width + 2 * PADDING
|
||||
h = extents.height + 2 * PADDING
|
||||
|
||||
f = open(self._fname, "w")
|
||||
|
||||
f.write("%!PS-Adobe-2.0\n")
|
||||
f.write(
|
||||
f"%%BoundingBox: 0 0 {w:.0f} {h:.0f}\n\n"
|
||||
)
|
||||
# f.write(f"%%DocumentMedia: \d+x\d+mm ((\d+) (\d+)) 0 \("
|
||||
# dwg['width']=f'{w:.2f}mm'
|
||||
# dwg['height']=f'{h:.2f}mm'
|
||||
|
||||
for i, part in enumerate(self.parts):
|
||||
if not part.pathes:
|
||||
continue
|
||||
# g = dwg.add( dwg.g(id=f'p-{i}',style='fill:none;stroke-linecap:round;stroke-linejoin:round;') )
|
||||
for j, path in enumerate(part.pathes):
|
||||
p = []
|
||||
x, y = 0, 0
|
||||
path.faster_edges()
|
||||
|
||||
for c in path.path:
|
||||
x0, y0 = x, y
|
||||
C, x, y = c[0:3]
|
||||
if C == "M":
|
||||
p.append(f"{x:.3f} {y:.3f} moveto")
|
||||
elif C == "L":
|
||||
p.append(f"{x:.3f} {y:.3f} lineto")
|
||||
elif C == "C":
|
||||
x1, y1, x2, y2 = c[3:]
|
||||
p.append(
|
||||
f"{x1:.3f} {y1:.3f} {x2:.3f} {y2:.3f} {x:.3f} {y:.3f} curveto"
|
||||
)
|
||||
elif C == "T":
|
||||
text, params = c[3:]
|
||||
text = text.replace("(", "r\(").replace(")", r"\)")
|
||||
color = " ".join((f"{c:.2f}"
|
||||
for c in params["rgb"]))
|
||||
f.write(f"/{params['ff']} findfont\n")
|
||||
f.write(f"{params['fs']*72 / 25.4} scalefont\n")
|
||||
f.write("setfont\n")
|
||||
f.write(f"{color} setrgbcolor\n")
|
||||
f.write(f"{x:.3f} {y:.3f} moveto\n")
|
||||
f.write(f"({text}) show\n\n")
|
||||
else:
|
||||
print("Unknown", c)
|
||||
color = (
|
||||
random_svg_color()
|
||||
if RANDOMIZE_COLORS
|
||||
else rgb_to_svg_color(*path.params["rgb"])
|
||||
)
|
||||
if p: # todo: might be empty since text is not implemented yet
|
||||
color = " ".join((f"{c:.2f}"
|
||||
for c in path.params["rgb"]))
|
||||
f.write("newpath\n")
|
||||
f.write("\n".join(p))
|
||||
f.write("\n")
|
||||
f.write(f"{path.params['lw']} setlinewidth\n")
|
||||
f.write(f"{color} setrgbcolor\n")
|
||||
f.write("stroke\n\n")
|
||||
f.write(
|
||||
"""
|
||||
showpage
|
||||
%%Trailer
|
||||
%%EOF
|
||||
"""
|
||||
)
|
||||
f.close()
|
||||
|
||||
|
||||
from random import random
|
||||
|
||||
|
||||
def random_svg_color():
|
||||
r, g, b = random(), random(), random()
|
||||
return f"rgb({r*255:.0f},{g*255:.0f},{b*255:.0f})"
|
||||
|
||||
|
||||
def rgb_to_svg_color(r, g, b):
|
||||
return f"rgb({r*255:.0f},{g*255:.0f},{b*255:.0f})"
|
||||
|
||||
|
||||
def line_intersection(line1, line2):
|
||||
|
||||
xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
|
||||
ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1])
|
||||
|
||||
def det(a, b):
|
||||
return a[0] * b[1] - a[1] * b[0]
|
||||
|
||||
div = det(xdiff, ydiff)
|
||||
if div == 0:
|
||||
# todo: deal with paralel line intersection / overlay
|
||||
return False, None, None
|
||||
|
||||
d = (det(*line1), det(*line2))
|
||||
x = det(d, xdiff) / div
|
||||
y = det(d, ydiff) / div
|
||||
|
||||
on_segments = (
|
||||
(x + EPS >= min(line1[0][0], line1[1][0])),
|
||||
(x + EPS >= min(line2[0][0], line2[1][0])),
|
||||
(x - EPS <= max(line1[0][0], line1[1][0])),
|
||||
(x - EPS <= max(line2[0][0], line2[1][0])),
|
||||
(y + EPS >= min(line1[0][1], line1[1][1])),
|
||||
(y + EPS >= min(line2[0][1], line2[1][1])),
|
||||
(y - EPS <= max(line1[0][1], line1[1][1])),
|
||||
(y - EPS <= max(line2[0][1], line2[1][1])),
|
||||
)
|
||||
|
||||
return min(on_segments), x, y
|
|
@ -0,0 +1,44 @@
|
|||
class Extents:
|
||||
__slots__ = "xmin ymin xmax ymax".split()
|
||||
|
||||
def __init__(self,xmin=float('inf'),ymin=float('inf'),xmax=float('-inf'),ymax=float('-inf')):
|
||||
self.xmin = xmin
|
||||
self.ymin = ymin
|
||||
self.xmax = xmax
|
||||
self.ymax = ymax
|
||||
|
||||
def add(self,x,y):
|
||||
self.xmin = min(self.xmin,x)
|
||||
self.xmax = max(self.xmax,x)
|
||||
self.ymin = min(self.ymin,y)
|
||||
self.ymax = max(self.ymax,y)
|
||||
|
||||
def extend(self,l):
|
||||
for x,y in l:
|
||||
self.add(x,y)
|
||||
|
||||
def __add__(self,extent):
|
||||
#todo: why can this happen?
|
||||
if extent ==0:
|
||||
return Extents(self.xmin,self.ymin,self.xmax,self.ymax)
|
||||
return Extents(
|
||||
min(self.xmin,extent.xmin),min(self.ymin,extent.ymin),
|
||||
max(self.xmax,extent.xmax),max(self.ymax,extent.ymax)
|
||||
)
|
||||
|
||||
def __radd__(self,extent):
|
||||
if extent == 0:
|
||||
return Extents(self.xmin,self.ymin,self.xmax,self.ymax)
|
||||
return self.__add__(extent)
|
||||
|
||||
def get_width(self):
|
||||
return self.xmax-self.xmin
|
||||
|
||||
def get_height(self):
|
||||
return self.ymax-self.ymin
|
||||
|
||||
width = property(get_width)
|
||||
height = property(get_height)
|
||||
|
||||
def __repr__(self):
|
||||
return f'Extents ({self.xmin},{self.ymin})-({self.xmax},{self.ymax})'
|
|
@ -18,15 +18,14 @@
|
|||
import subprocess
|
||||
import tempfile
|
||||
import os
|
||||
import cairo
|
||||
import re
|
||||
from boxes import svgutil
|
||||
from boxes.drawing import SVGSurface, PSSurface, Context
|
||||
|
||||
class PSFile:
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
|
||||
def adjustDocumentMedia(self):
|
||||
return
|
||||
with open(self.filename, "r+") as f:
|
||||
s = f.read(1024)
|
||||
m = re.search(r"%%BoundingBox: (\d+) (\d+) (\d+) (\d+)", s)
|
||||
|
@ -83,17 +82,20 @@ class Formats:
|
|||
width = height = 10000 # mm
|
||||
|
||||
if fmt in ("svg", "svg_Ponoko"):
|
||||
surface = cairo.SVGSurface(filename, width, height)
|
||||
surface = SVGSurface(filename, width, height)
|
||||
mm2pt = 1.0
|
||||
else:
|
||||
mm2pt = 72 / 25.4
|
||||
width *= mm2pt
|
||||
height *= mm2pt # 3.543307
|
||||
surface = cairo.PSSurface(filename, width, height)
|
||||
surface = PSSurface(filename, width, height)
|
||||
|
||||
ctx = cairo.Context(surface)
|
||||
ctx = Context(surface)
|
||||
if fmt in ("svg", "svg_Ponoko"):
|
||||
ctx.translate(0, height)
|
||||
ctx.scale(mm2pt, -mm2pt)
|
||||
else:
|
||||
ctx.scale(mm2pt, mm2pt)
|
||||
|
||||
return surface, ctx
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ class SVGFile(object):
|
|||
self.symbol_extends = {}
|
||||
|
||||
def fix(self, metadata=None):
|
||||
return
|
||||
#print("Optimizations:",
|
||||
self.optimize(self.tree.getroot())
|
||||
self.getEnvelope()
|
||||
|
|
Loading…
Reference in New Issue