使用 ReportLab (Python) 在 PDF 文档中生成 PDF 图像

发布于 2024-09-13 20:26:42 字数 128 浏览 8 评论 0原文

我将 matplotlib 中的一些绘图保存为 pdf 格式,因为它似乎提供了更好的质量。如何使用 ReportLab 将 PDF 图像包含到 PDF 文档中?便捷方法Image(filename) 不适用于此格式。

I saved some plots from matplotlib into a pdf format because it seems to offer better quality. How do I include the PDF image into a PDF document using ReportLab? The convenience method Image(filename) does not work for this format.

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

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

发布评论

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

评论(4

自在安然 2024-09-20 20:26:42

您可以将精彩的 pdfrw 包与 reportlab 一起使用,并使用它将 matplotlib 图形的文件状对象直接传递到可流动的对象中:

这之前已经回答过,但我想在这里给出一个最小的例子,也请看这里:https://stackoverflow.com/a/13870512/4497962

from io import BytesIO
import matplotlib.pyplot as plt
from pdfrw import PdfReader, PdfDict
from pdfrw.buildxobj import pagexobj
from pdfrw.toreportlab import makerl
from reportlab.platypus import Flowable
from reportlab.lib.enums import TA_JUSTIFY,TA_LEFT,TA_CENTER,TA_RIGHT

class PdfImage(Flowable):
    """
    PdfImage wraps the first page from a PDF file as a Flowable
    which can be included into a ReportLab Platypus document.
    Based on the vectorpdf extension in rst2pdf (http://code.google.com/p/rst2pdf/)

    This can be used from the place where you want to return your matplotlib image
    as a Flowable:

        img = BytesIO()

        fig, ax = plt.subplots(figsize=(canvaswidth,canvaswidth))

        ax.plot([1,2,3],[6,5,4],antialiased=True,linewidth=2,color='red',label='a curve')

        fig.savefig(img,format='PDF')

        return(PdfImage(img))

    """

    def __init__(self, filename_or_object, width=None, height=None, kind='direct'):
        # If using StringIO buffer, set pointer to begining
        if hasattr(filename_or_object, 'read'):
            filename_or_object.seek(0)
            #print("read")
        self.page = PdfReader(filename_or_object, decompress=False).pages[0]
        self.xobj = pagexobj(self.page)

        self.imageWidth = width
        self.imageHeight = height
        x1, y1, x2, y2 = self.xobj.BBox

        self._w, self._h = x2 - x1, y2 - y1
        if not self.imageWidth:
            self.imageWidth = self._w
        if not self.imageHeight:
            self.imageHeight = self._h
        self.__ratio = float(self.imageWidth)/self.imageHeight
        if kind in ['direct','absolute'] or width==None or height==None:
            self.drawWidth = width or self.imageWidth
            self.drawHeight = height or self.imageHeight
        elif kind in ['bound','proportional']:
            factor = min(float(width)/self._w,float(height)/self._h)
            self.drawWidth = self._w*factor
            self.drawHeight = self._h*factor

    def wrap(self, availableWidth, availableHeight):
        """
        returns draw- width and height

        convenience function to adapt your image 
        to the available Space that is available
        """
        return self.drawWidth, self.drawHeight

    def drawOn(self, canv, x, y, _sW=0):
        """
        translates Bounding Box and scales the given canvas
        """
        if _sW > 0 and hasattr(self, 'hAlign'):
            a = self.hAlign
            if a in ('CENTER', 'CENTRE', TA_CENTER):
                x += 0.5*_sW
            elif a in ('RIGHT', TA_RIGHT):
                x += _sW
            elif a not in ('LEFT', TA_LEFT):
                raise ValueError("Bad hAlign value " + str(a))

        #xobj_name = makerl(canv._doc, self.xobj)
        xobj_name = makerl(canv, self.xobj)

        xscale = self.drawWidth/self._w
        yscale = self.drawHeight/self._h

        x -= self.xobj.BBox[0] * xscale
        y -= self.xobj.BBox[1] * yscale

        canv.saveState()
        canv.translate(x, y)
        canv.scale(xscale, yscale)
        canv.doForm(xobj_name)
        canv.restoreState()

You can use the wonderful pdfrw package together with reportlab and use it to pass file-like objects of matplotlib figures directly into a flowable:

This was answered before, but I want to give a minimal example here, please also look here: https://stackoverflow.com/a/13870512/4497962

from io import BytesIO
import matplotlib.pyplot as plt
from pdfrw import PdfReader, PdfDict
from pdfrw.buildxobj import pagexobj
from pdfrw.toreportlab import makerl
from reportlab.platypus import Flowable
from reportlab.lib.enums import TA_JUSTIFY,TA_LEFT,TA_CENTER,TA_RIGHT

class PdfImage(Flowable):
    """
    PdfImage wraps the first page from a PDF file as a Flowable
    which can be included into a ReportLab Platypus document.
    Based on the vectorpdf extension in rst2pdf (http://code.google.com/p/rst2pdf/)

    This can be used from the place where you want to return your matplotlib image
    as a Flowable:

        img = BytesIO()

        fig, ax = plt.subplots(figsize=(canvaswidth,canvaswidth))

        ax.plot([1,2,3],[6,5,4],antialiased=True,linewidth=2,color='red',label='a curve')

        fig.savefig(img,format='PDF')

        return(PdfImage(img))

    """

    def __init__(self, filename_or_object, width=None, height=None, kind='direct'):
        # If using StringIO buffer, set pointer to begining
        if hasattr(filename_or_object, 'read'):
            filename_or_object.seek(0)
            #print("read")
        self.page = PdfReader(filename_or_object, decompress=False).pages[0]
        self.xobj = pagexobj(self.page)

        self.imageWidth = width
        self.imageHeight = height
        x1, y1, x2, y2 = self.xobj.BBox

        self._w, self._h = x2 - x1, y2 - y1
        if not self.imageWidth:
            self.imageWidth = self._w
        if not self.imageHeight:
            self.imageHeight = self._h
        self.__ratio = float(self.imageWidth)/self.imageHeight
        if kind in ['direct','absolute'] or width==None or height==None:
            self.drawWidth = width or self.imageWidth
            self.drawHeight = height or self.imageHeight
        elif kind in ['bound','proportional']:
            factor = min(float(width)/self._w,float(height)/self._h)
            self.drawWidth = self._w*factor
            self.drawHeight = self._h*factor

    def wrap(self, availableWidth, availableHeight):
        """
        returns draw- width and height

        convenience function to adapt your image 
        to the available Space that is available
        """
        return self.drawWidth, self.drawHeight

    def drawOn(self, canv, x, y, _sW=0):
        """
        translates Bounding Box and scales the given canvas
        """
        if _sW > 0 and hasattr(self, 'hAlign'):
            a = self.hAlign
            if a in ('CENTER', 'CENTRE', TA_CENTER):
                x += 0.5*_sW
            elif a in ('RIGHT', TA_RIGHT):
                x += _sW
            elif a not in ('LEFT', TA_LEFT):
                raise ValueError("Bad hAlign value " + str(a))

        #xobj_name = makerl(canv._doc, self.xobj)
        xobj_name = makerl(canv, self.xobj)

        xscale = self.drawWidth/self._w
        yscale = self.drawHeight/self._h

        x -= self.xobj.BBox[0] * xscale
        y -= self.xobj.BBox[1] * yscale

        canv.saveState()
        canv.translate(x, y)
        canv.scale(xscale, yscale)
        canv.doForm(xobj_name)
        canv.restoreState()
复古式 2024-09-20 20:26:42

根据 ReportLab 的常见问题解答,这只能通过 ReportLab 实现加:

我可以在 PDF 中使用矢量图形吗?

不,开源包不行
这。 PageCatcher(参见前面的
答案)让您轻松
通过保存合并任何矢量图像
它作为 PDF,然后准确使用它
就像图像文件一样,然后报告
标记语言接受 PDF 文件
还有 JPG、GIF 和 PNG。

更新:我已经有一段时间没有研究过这个问题了,但是在pdfrw 它说:

pdfrw可以读写PDF文件,也​​可以用来读取PDF文件,然后在reportlab中使用。

According to ReportLab's FAQ this is only possible with ReportLab PLUS:

Can I use vector graphics in my PDFs?

No, the Open Source package doesn't do
this. PageCatcher (see the previous
answer) allows you to easily
incorporate any vector image by saving
it as a PDF and then using it exactly
as you would an image file, and Report
Markup Language accepts PDF files
along with JPG, GIF and PNG.

Update: I haven't looked into this for a while but on the page of pdfrw it says:

pdfrw can read and write PDF files, and can also be used to read in PDFs which can then be used inside reportlab.

極樂鬼 2024-09-20 20:26:42

您可以使用 matplotlib 中的 svg 导出功能,并使用 svglib python 库在 reportlab 生成的 PDF 文件中包含矢量图形。 svglib 采用 svg 文件并制作可直接在 reportlab 中使用的绘图对象。

另请参阅此问题以了解更多详细信息:从 SVG 输入生成 PDF

You can use svg export from matplotlib and use svglib python library to include vector graphics in reportlab generated PDF files. svglib takes a svg file and makes a drawing object that can be directly used in reportlab.

See also this question for more details: Generating PDFs from SVG input

凉城已无爱 2024-09-20 20:26:42

使用 from reportlab.graphics import renderPDF

Use from reportlab.graphics import renderPDF

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