【问题标题】:How to add an image to PDF using Python and create a report from esri geodatabase tables如何使用 Python 将图像添加到 PDF 并从 esri 地理数据库表创建报告
【发布时间】:2026-02-02 02:55:01
【问题描述】:

我有一个旧脚本,它使用 SSReport 创建和生成添加一些基本数据的 PDF。我想更新它以包含一个图像文件并遍历一些 esri 地理数据库表。我在 SSReport 库上没有看到太多使用 2.7 的文档。有更新/更好的方法吗?

如果可能,我不想安装第 3 方软件包。

import SSReport as REPORT
pdfOutput = REPORT.openPDF(fileName)

#Set up Table
NumColumns = 4
report = REPORT.startNewReport(NumColumns,
                               title = 'Report ',
                               landscape = False,
                               numRows = "", # probably empty
                               titleFont = REPORT.ssTitleFont)

grid = report.grid
grid.writeCell((grid.rowCount, 1),"hello world",justify = "left",)
grid.finalizeTable() # Will fill empty rows with spaces.
report.write(pdfOutput) # write to PDF

【问题讨论】:

    标签: python matplotlib pdf-generation esri arcpy


    【解决方案1】:

    总的来说,我想创建一个 PDF 报告,其中包括地图、图像和一些存储在 Esri 地理数据库中的表格数据。由于缺乏关于上述方法的信息和时间紧迫,我最终依靠 arcpy.Mapping 来更新包括图像在内的地图图层元素并导出布局。

    我使用 MatplotLib 生成额外的图表和表格,因为有很多示例和线程可以提供帮助。还随 ArcGIS Desktop 和 Server 一起安装,以避免为客户端安装 3rd 方库的先决条件。

    示例如下:

    import matplotlib.pyplot as plt
    import xlrd
    import xlwt
    import datetime
    import os
    import glob
    import arcpy
    import SSReport as REPORT
    import numpy as NUM
    from matplotlib.backends.backend_pdf import PdfPages as PDF
    import matplotlib.pyplot as PLT
    
    # get path for mxd template from location of script
    filePath = os.path.dirname(os.path.abspath(__file__))
    templatePath = os.path.join(filePath,"templates")
    
    def TabletoPDF2(outdir, outputPDF):
    
        tables = [os.path.join(outdir,'scratch.gdb', 'table1'),
                  os.path.join(outdir, 'scratch.gdb', 'table2')]
    
        pp = PDF(outputPDF)
    
        for table in tables:
            # convert to format for creating charts.
            ntab = arcpy.da.TableToNumPyArray(table, "*")
            columns = [fld for fld in ntab.dtype.names if fld not in ["OBJECTID"]]
            cell_text = []
            for row in ntab.tolist():
                cell_text.append(row[1:])
    
            fig = PLT.figure(figsize=(8.2, 10.6))
    
            # Create PIECHART (percent lengeth)
            ax1 = PLT.subplot(211)
    
            data = ntab["percent_len"].tolist()
            vals = [x for x in data if x > 0.]
            labels = ntab[columns[0]].tolist()
            labels = [n for n, v in zip(labels, data) if v > 0]
            ax1.pie(vals, autopct='%1.1f%%', shadow=True, startangle=90)
            ax1.axis('equal')
            ax1.legend(labels, loc='center right', fontsize=8, bbox_to_anchor=(1, 1))
    
            # Create TABLE of values
            ax2 = PLT.subplot(212)
            the_table = PLT.table(cellText=cell_text, colLabels=columns, loc='center')
            the_table.auto_set_font_size(True)
            PLT.axis('off')
    
            PLT.tight_layout()
    
            #### Set Title ####
            title = os.path.basename(table)
            PLT.suptitle(title, fontsize=11, fontweight='bold')
    
            pp.savefig(fig)
        pp.close()
    
        return outputPDF
    
    
    def CreatePDFReport(sPath, outprofilegraph, sfroute_feat):
    
        template_mxd_filename = os.path.join(templatePath,'Reportemplate.mxd')
    
        layoutpdf_filename = os.path.join(sPath,'Layout.pdf')
        tablepdf_filename = os.path.join(sPath,'TableReport.pdf')
        finalpdf_filename  = os.path.join(sPath,'Final Report.pdf')
    
        #Create layout report (page1)
        arcpy.AddMessage("Creating Layout...")
        arcpy.AddMessage(template_mxd_filename)
        mxd = arcpy.mapping.MapDocument(template_mxd_filename)
        change_picture_element(mxd, outprofilegraph)
        change_layer_source(mxd, sfroute_feat)
        arcpy.mapping.ExportToPDF(mxd,layoutpdf_filename)
    
        # Create Table Report(page2)
        TablePDF = CreateTableReport(tablepdf_filename)
        TablePDF = TabletoPDF2(sPath, tablepdf_filename)
    
        #Create Final report (merge)
        msg = ("Creating Output Report {}".format(finalpdf_filename))
        arcpy.AddMessage(msg)
        if os.path.exists(finalpdf_filename):
          os.remove(finalpdf_filename)
        pdfFinal = arcpy.mapping.PDFDocumentCreate(finalpdf_filename)
        pdfFinal.appendPages(layoutpdf_filename)
        pdfFinal.appendPages(TablePDF)
        pdfFinal.saveAndClose()
    
        os.remove(tablepdf_filename)
        os.remove(layoutpdf_filename)
    
        return finalpdf_filename
    
    
    def change_layer_source(mxd, route_feat):
        """ Update layer datasource and zoom to extent """
    
        arcpy.AddMessage(route_feat)
        replace_workspace_path, datasetname = os.path.split(route_feat)
    
    
        df = arcpy.mapping.ListDataFrames(mxd)[0]
        for lyr in arcpy.mapping.ListLayers(mxd, data_frame=df):
            if lyr.name == 'RouteLayer':
                lyr.replaceDataSource (replace_workspace_path, "None")
                ext = lyr.getExtent()
                df.extent = ext
        # mxd.save()
    
    def change_picture_element(mxd, outprofilegraph):
        for elm in arcpy.mapping.ListLayoutElements(mxd, "PICTURE_ELEMENT"):
            if elm.name == "elevprofile":
                elm.sourceImage = outprofilegraph
        # mxd.save()
    
    
    if __name__ == '__main__':
    
        folderPath = arcpy.GetParameterAsText(0)
        inTable = arcpy.GetParameterAsText(1)
        sfroute_feat = arcpy.GetParameterAsText(2)
    
        finalReport = CreatePDFReport(folderPath, outprofilegraph, sfroute_feat)
    
        # Set outputs
        arcpy.SetParameterAsText(4, finalReport)
    

    【讨论】: