-*- coding: utf-8 -*-
import os
import shapefile
from reportlab.lib.pagesizes import letter, A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, Image, PageBreak
from reportlab.lib.units import inch, cm
from reportlab.lib import colors
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime
font_path = 'C:/Windows/Fonts/simsun.ttc'
注册中文字体(需要提前下载中文字体文件,如simsun.ttf)
try:
pdfmetrics.registerFont(TTFont('SimSun',font_path))
except:
print("警告: 未找到SimSun字体,使用默认字体可能无法正确显示中文")
2. 获取样式表并修改 Heading2 样式
styles = getSampleStyleSheet()
方法一:直接修改现有的 Heading2 样式
styles['Heading2'].fontName = 'SimSun' # 使用我们注册的中文字体
可以根据需要调整其他属性
styles['Heading2'].fontSize = 14
styles['Heading2'].spaceBefore = 12
styles['Heading2'].spaceAfter = 6
方法二:创建基于 Heading2 的新样式(推荐,不影响其他可能的使用)
if 'CustomHeading2' not in styles:
styles.add(ParagraphStyle(
name='CustomHeading2',
parent=styles['Heading2'],
fontName='SimSun', # 关键:使用中文字体
fontSize=14,
spaceBefore=12,
spaceAfter=6
))
定义样式
def get_chinese_styles():
styles = getSampleStyleSheet()
创建中文字体样式
chinese_style = ParagraphStyle(
'ChineseStyle',
fontName='simSun',
fontSize=10,
leading=12,
alignment=TA_JUSTIFY
)
title_style = ParagraphStyle(
'ChineseTitle',
fontName='simSun',
fontSize=16,
leading=20,
alignment=TA_CENTER,
spaceAfter=30
)
heading_style = ParagraphStyle(
'ChineseHeading',
fontName='simSun',
fontSize=14,
leading=18,
alignment=TA_LEFT,
spaceAfter=12
)
return styles, chinese_style, title_style, heading_style
从Shapefile读取数据
def read_shapefile_data(shapefile_path):
sf = shapefile.Reader(shapefile_path)
fields = [field[0] for field in sf.fields[1:]] # 跳过第一个DeletionFlag字段
records = sf.records()
shapes = sf.shapes()
构建数据表
table_data = [["序号", "村名称", "农户姓名", "身份证件号", "手机号", "投保地号",
"地块名称", "地块中心点经度", "地块中心点纬度", "作物名称", "种植数量", "承包数量"]]
for i, record in enumerate(records):
计算地块中心点
shape = shapes[i]
if len(shape.points) > 0:
points = np.array(shape.points)
center_lon = np.mean(points[:, 0])
center_lat = np.mean(points[:, 1])
else:
center_lon = ""
center_lat = ""
将记录转换为列表,添加序号和中心点坐标
row = [i+1] + list(record)[:6] + [f"{center_lon:.6f}", f"{center_lat:.6f}"] + list(record)[6:]
table_data.append(row)
计算总面积
total_area =0 # sum(float(record[10]) for record in records)
return table_data, total_area, fields, records, shapes
创建地块分布图
def create_distribution_map(shapes, output_path):
设置中文字体支持
plt.rcParams['font.sans-serif'] = ['SimSun', 'SimHei', 'Microsoft YaHei', 'DejaVu Sans'] # 设置字体
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
或者使用绝对路径指定字体文件
font_path = 'C:/Windows/Fonts/simsun.ttc' # SimSun字体路径
font_prop = font_manager.FontProperties(fname=font_path)
plt.figure(figsize=(10, 8))
绘制所有地块
for shape in shapes:
if len(shape.points) > 0:
points = np.array(shape.points)
plt.fill(points[:, 0], points[:, 1], alpha=0.5, edgecolor='black')
plt.xlabel('经度')
plt.ylabel('纬度')
plt.title('塔林艾力嘎查水地玉米作物承保地块分布图')
plt.grid(True)
plt.savefig(output_path, dpi=300, bbox_inches='tight')
plt.close()
生成PDF报告
def generate_pdf_report(shapefile_path, output_pdf):
读取Shapefile数据
table_data, total_area, fields, records, shapes = read_shapefile_data(shapefile_path)
创建地块分布图
map_image_path = "distribution_map.png"
create_distribution_map(shapes, map_image_path)
设置PDF文档
doc = SimpleDocTemplate(output_pdf, pagesize=A4)
styles, chinese_style, title_style, heading_style = get_chinese_styles()
story = []
封面页
story.append(Paragraph("2025年内蒙古自治区通辽市科尔沁左翼中旗腰林毛都镇塔林艾力嘎查", title_style))
story.append(Paragraph("100%散户水地玉米作物", title_style))
story.append(Spacer(1, 1*inch))
story.append(Paragraph("验标报告", title_style))
story.append(Spacer(1, 2*inch))
story.append(Paragraph("北京东辰至远科技股份有限公司", title_style))
story.append(Paragraph("2025年6月16日", title_style))
story.append(PageBreak())
目录页
story.append(Paragraph("目录", heading_style))
story.append(Paragraph("一、标的情况概述 ...... 1", chinese_style))
story.append(Paragraph("二、遥感验标方法 ...... 3", chinese_style))
story.append(Paragraph("三、验标结果 ...... 8", chinese_style))
story.append(PageBreak())
一、标的情况概述
story.append(Paragraph("一、标的情况概述", heading_style))
overview_text = """
本次承保地块主要集中在腰林毛都镇塔林艾力嘎查,投保地块耕地等级基本为1-4级地,
塔林艾力嘎查本次投保100%散户共涉及{}户,{}个地块,承保面积合计{}亩,
实测面积{}亩,超出承保面积0%,符合数据标准要求。
""".format(len(records), len(records), total_area, total_area)
story.append(Paragraph(overview_text, chinese_style))
story.append(PageBreak())
二、遥感验标方法
story.append(Paragraph("二、遥感验标方法", heading_style))
method_text = """
为落实农业保险"双精准管理"(精准承保、精准理赔)要求,解决传统验标中存在的"地块边界模糊、
面积不准、作物识别误差大、权属信息核实困难"等问题,我司依托遥感技术(RS)、地理信息系统(GIS)
及实地核查,构建"天-空-地"一体化验标体系,实现投保地块空间位置、界线、面积、种植作物等信息的精准提取,
同步通过土地确权数据、实地调研验证地块权属与投保人信息,为农业保险承保、理赔提供科学、客观的数据支撑。
"""
story.append(Paragraph(method_text, chinese_style))
技术路线
story.append(Paragraph("1. 技术路线", heading_style))
tech_text = """
本方案采用"数据准备→遥感影像获取与处理→地块信息提取→多源数据融合验证→精度评估→成果输出"的技术流程,具体如下:
数据准备:遥感影像获取与预处理;
地块边界与面积提取;
种植作物识别;
权属与投保人信息验证
精度评估与误差修正
成果输出。
"""
story.append(Paragraph(tech_text, chinese_style))
数据准备
story.append(Paragraph("2. 数据准备", heading_style))
data_prep_text = """
(1)基础地理数据
卫星遥感影像:优先选用高分辨率光学卫星(分辨率≤0.8米)或多光谱卫星(如高分一号、PlanetScope,分辨率≤2米);
若需大范围覆盖,可结合其他亚米级高分辨率商业卫星数据。
影像要求:覆盖较快地块所在区域,成像时间与作物关键物候期(如播种期、抽穗期、收获期)匹配,云量≤10%(光学影像)。
辅助数据:
-
土地确权数据(自然资源部门提供的农村土地承包经营权确权登记数据库,含地块矢量边界、权属人、面积等信息,坐标系统为CGCS2000);
-
农业部门种植结构统计数据(作物类型、种植面积、分布范围);
-
地形数据(DEM,分辨率≤15米,用于地形校正与坡度分析);
-
气象数据(降水、温度等,用于作物生长状况辅助判断)。
(2)实地调研数据
-
抽取典型地块(覆盖不同作物类型、地形条件)开展实地测量(GPS/RTK打点),记录地块实际边界、面积、种植作物及权属人信息;
-
收集农户土地承包合同、身份证信息,核对投保人身份与地块权属一致性。
"""
story.append(Paragraph(data_prep_text, chinese_style))
story.append(PageBreak())
三、验标结果
story.append(Paragraph("三、验标结果", heading_style))
result_text = """
依据以上验标基础数据,按照标的核验流程,完成塔林艾力嘎查100%散户水地玉米作物所有承保地块验标工作。
验标结果如表1所示。
"""
story.append(Paragraph(result_text, chinese_style))
story.append(Spacer(1, 0.2*inch))
创建表格
table = Table(table_data, repeatRows=1)
table.setStyle(TableStyle([
('FONT', (0, 0), (-1, -1), 'SimSun', 8),
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('FONTSIZE', (0, 0), (-1, 0), 10),
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
('BACKGROUND', (0, 1), (-1, -1), colors.beige),
('GRID', (0, 0), (-1, -1), 1, colors.black),
('WORDWRAP', (0, 0), (-1, -1), True),
]))
story.append(table)
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph(f"合计: {total_area}亩", chinese_style))
story.append(PageBreak())
添加地块分布图
story.append(Paragraph("腰林毛都镇塔林艾力嘎查100%散户水地玉米作物承保地块卫星影像分布如图所示:", heading_style))
story.append(Spacer(1, 0.2*inch))
添加地图图像
img = Image(map_image_path, width=6*inch, height=4.8*inch)
story.append(img)
story.append(Paragraph("2025年内蒙古自治区通辽市科尔沁左翼中旗腰林毛都镇塔林艾力嘎查100%散户水地玉米作物承保地块分布图", heading_style))
生成PDF
doc.build(story)
清理临时文件
#if os.path.exists(map_image_path):
os.remove(map_image_path)
print(f"PDF报告已生成: {output_pdf}")
主函数
if name == "main":
shapefile_path = "塔林艾力嘎查.shp" # 替换为您的Shapefile路径
output_pdf = "2025内蒙中华验标报告100%散户水地玉米---塔林艾力嘎查.pdf"
generate_pdf_report(shapefile_path, output_pdf)