Handle non-solid pens

This commit is contained in:
Kovid Goyal 2012-12-31 20:08:17 +05:30
parent 9f13e30737
commit 0dd9c26dbe
4 changed files with 41 additions and 32 deletions

View File

@ -109,7 +109,6 @@ class PdfEngine(QPaintEngine):
def init_page(self): def init_page(self):
self.pdf.transform(self.pdf_system) self.pdf.transform(self.pdf_system)
self.pdf.set_rgb_colorspace()
self.graphics.reset() self.graphics.reset()
self.pdf.save_stack() self.pdf.save_stack()
self.current_page_inited = True self.current_page_inited = True

View File

@ -15,7 +15,7 @@ from PyQt4.Qt import (
from calibre.ebooks.pdf.render.common import ( from calibre.ebooks.pdf.render.common import (
Name, Array, fmtnum, Stream, Dictionary) Name, Array, fmtnum, Stream, Dictionary)
from calibre.ebooks.pdf.render.serialize import Path, Color from calibre.ebooks.pdf.render.serialize import Path
def convert_path(path): # {{{ def convert_path(path): # {{{
p = Path() p = Path()
@ -392,8 +392,6 @@ class Graphics(object):
return color, opacity, pattern, do_fill return color, opacity, pattern, do_fill
def apply_stroke(self, state, pdf_system, painter): def apply_stroke(self, state, pdf_system, painter):
# TODO: Handle pens with non solid brushes by setting the colorspace
# for stroking to a pattern
# TODO: Support miter limit by using QPainterPathStroker # TODO: Support miter limit by using QPainterPathStroker
pen = state.stroke pen = state.stroke
self.pending_state.do_stroke = True self.pending_state.do_stroke = True
@ -427,14 +425,10 @@ class Graphics(object):
pdf.current_page.write(' 0 d ') pdf.current_page.write(' 0 d ')
# Stroke fill # Stroke fill
b = pen.brush() color, opacity, pattern, self.pending_state.do_stroke = self.convert_brush(
vals = list(b.color().getRgbF()) pen.brush(), state.brush_origin, state.opacity, pdf_system,
vals[-1] *= state.opacity painter.transform())
color = Color(*vals) self.pdf.apply_stroke(color, pattern, opacity)
pdf.set_stroke_color(color)
if vals[-1] < 1e-5 or b.style() == Qt.NoBrush:
self.pending_state.do_stroke = False
def apply_fill(self, state, pdf_system, painter): def apply_fill(self, state, pdf_system, painter):
self.pending_state.do_fill = True self.pending_state.do_fill = True
@ -458,7 +452,7 @@ class Graphics(object):
the brush origin before painting an object. While not perfect, this is the brush origin before painting an object. While not perfect, this is
better than nothing. better than nothing.
''' '''
if not self.current_state.do_fill: if not hasattr(self, 'last_fill') or not self.current_state.do_fill:
return return
if isinstance(self.last_fill.brush, TexturePattern): if isinstance(self.last_fill.brush, TexturePattern):

View File

@ -10,7 +10,6 @@ __docformat__ = 'restructuredtext en'
import hashlib import hashlib
from future_builtins import map from future_builtins import map
from itertools import izip from itertools import izip
from collections import namedtuple
from PyQt4.Qt import QBuffer, QByteArray, QImage, Qt, QColor, qRgba from PyQt4.Qt import QBuffer, QByteArray, QImage, Qt, QColor, qRgba
@ -23,8 +22,6 @@ from calibre.ebooks.pdf.render.links import Links
PDFVER = b'%PDF-1.3' PDFVER = b'%PDF-1.3'
Color = namedtuple('Color', 'red green blue opacity')
class IndirectObjects(object): class IndirectObjects(object):
def __init__(self): def __init__(self):
@ -353,9 +350,6 @@ class PDFStream(object):
cm = ' '.join(map(fmtnum, vals)) cm = ' '.join(map(fmtnum, vals))
self.current_page.write_line(cm + ' cm') self.current_page.write_line(cm + ' cm')
def set_rgb_colorspace(self):
self.current_page.write_line('/DeviceRGB CS /DeviceRGB cs')
def save_stack(self): def save_stack(self):
self.current_page.write_line('q') self.current_page.write_line('q')
@ -391,13 +385,11 @@ class PDFStream(object):
def serialize(self, o): def serialize(self, o):
serialize(o, self.current_page) serialize(o, self.current_page)
def set_stroke_color(self, color): def set_stroke_opacity(self, opacity):
opacity = color.opacity
if opacity not in self.stroke_opacities: if opacity not in self.stroke_opacities:
op = Dictionary({'Type':Name('ExtGState'), 'CA': opacity}) op = Dictionary({'Type':Name('ExtGState'), 'CA': opacity})
self.stroke_opacities[opacity] = self.objects.add(op) self.stroke_opacities[opacity] = self.objects.add(op)
self.current_page.set_opacity(self.stroke_opacities[opacity]) self.current_page.set_opacity(self.stroke_opacities[opacity])
self.current_page.write_line(' '.join(map(fmtnum, color[:3])) + ' SC')
def set_fill_opacity(self, opacity): def set_fill_opacity(self, opacity):
opacity = float(opacity) opacity = float(opacity)
@ -518,17 +510,27 @@ class PDFStream(object):
serialize(Name(name), self.current_page) serialize(Name(name), self.current_page)
self.current_page.write_line(' Do Q') self.current_page.write_line(' Do Q')
def apply_color_space(self, color, pattern, stroke=False):
wl = self.current_page.write_line
if color is not None and pattern is None:
wl(' '.join(map(fmtnum, color)) + (' RG' if stroke else ' rg'))
elif color is None and pattern is not None:
wl('/Pattern %s /%s %s'%('CS' if stroke else 'cs', pattern,
'SCN' if stroke else 'scn'))
elif color is not None and pattern is not None:
col = ' '.join(map(fmtnum, color))
wl('/PCSp %s %s /%s %s'%('CS' if stroke else 'cs', col, pattern,
'SCN' if stroke else 'scn'))
def apply_fill(self, color=None, pattern=None, opacity=None): def apply_fill(self, color=None, pattern=None, opacity=None):
if opacity is not None: if opacity is not None:
self.set_fill_opacity(opacity) self.set_fill_opacity(opacity)
wl = self.current_page.write_line self.apply_color_space(color, pattern)
if color is not None and pattern is None:
wl(' '.join(map(fmtnum, color)) + ' rg') def apply_stroke(self, color=None, pattern=None, opacity=None):
elif color is None and pattern is not None: if opacity is not None:
wl('/Pattern cs /%s scn'%pattern) self.set_stroke_opacity(opacity)
elif color is not None and pattern is not None: self.apply_color_space(color, pattern, stroke=True)
col = ' '.join(map(fmtnum, color))
wl('/PCSp cs %s /%s scn'%(col, pattern))
def end(self): def end(self):
if self.current_page.getvalue(): if self.current_page.getvalue():

View File

@ -12,7 +12,7 @@ from tempfile import gettempdir
from PyQt4.Qt import (QBrush, QColor, QPoint, QPixmap, QPainterPath, QRectF, from PyQt4.Qt import (QBrush, QColor, QPoint, QPixmap, QPainterPath, QRectF,
QApplication, QPainter, Qt, QImage, QLinearGradient, QApplication, QPainter, Qt, QImage, QLinearGradient,
QPointF) QPointF, QPen)
QBrush, QColor, QPoint, QPixmap, QPainterPath, QRectF, Qt, QPointF QBrush, QColor, QPoint, QPixmap, QPainterPath, QRectF, Qt, QPointF
from calibre.ebooks.pdf.render.engine import PdfDevice from calibre.ebooks.pdf.render.engine import PdfDevice
@ -69,6 +69,14 @@ def full(p, xmax, ymax):
g.setColorAt(1, QColor('#fff')) g.setColorAt(1, QColor('#fff'))
p.fillRect(x, y, w, w, QBrush(g)) p.fillRect(x, y, w, w, QBrush(g))
pen = QPen(QBrush(Qt.blue))
pen.setWidth(xmax/3)
p.setPen(pen)
x += w + w/10
y += w
p.drawLine(x, y, x+w, y)
def run(dev, func): def run(dev, func):
p = QPainter(dev) p = QPainter(dev)
if isinstance(dev, PdfDevice): if isinstance(dev, PdfDevice):
@ -91,12 +99,18 @@ def brush(p, xmax, ymax):
p.fillRect(0, y+xmax/1.9, w, w, QBrush(pix)) p.fillRect(0, y+xmax/1.9, w, w, QBrush(pix))
def pen(p, xmax, ymax):
pix = QPixmap(I('console.png'))
pen = QPen(QBrush(pix), 60)
p.setPen(pen)
p.drawRect(0, xmax/3, xmax/3, xmax/2)
def main(): def main():
app = QApplication([]) app = QApplication([])
app app
tdir = gettempdir() tdir = gettempdir()
pdf = os.path.join(tdir, 'painter.pdf') pdf = os.path.join(tdir, 'painter.pdf')
func = full func = pen
dpi = 100 dpi = 100
with open(pdf, 'wb') as f: with open(pdf, 'wb') as f:
dev = PdfDevice(f, xdpi=dpi, ydpi=dpi, compress=False) dev = PdfDevice(f, xdpi=dpi, ydpi=dpi, compress=False)