使用canvas绘制图像并使用SimpleDocTemplate

发布于 2024-10-24 10:00:34 字数 1753 浏览 1 评论 0原文

我正在 django 视图中使用 reportlab 编写 pdf,它们非常简单,包括页眉、内容和页脚。

我正在使用非常适合的 SimpleDocTemplate 来绘制内容中的表格,页脚和页眉是 drwan 使用的:

build([data], onFirstPage=drawPageFrame, onLaterPages=drawPageFrame).

我的问题是,如何像使用 Canvas.drawImage(...) 一样绘制图像?我需要一个“浮动”图像...位于我想要的文本上方,而使用 SimpleDocTemplate 我没有 Canvas 对象来执行此操作。

搜索我发现了这个:

鸭嘴兽布局使用 Flowables。打包者通常会设置 当每个 flowable 被包装、分割或分割时,属性 canv 到每个 flowable 上 围绕wrap、split 和draw 方法进行绘制。在这些方法里面 您可以使用 self 的 canv 属性访问画布。

这个可以怎么用呢?

嗯,还有更多要测试的东西:

flowables.Macro
flowables.CallerMacro
# -*- coding: utf-8 -*-
from reportlab.lib.pagesizes import A4, landscape, portrait
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Table, Flowable, SimpleDocTemplate, Paragraph, Spacer, Image
from reportlab.lib import randomtext
from reportlab import platypus

import os,random

styles = getSampleStyleSheet()
path = os.path.realpath(os.path.dirname(__file__))

def drawPageFrame(canvas, doc):
    canvas.saveState()
    canvas.drawImage(path+"/ujiPDF.jpg",50,50,57,57)
    canvas.restoreState()

doc = SimpleDocTemplate("salida.pdf",pagesize=A4)

elementos = []

com = 'canvas.drawImage("'+path+'/ujiPDF.jpg",100,100,57,57)'
print com
elementos.append(platypus.flowables.Macro('canvas.saveState()'))
print platypus.flowables.Macro(com)
elementos.append(platypus.flowables.Macro(com))
elementos.append(platypus.flowables.Macro('canvas.restoreState()'))

para = Paragraph(randomtext.randomText(randomtext.PYTHON,20), styles["Normal"])
elementos.append(para)

doc.build(elementos,onFirstPage=drawPageFrame, onLaterPages=drawPageFrame)

这是宏方法...干净退出,但没有第二个图像。

I'm writing pdfs with reportlab inside a django view, they are very simple, the header, the contents and the footer.

I'm using SimpleDocTemplate wich fits very well, to draw tables in the contents, the footer and the header are drwan using:

build([data], onFirstPage=drawPageFrame, onLaterPages=drawPageFrame).

My question is, How can I draw a image like using Canvas.drawImage(...)? I need a "floating" image... positioned over the text where I want, and with SimpleDocTemplate I don't have a Canvas object to do this.

Searching I have found this:

The platypus layout stuff uses flowables. Packers normally set the
attribute canv onto each flowable when it is being wrapped, split or
drawn ie around the wrap, split and draw methods. Inside those methods
you have access to the canvas using the canv attribute of self.

How can this be used?

Ummmm, more stuff to test:

flowables.Macro
flowables.CallerMacro
# -*- coding: utf-8 -*-
from reportlab.lib.pagesizes import A4, landscape, portrait
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Table, Flowable, SimpleDocTemplate, Paragraph, Spacer, Image
from reportlab.lib import randomtext
from reportlab import platypus

import os,random

styles = getSampleStyleSheet()
path = os.path.realpath(os.path.dirname(__file__))

def drawPageFrame(canvas, doc):
    canvas.saveState()
    canvas.drawImage(path+"/ujiPDF.jpg",50,50,57,57)
    canvas.restoreState()

doc = SimpleDocTemplate("salida.pdf",pagesize=A4)

elementos = []

com = 'canvas.drawImage("'+path+'/ujiPDF.jpg",100,100,57,57)'
print com
elementos.append(platypus.flowables.Macro('canvas.saveState()'))
print platypus.flowables.Macro(com)
elementos.append(platypus.flowables.Macro(com))
elementos.append(platypus.flowables.Macro('canvas.restoreState()'))

para = Paragraph(randomtext.randomText(randomtext.PYTHON,20), styles["Normal"])
elementos.append(para)

doc.build(elementos,onFirstPage=drawPageFrame, onLaterPages=drawPageFrame)

This is the Macro approach...clean exit but without the second image.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

心欲静而疯不止 2024-10-31 10:00:34

如果我理解正确的话,您不需要对整个文档模板进行子类化,您只需要一个可以放入 SimpleDocTemplate 的可流动文件。您可以通过 Flowable 本身的一个非常简单的子类来实现这一点。

->特别是,由于人们经常询问如何将 matplotlib 对象放入 reportlab,我将展示如何使用 matplotlib 生成绘图,然后使用修改后的 flowable 将该绘图放入 SimpleDocTemplate 中(无需将文件保存到磁盘)。这个概念适用于任何文件或任何可以输入 cStringIO 的内容

->下面的代码确实允许您将图形放在文本上(将高度从负值更改为正值,以将其推到绘图所在部分顶部的假想线上方)

关键概念是每个 Flowable 本身也可以包含我们可以在其上绘图的画布。

import matplotlib.pyplot as plt
import cStringIO
from reportlab.lib.units import inch, cm
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, Table
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
import reportlab.lib, reportlab.platypus

class flowable_fig(reportlab.platypus.Flowable):
    def __init__(self, imgdata):
        reportlab.platypus.Flowable.__init__(self)
        self.img = reportlab.lib.utils.ImageReader(imgdata)

    def draw(self):
        self.canv.drawImage(self.img, 0, 0, height = -2*inch, width=4*inch)
        # http://www.reportlab.com/apis/reportlab/2.4/pdfgen.html
                            
doc = SimpleDocTemplate(("report.pdf"),pagesize=letter,
                    rightMargin=72,leftMargin=72,
                    topMargin=72,bottomMargin=18)
Story=[]
styles=getSampleStyleSheet()
ptext = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi massa dolor, vulputate quis elit sed, sagittis consectetur erat. Sed lobortis nisi eros, eu maximus enim iaculis ac. Vestibulum sagittis urna nec interdum aliquam. Pellentesque ornare velit ut ante ullamcorper, vulputate accumsan nisi vulputate. Fusce consectetur dolor quam. Phasellus hendrerit, ligula vel consectetur pretium, lorem neque dapibus eros, ornare suscipit ipsum dolor id nisl. Sed vel orci id leo efficitur lobortis sit amet id risus. Nullam euismod, ipsum a posuere scelerisque, ante lorem ultrices nibh, ut feugiat metus ex congue enim. Nam lobortis, metus id pellentesque feugiat, arcu orci rutrum felis, quis luctus urna nisl at nulla. Donec eu eros pharetra dolor congue facilisis at ac magna. Nullam eu ultricies metus. Sed sodales, libero viverra pellentesque tempus, magna purus convallis nibh, eu condimentum tortor erat tincidunt turpis. Vestibulum scelerisque tincidunt egestas. Nullam commodo diam nisl, sed consequat ex sagittis eu.'
Story.append(Paragraph(ptext, styles["Normal"]))

fig = plt.figure(figsize=(10, 3))
plt.plot([1,2,3,4])
plt.ylabel('This is a boring plot')
imgdata = cStringIO.StringIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0)  # rewind the data

pic = flowable_fig(imgdata)
Story.append(pic)
doc.build(Story)

您可以扩展这个最小的代码片段来完成您喜欢的任何事情,并且您可以向 Story 变量添加任意多的片段(这实际上只是一个可流动的列表)。神奇之处在于我们向文档生成器提供了一个 Flowable,它使用 Flowable 自己的画布来绘制图形。

编辑:我差点忘了,因为这使我们能够完全访问drawImage,我们还可以使该图片或绘图具有透明度,以便可以通过它看到其他东西。 drawImage 上的文档有详细信息。

You don't need to subclass the whole document template if I understand you right, you just want a flowable that you can put INTO a SimpleDocTemplate. You can achieve that with a very easy subclass of Flowable itself.

-> In particular since people often ask about how to put matplotlib objects into reportlab, I'll show how to generate a plot with matplotlib and then use the modified flowable to put that plot into a SimpleDocTemplate (without saving the file to disk). The concept applies to any file or anything you can feed into a cStringIO

-> The below DOES allow you to put the figure over the text (change the height from negative to positive to push it above the imaginary line at the top of the section the plot goes into)

The key concept is that each Flowable does, itself, also contain a canvas we can draw onto.

import matplotlib.pyplot as plt
import cStringIO
from reportlab.lib.units import inch, cm
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, Table
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
import reportlab.lib, reportlab.platypus

class flowable_fig(reportlab.platypus.Flowable):
    def __init__(self, imgdata):
        reportlab.platypus.Flowable.__init__(self)
        self.img = reportlab.lib.utils.ImageReader(imgdata)

    def draw(self):
        self.canv.drawImage(self.img, 0, 0, height = -2*inch, width=4*inch)
        # http://www.reportlab.com/apis/reportlab/2.4/pdfgen.html
                            
doc = SimpleDocTemplate(("report.pdf"),pagesize=letter,
                    rightMargin=72,leftMargin=72,
                    topMargin=72,bottomMargin=18)
Story=[]
styles=getSampleStyleSheet()
ptext = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi massa dolor, vulputate quis elit sed, sagittis consectetur erat. Sed lobortis nisi eros, eu maximus enim iaculis ac. Vestibulum sagittis urna nec interdum aliquam. Pellentesque ornare velit ut ante ullamcorper, vulputate accumsan nisi vulputate. Fusce consectetur dolor quam. Phasellus hendrerit, ligula vel consectetur pretium, lorem neque dapibus eros, ornare suscipit ipsum dolor id nisl. Sed vel orci id leo efficitur lobortis sit amet id risus. Nullam euismod, ipsum a posuere scelerisque, ante lorem ultrices nibh, ut feugiat metus ex congue enim. Nam lobortis, metus id pellentesque feugiat, arcu orci rutrum felis, quis luctus urna nisl at nulla. Donec eu eros pharetra dolor congue facilisis at ac magna. Nullam eu ultricies metus. Sed sodales, libero viverra pellentesque tempus, magna purus convallis nibh, eu condimentum tortor erat tincidunt turpis. Vestibulum scelerisque tincidunt egestas. Nullam commodo diam nisl, sed consequat ex sagittis eu.'
Story.append(Paragraph(ptext, styles["Normal"]))

fig = plt.figure(figsize=(10, 3))
plt.plot([1,2,3,4])
plt.ylabel('This is a boring plot')
imgdata = cStringIO.StringIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0)  # rewind the data

pic = flowable_fig(imgdata)
Story.append(pic)
doc.build(Story)

You can expand this minimum code snipped to accomplish whatever you like and you can add as many pieces to the Story variable (which is just a list of flowables really). The magic is just that we're handing the doc builder a Flowable that uses the Flowable's own canvas to draw the figure.

EDIT: I almost forgot, because this gives us full access to drawImage, we can also make that picture or plot have transparency so other things can be seen through it. The docs on drawImage have the details.

吹梦到西洲 2024-10-31 10:00:34

鸭嘴兽中有Image类。只需使用 from reportlab.platypus import Image 即可访问此类。它的工作方式与内部的其他类类似,并且 smth.append(Image(filename)) 将图像附加到您需要构建到 pdf 中的对象。创立于 Tyler Lessman 个人网站

There is Image class in the platypus. Just use from reportlab.platypus import Image and you got access to this class. It works like other classes inside and smth.append(Image(filename)) appends image to object you need to build into pdf. Founded at Tyler Lessman personal website

最好的选择是创建 SimpleDocTemplate 或 BaseDocTemplate 的子类。在构建方法中,您将可以访问画布。如果您想利用 SimpleDocTemplate 所做的一切,您可以尝试直接从 site-packages/reportlab/platypus/doctemplate.py 复制它。

Your best option is to create a subclass of SimpleDocTemplate or BaseDocTemplate. In the build method you will have access to the canvas. If you want to tap into everything that SimpleDocTemplate does, you might try copying it directly from site-packages/reportlab/platypus/doctemplate.py.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文