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):
self.pdf.transform(self.pdf_system)
self.pdf.set_rgb_colorspace()
self.graphics.reset()
self.pdf.save_stack()
self.current_page_inited = True

View File

@ -15,7 +15,7 @@ from PyQt4.Qt import (
from calibre.ebooks.pdf.render.common import (
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): # {{{
p = Path()
@ -392,8 +392,6 @@ class Graphics(object):
return color, opacity, pattern, do_fill
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
pen = state.stroke
self.pending_state.do_stroke = True
@ -427,14 +425,10 @@ class Graphics(object):
pdf.current_page.write(' 0 d ')
# Stroke fill
b = pen.brush()
vals = list(b.color().getRgbF())
vals[-1] *= state.opacity
color = Color(*vals)
pdf.set_stroke_color(color)
if vals[-1] < 1e-5 or b.style() == Qt.NoBrush:
self.pending_state.do_stroke = False
color, opacity, pattern, self.pending_state.do_stroke = self.convert_brush(
pen.brush(), state.brush_origin, state.opacity, pdf_system,
painter.transform())
self.pdf.apply_stroke(color, pattern, opacity)
def apply_fill(self, state, pdf_system, painter):
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
better than nothing.
'''
if not self.current_state.do_fill:
if not hasattr(self, 'last_fill') or not self.current_state.do_fill:
return
if isinstance(self.last_fill.brush, TexturePattern):

View File

@ -10,7 +10,6 @@ __docformat__ = 'restructuredtext en'
import hashlib
from future_builtins import map
from itertools import izip
from collections import namedtuple
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'
Color = namedtuple('Color', 'red green blue opacity')
class IndirectObjects(object):
def __init__(self):
@ -353,9 +350,6 @@ class PDFStream(object):
cm = ' '.join(map(fmtnum, vals))
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):
self.current_page.write_line('q')
@ -391,13 +385,11 @@ class PDFStream(object):
def serialize(self, o):
serialize(o, self.current_page)
def set_stroke_color(self, color):
opacity = color.opacity
def set_stroke_opacity(self, opacity):
if opacity not in self.stroke_opacities:
op = Dictionary({'Type':Name('ExtGState'), 'CA': opacity})
self.stroke_opacities[opacity] = self.objects.add(op)
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):
opacity = float(opacity)
@ -518,17 +510,27 @@ class PDFStream(object):
serialize(Name(name), self.current_page)
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):
if opacity is not None:
self.set_fill_opacity(opacity)
wl = self.current_page.write_line
if color is not None and pattern is None:
wl(' '.join(map(fmtnum, color)) + ' rg')
elif color is None and pattern is not None:
wl('/Pattern cs /%s scn'%pattern)
elif color is not None and pattern is not None:
col = ' '.join(map(fmtnum, color))
wl('/PCSp cs %s /%s scn'%(col, pattern))
self.apply_color_space(color, pattern)
def apply_stroke(self, color=None, pattern=None, opacity=None):
if opacity is not None:
self.set_stroke_opacity(opacity)
self.apply_color_space(color, pattern, stroke=True)
def end(self):
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,
QApplication, QPainter, Qt, QImage, QLinearGradient,
QPointF)
QPointF, QPen)
QBrush, QColor, QPoint, QPixmap, QPainterPath, QRectF, Qt, QPointF
from calibre.ebooks.pdf.render.engine import PdfDevice
@ -69,6 +69,14 @@ def full(p, xmax, ymax):
g.setColorAt(1, QColor('#fff'))
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):
p = QPainter(dev)
if isinstance(dev, PdfDevice):
@ -91,12 +99,18 @@ def brush(p, xmax, ymax):
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():
app = QApplication([])
app
tdir = gettempdir()
pdf = os.path.join(tdir, 'painter.pdf')
func = full
func = pen
dpi = 100
with open(pdf, 'wb') as f:
dev = PdfDevice(f, xdpi=dpi, ydpi=dpi, compress=False)