py3: Full fix for svg2painterpath (I hope)

This commit is contained in:
Kovid Goyal 2019-04-15 12:10:13 +05:30
parent e5b32b2c2f
commit 3d795076c6
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 33 additions and 23 deletions

View File

@ -495,7 +495,11 @@ class Ornamental(Style):
def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block): def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block):
if not self.PATH_CACHE: if not self.PATH_CACHE:
from calibre.utils.speedups import svg_path_to_painter_path from calibre.utils.speedups import svg_path_to_painter_path
self.__class__.PATH_CACHE['corner'] = svg_path_to_painter_path(self.CORNER_VECTOR) try:
self.__class__.PATH_CACHE['corner'] = svg_path_to_painter_path(self.CORNER_VECTOR)
except Exception:
import traceback
traceback.print_exc()
p = painter p = painter
painter.setRenderHint(QPainter.Antialiasing) painter.setRenderHint(QPainter.Antialiasing)
g = QRadialGradient(QPointF(rect.center()), rect.width()) g = QRadialGradient(QPointF(rect.center()), rect.width())
@ -503,7 +507,10 @@ class Ornamental(Style):
painter.fillRect(rect, QBrush(g)) painter.fillRect(rect, QBrush(g))
painter.save() painter.save()
painter.setWindow(0, 0, *self.VIEWPORT) painter.setWindow(0, 0, *self.VIEWPORT)
path = self.PATH_CACHE['corner'] try:
path = self.PATH_CACHE['corner']
except KeyError:
path = QPainterPath()
pen = p.pen() pen = p.pen()
pen.setColor(self.ccolor1) pen.setColor(self.ccolor1)
p.setPen(pen) p.setPen(pen)

View File

@ -55,15 +55,15 @@ def svg_path_to_painter_path(d):
from PyQt5.Qt import QPainterPath from PyQt5.Qt import QPainterPath
cmd = last_cmd = b'' cmd = last_cmd = b''
path = QPainterPath() path = QPainterPath()
moveto_abs, moveto_rel = b'Mm' moveto_abs, moveto_rel = b'M', b'm'
closepath1, closepath2 = b'Zz' closepath1, closepath2 = b'Z', b'z'
lineto_abs, lineto_rel = b'Ll' lineto_abs, lineto_rel = b'L', b'l'
hline_abs, hline_rel = b'Hh' hline_abs, hline_rel = b'H', b'h'
vline_abs, vline_rel = b'Vv' vline_abs, vline_rel = b'V', b'v'
curveto_abs, curveto_rel = b'Cc' curveto_abs, curveto_rel = b'C', b'c'
smoothcurveto_abs, smoothcurveto_rel = b'Ss' smoothcurveto_abs, smoothcurveto_rel = b'S', b's'
quadcurveto_abs, quadcurveto_rel = b'Qq' quadcurveto_abs, quadcurveto_rel = b'Q', b'q'
smoothquadcurveto_abs, smoothquadcurveto_rel = b'Tt' smoothquadcurveto_abs, smoothquadcurveto_rel = b'T', b't'
# Store the last parsed values # Store the last parsed values
# x/y = end position # x/y = end position
@ -74,16 +74,21 @@ def svg_path_to_painter_path(d):
d = d.encode('ascii') d = d.encode('ascii')
d = d.replace(b',', b' ').replace(b'\n', b' ') d = d.replace(b',', b' ').replace(b'\n', b' ')
end = len(d) end = len(d)
data = ReadOnlyFileBuffer(d) pos = [0]
def read_byte():
p = pos[0]
pos[0] += 1
return d[p:p+1]
def parse_float(): def parse_float():
chars = [] chars = []
while data.tell() < end: while pos[0] < end:
c = data.read(1) c = read_byte()
if c == b' ' and not chars: if c == b' ' and not chars:
continue continue
if c == b'-' or b'0' <= c[0] <= b'9' or c == b'.': if c in b'-.0123456789':
chars.append(c[0]) chars.append(c)
else: else:
break break
if not chars: if not chars:
@ -97,16 +102,14 @@ def svg_path_to_painter_path(d):
repeated_command = None repeated_command = None
while data.tell() < end: while pos[0] < end:
last_cmd = cmd last_cmd = cmd
cmd = data.read(1) if repeated_command is None else repeated_command cmd = read_byte() if repeated_command is None else repeated_command
if isinstance(cmd, memoryview):
cmd = cmd.tobytes()
repeated_command = None repeated_command = None
if cmd == b' ': if cmd == b' ':
continue continue
elif cmd == moveto_abs: if cmd == moveto_abs:
x, y = parse_float(), parse_float() x, y = parse_float(), parse_float()
path.moveTo(x, y) path.moveTo(x, y)
elif cmd == moveto_rel: elif cmd == moveto_rel:
@ -178,11 +181,11 @@ def svg_path_to_painter_path(d):
x1, y1 = x, y x1, y1 = x, y
x, y = parse_floats(2, x, y) x, y = parse_floats(2, x, y)
path.quadTo(x1, y1, x, y) path.quadTo(x1, y1, x, y)
elif cmd[0:1] in b'-.0123456789': elif cmd in b'-.0123456789':
# A new number begins # A new number begins
# In this case, multiple parameters tuples are specified for the last command # In this case, multiple parameters tuples are specified for the last command
# We rewind to reparse data correctly # We rewind to reparse data correctly
data.seek(-1, os.SEEK_CUR) pos[0] -= 1
# Handle extra parameters # Handle extra parameters
if last_cmd == moveto_abs: if last_cmd == moveto_abs: