Is it possible to create a gradient fill in a PDF using ReportLab (python)?
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With