使用画布绘制图像并使用SimpleDocTemplate

时间:2022-11-04 09:58:14

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

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

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

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

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.

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

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.

鸭嘴兽布局的东西使用flowables。当包装,拆分或绘制时,包装工通常将属性canv设置到每个flowable上,即围绕wrap,split和draw方法。在这些方法中,您可以使用self的canv属性访问画布。

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.

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

3 个解决方案

#1


2  

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.

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

#2


4  

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

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

#3


4  

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.

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

-> 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

- >特别是因为人们经常询问如何将matplotlib对象放入reportlab,我将展示如何使用matplotlib生成一个绘图,然后使用修改后的flowable将该绘图放入SimpleDocTemplate(不将文件保存到磁盘)。该概念适用于您可以提供给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)

- >以下DOES允许您将数字放在文本上(将高度从负数更改为正数,将其推到图表所在部分顶部的虚线上方)

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

关键概念是每个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)

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.

您可以扩展此最小代码剪切以完成您喜欢的任何内容,并且您可以向Story变量添加尽可能多的部分(这只是一个可流动的列表)。神奇之处在于我们正在将文档构建器交给Flowable,它使用Flowable自己的画布来绘制图形。

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.

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

#1


2  

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.

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

#2


4  

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

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

#3


4  

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.

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

-> 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

- >特别是因为人们经常询问如何将matplotlib对象放入reportlab,我将展示如何使用matplotlib生成一个绘图,然后使用修改后的flowable将该绘图放入SimpleDocTemplate(不将文件保存到磁盘)。该概念适用于您可以提供给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)

- >以下DOES允许您将数字放在文本上(将高度从负数更改为正数,将其推到图表所在部分顶部的虚线上方)

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

关键概念是每个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)

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.

您可以扩展此最小代码剪切以完成您喜欢的任何内容,并且您可以向Story变量添加尽可能多的部分(这只是一个可流动的列表)。神奇之处在于我们正在将文档构建器交给Flowable,它使用Flowable自己的画布来绘制图形。

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.

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