From 3d795076c6b098ba378e1b695acfeb55d4aedbd4 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 15 Apr 2019 12:10:13 +0530 Subject: [PATCH] py3: Full fix for svg2painterpath (I hope) --- src/calibre/ebooks/covers.py | 11 +++++++-- src/calibre/utils/speedups.py | 45 +++++++++++++++++++---------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/calibre/ebooks/covers.py b/src/calibre/ebooks/covers.py index a5a1c7df2d..14f9ac71f2 100644 --- a/src/calibre/ebooks/covers.py +++ b/src/calibre/ebooks/covers.py @@ -495,7 +495,11 @@ class Ornamental(Style): def __call__(self, painter, rect, color_theme, title_block, subtitle_block, footer_block): if not self.PATH_CACHE: 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 painter.setRenderHint(QPainter.Antialiasing) g = QRadialGradient(QPointF(rect.center()), rect.width()) @@ -503,7 +507,10 @@ class Ornamental(Style): painter.fillRect(rect, QBrush(g)) painter.save() 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.setColor(self.ccolor1) p.setPen(pen) diff --git a/src/calibre/utils/speedups.py b/src/calibre/utils/speedups.py index 9b93e95ac8..b321b9ed04 100644 --- a/src/calibre/utils/speedups.py +++ b/src/calibre/utils/speedups.py @@ -55,15 +55,15 @@ def svg_path_to_painter_path(d): from PyQt5.Qt import QPainterPath cmd = last_cmd = b'' path = QPainterPath() - moveto_abs, moveto_rel = b'Mm' - closepath1, closepath2 = b'Zz' - lineto_abs, lineto_rel = b'Ll' - hline_abs, hline_rel = b'Hh' - vline_abs, vline_rel = b'Vv' - curveto_abs, curveto_rel = b'Cc' - smoothcurveto_abs, smoothcurveto_rel = b'Ss' - quadcurveto_abs, quadcurveto_rel = b'Qq' - smoothquadcurveto_abs, smoothquadcurveto_rel = b'Tt' + moveto_abs, moveto_rel = b'M', b'm' + closepath1, closepath2 = b'Z', b'z' + lineto_abs, lineto_rel = b'L', b'l' + hline_abs, hline_rel = b'H', b'h' + vline_abs, vline_rel = b'V', b'v' + curveto_abs, curveto_rel = b'C', b'c' + smoothcurveto_abs, smoothcurveto_rel = b'S', b's' + quadcurveto_abs, quadcurveto_rel = b'Q', b'q' + smoothquadcurveto_abs, smoothquadcurveto_rel = b'T', b't' # Store the last parsed values # x/y = end position @@ -74,16 +74,21 @@ def svg_path_to_painter_path(d): d = d.encode('ascii') d = d.replace(b',', b' ').replace(b'\n', b' ') 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(): chars = [] - while data.tell() < end: - c = data.read(1) + while pos[0] < end: + c = read_byte() if c == b' ' and not chars: continue - if c == b'-' or b'0' <= c[0] <= b'9' or c == b'.': - chars.append(c[0]) + if c in b'-.0123456789': + chars.append(c) else: break if not chars: @@ -97,16 +102,14 @@ def svg_path_to_painter_path(d): repeated_command = None - while data.tell() < end: + while pos[0] < end: last_cmd = cmd - cmd = data.read(1) if repeated_command is None else repeated_command - if isinstance(cmd, memoryview): - cmd = cmd.tobytes() + cmd = read_byte() if repeated_command is None else repeated_command repeated_command = None if cmd == b' ': continue - elif cmd == moveto_abs: + if cmd == moveto_abs: x, y = parse_float(), parse_float() path.moveTo(x, y) elif cmd == moveto_rel: @@ -178,11 +181,11 @@ def svg_path_to_painter_path(d): x1, y1 = x, y x, y = parse_floats(2, x, y) path.quadTo(x1, y1, x, y) - elif cmd[0:1] in b'-.0123456789': + elif cmd in b'-.0123456789': # A new number begins # In this case, multiple parameters tuples are specified for the last command # We rewind to reparse data correctly - data.seek(-1, os.SEEK_CUR) + pos[0] -= 1 # Handle extra parameters if last_cmd == moveto_abs: