如何用ReportLab缩放SVG适配PDF页面(不修改matplotlib的figsize)
问题:无需保存SVG文件,在生成PDF前缩放绘图适配页面(不修改matplotlib的figsize)
我找到一段无需保存绘图文件即可生成含绘图PDF的代码,现在希望在将SVG添加到PDF前对其进行缩放以适配页面,但不想通过修改matplotlib的figsize参数实现。尝试用svgutils调整SVG尺寸但效果不理想,现有代码如下:
from reportlab.graphics import renderPDF from reportlab.lib.pagesizes import LETTER from reportlab.pdfgen.canvas import Canvas from io import BytesIO from svglib.svglib import svg2rlg def one_page_pdf(file_name, figs, text="Default"): canvas = Canvas(filename=file_name, pagesize=(LETTER[1], LETTER[0])) img_data = BytesIO() figs.savefig(img_data, format="svg") # figs.set_size_inches(6, 6) img_data.seek(0) drawing = svg2rlg(img_data) renderPDF.draw(drawing, canvas, 10, 100) canvas.drawString(10, 50, text) canvas.showPage() canvas.save()
请问该如何正确实现这一需求?
解决方案:通过ReportLab的画布缩放或Drawing对象缩放实现
你可以通过以下两种方式实现SVG绘图的缩放,无需修改matplotlib的figsize:
方法1:直接缩放ReportLab的Drawing对象
获取绘图的原始尺寸,计算适配页面可用区域的缩放比例,然后对Drawing对象进行缩放:
from reportlab.graphics import renderPDF from reportlab.lib.pagesizes import LETTER from reportlab.pdfgen.canvas import Canvas from io import BytesIO from svglib.svglib import svg2rlg def one_page_pdf(file_name, figs, text="Default"): # 页面尺寸:横向LETTER,(宽度, 高度),单位为点(1英寸=72点) page_width, page_height = (LETTER[1], LETTER[0]) canvas = Canvas(filename=file_name, pagesize=(page_width, page_height)) # 将matplotlib绘图导出为SVG到内存 img_data = BytesIO() figs.savefig(img_data, format="svg") img_data.seek(0) # 转换SVG为ReportLab的Drawing对象 drawing = svg2rlg(img_data) # 定义页面边距:左右10点,上下分别留100点(顶部)和60点(底部文本区域) margin_left = 10 margin_right = 10 margin_top = 100 margin_bottom = 60 # 计算可用区域尺寸 available_width = page_width - margin_left - margin_right available_height = page_height - margin_top - margin_bottom # 获取绘图原始尺寸 draw_width = drawing.width draw_height = drawing.height # 计算缩放比例:取宽高比例的最小值,保证绘图完整适配可用区域 scale_x = available_width / draw_width scale_y = available_height / draw_height scale_factor = min(scale_x, scale_y) # 缩放Drawing对象 drawing.scale(scale_factor, scale_factor) # 计算绘图的绘制位置(垂直居中) draw_x = margin_left draw_y = margin_bottom + (available_height - draw_height * scale_factor) / 2 # 绘制缩放后的绘图 renderPDF.draw(drawing, canvas, draw_x, draw_y) # 绘制文本 canvas.drawString(margin_left, margin_bottom - 10, text) canvas.showPage() canvas.save()
方法2:通过Canvas的状态管理缩放画布
利用ReportLab Canvas的saveState()和restoreState()临时缩放画布,绘制完成后恢复原状态:
from reportlab.graphics import renderPDF from reportlab.lib.pagesizes import LETTER from reportlab.pdfgen.canvas import Canvas from io import BytesIO from svglib.svglib import svg2rlg def one_page_pdf(file_name, figs, text="Default"): page_width, page_height = (LETTER[1], LETTER[0]) canvas = Canvas(filename=file_name, pagesize=(page_width, page_height)) img_data = BytesIO() figs.savefig(img_data, format="svg") img_data.seek(0) drawing = svg2rlg(img_data) margin_left = 10 margin_right = 10 margin_top = 100 margin_bottom = 60 available_width = page_width - margin_left - margin_right available_height = page_height - margin_top - margin_bottom draw_width = drawing.width draw_height = drawing.height scale_x = available_width / draw_width scale_y = available_height / draw_height scale_factor = min(scale_x, scale_y) # 保存当前画布状态,准备缩放 canvas.saveState() # 平移到边距位置,再缩放画布 canvas.translate(margin_left, margin_bottom) canvas.scale(scale_factor, scale_factor) # 绘制绘图(此时坐标已缩放,直接用0,0作为起点即可) renderPDF.draw(drawing, canvas, 0, 0) # 恢复画布原状态 canvas.restoreState() canvas.drawString(margin_left, margin_bottom - 10, text) canvas.showPage() canvas.save()
关键说明
- 两种方法都通过计算可用区域与绘图原始尺寸的比例确定缩放因子,保证绘图完整适配页面且不变形
- 方法1直接修改
Drawing对象的尺寸,适合需要多次复用该绘图的场景 - 方法2通过画布状态管理实现临时缩放,不修改
Drawing对象本身,更灵活
内容的提问来源于stack exchange,提问作者Mustafa Almashhadani
相关产品推荐
相关产品推荐

