简体   繁体   中英

Creating a gradient fill in a PDF file using reportlab

是否可以使用ReportLab (python)在PDF中创建渐变填充?

ReportLab now supports PDF gradients.

A patch for gradient support was posted to the ReportLab mailing list by Peter Johnson on 6 August 2012 and was added to the source the next day. I cannot spot anything in the release notes for ReportLab 2.6 but since that was released on the 1st of October 2012 presumably it is in there. It is definitely present in 2.7.

Both linear and radial gradients with multiple stops can be specified. Searching the documentation for the term gradient doesn't turn up anything. However, the message with the first version of the patch has a couple of examples which are the basis of some tests in the ReportLab source . Based on this I've worked up a quick demo script:

from reportlab.pdfgen.canvas import Canvas
from reportlab.lib.colors import red, yellow, green
from reportlab.lib.units import mm

c = Canvas("gradient.pdf")

# Linear gradient with the endpoints extending over the page.
c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow))
c.drawString(5*mm, 290*mm, "c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow))")
c.line(105*mm, 200*mm, 180*mm, 100*mm)
c.showPage()

# Linear gradient constrained within the endpoints.
c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow), extend=False)
c.drawString(5*mm, 290*mm, "c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow), extend=False)")
c.line(105*mm, 200*mm, 180*mm, 100*mm)
c.showPage()

# Linear gradient with multiple stops.
c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow, green), (0, 0.8, 1), extend=False)
c.drawString(5*mm, 290*mm, "c.linearGradient(105*mm, 200*mm, 180*mm, 100*mm, (red, yellow, green), (0, 0.8, 1), extend=False)")
c.line(105*mm, 200*mm, 180*mm, 100*mm)
c.line(141*mm, 102*mm, 189*mm, 138*mm)
c.showPage()

# Radial gradient with the endpoint extending over the page.
c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow))
c.drawString(5*mm, 290*mm, "c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow))")
c.circle(105*mm, 200*mm, 60*mm)
c.showPage()

# Radial gradient constrained within the circle.
c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow), extend=False)
c.drawString(5*mm, 290*mm, "c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow), extend=False)")
c.circle(105*mm, 200*mm, 60*mm)
c.showPage()

# Radial gradient with multiple stops.
c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow, green), (0, 0.8, 1))
c.drawString(5*mm, 290*mm, "c.radialGradient(105*mm, 200*mm, 60*mm, (red, yellow, green), (0, 0.8, 1))")
c.circle(105*mm, 200*mm, 48*mm)
c.circle(105*mm, 200*mm, 60*mm)
c.showPage()

c.save()

This outputs six pages with various gradients plus the gradient method call and lines/circles showing where the endpoints and stops are:

基本线性渐变在页面上延伸线性渐变受限于端点具有多个停止的线性渐变基本径向渐变在页面上延伸径向梯度约束在半径范围内具有多个停止的径向梯度

[My answer is no longer correct, gradients are now available in Reportlab, see the other answer on this page for details.]

Sorry to ressurect this question, but I stumbled across it and it hadn't been correctly answered.

The answer is no, as of today, the current version of ReportLab does not support gradients. Gradients are supported by PDF, however. If you look in ReportLab's Canvas class you'll see that many of its methods are relatively small wrappers around the underlying PDF code generation. To access gradients in RL you'd need to extend the Canvas class and add additional methods to generate the correct PDF code. This is doable, but obviously not trivial, and it means you'd have to read up on the PDF spec.

There are two alternatives. Firstly generate the gradient as a raster image and use that, secondly generate the gradient by drawing a whole series of rectangles in different colors.

start_color = (1,0,0)
end_color = (0,1,0)
for i in range(100):
    p = i * 0.01
    canvas.setFillColorRGB(*[start_color[i]*(1.0-p)+end_color[i]*p for i in range(3)])
    canvas.rect(i, 0, 2, 100)

For example. Unfortunately getting the gradient smooth takes a lot of rectangles, and this can cause the PDF to be large and render slowly. You're better off with the raster approach.

Finally, you might consider using PyCairo. This has better support for lots of graphical elements, and can render to a PDF or PNG. It lacks reportlabs higher lever constructs (such as page layout), however.

You want to fill a rectangle (or other path) with a gradient instead of a solid color?

No problem. Use clipping to bound/limit the gradient to a path. Just remember to set the clip path before setting the gradient. (And wrap it inside saveState() / restoreState() to reset the clip and gradient afterwards.)

c = canvas.Canvas (filename)
#c.translate (8*cm, 8*cm)  # use this to move the rectangle
p = c.beginPath()
p.rect (0,0 , 5*cm,5*cm)
c.clipPath (p, stroke=0)
c.linearGradient (0,0 , 5*cm, 5*cm , (red, yellow))

For radial gradients it might be enough to set the extend keyword parameter to False .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM