PDF image in PDF document using ReportLab (Python)

前端 未结 4 1632
故里飘歌
故里飘歌 2021-01-17 11:43

I saved some plots from matplotlib into a pdf format because it seems to offer a better quality. How do I include the PDF image into a PDF document using ReportLab? The conv

相关标签:
4条回答
  • 2021-01-17 12:16

    Use from reportlab.graphics import renderPDF

    0 讨论(0)
  • 2021-01-17 12:30

    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()
    
    0 讨论(0)
  • 2021-01-17 12:33

    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

    0 讨论(0)
  • 2021-01-17 12:37

    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.

    0 讨论(0)
提交回复
热议问题