将JSON数据还原为PPT文件:Python自动化生成工具详解

引言

在上一篇博客中,我们实现了将PPT文件解析为JSON结构的功能。现在,我们将构建其逆向工具------通过JSON数据自动生成PPT文件。这一功能可应用于自动化报告生成、样式复用、数据驱动的PPT创建等场景。本文将详解代码实现与关键步骤。


核心代码解析

1. 颜色与对齐转换函数

将JSON中的十六进制颜色和对齐方式转换为PPT的API可识别的格式。

hex_to_rgb(rgb_tuple)

将十六进制颜色(如#FF0000)转换为RGB对象:

python 复制代码
def hex_to_rgb(rgb_tuple):
    if not rgb_tuple:
        return None
    return RGBColor(*rgb_tuple)
get_alignment(alignment_str)

将对齐字符串(如"PP_ALIGN.CENTER")转换为枚举值:

python 复制代码
def get_alignment(alignment_str):
    if alignment_str == "PP_ALIGN.LEFT":
        return PP_ALIGN.LEFT
    elif alignment_str == "PP_ALIGN.CENTER":
        return PP_ALIGN.CENTER
    elif alignment_str == "PP_ALIGN.RIGHT":
        return PP_ALIGN.RIGHT
    return PP_ALIGN.LEFT

2. 创建形状:create_shape

根据JSON数据中的形状类型(如文本框、表格、图片),动态创建对应的PPT形状。

关键逻辑:
python 复制代码
def create_shape(slide, shape_data):
    shape_type = shape_data["type"]
    left = Emu(shape_data["left"])
    top = Emu(shape_data["top"])
    width = Emu(shape_data["width"])
    height = Emu(shape_data["height"])

    if shape_type == MSO_SHAPE_TYPE.TEXT_BOX:
        shape = slide.shapes.add_textbox(left, top, width, height)
    elif shape_type == MSO_SHAPE_TYPE.TABLE:
        rows = len(shape_data.get("table", []))
        cols = max(len(row) for row in shape_data["table"]) if shape_data.get("table") else 1
        shape = slide.shapes.add_table(rows, cols, left, top, width, height).table
    elif shape_type == MSO_SHAPE_TYPE.PICTURE:
        image_path = "path/to/your/image.png"  # 需替换为实际路径
        shape = slide.shapes.add_picture(image_path, left, top, width, height)
    else:
        shape = slide.shapes.add_shape(
            MSO_SHAPE.RECTANGLE,  # 默认形状
            left,
            top,
            width,
            height
        )
    shape.rotation = shape_data.get("rotation", 0)
    return shape

3. 应用样式:apply_style

将JSON中的填充、边框样式应用到形状上。

填充样式:
python 复制代码
fill.type = MSO_FILL.SOLID  # 或BACKGROUND
fill.fore_color.rgb = hex_to_rgb(fill_data["color"])
边框样式:
python 复制代码
line.color.rgb = hex_to_rgb(line_data["color"])
line.width = Emu(line_data["width"])
line.dash_style = getattr(MSO_LINE_DASH_STYLE, line_data["dash_style"])

4. 应用文本样式:apply_text_style

根据JSON中的字体、段落设置,构建文本框内容。

示例:
python 复制代码
def apply_text_style(text_frame, text_style_data):
    for paragraph_data in text_style_data.get("paragraphs", []):
        paragraph = text_frame.add_paragraph()
        paragraph.text = paragraph_data["text"]
        paragraph.alignment = get_alignment(paragraph_data["alignment"])
        for run_data in paragraph_data["runs"]:
            run = paragraph.add_run()
            run.text = run_data["text"]
            font = run.font
            font.name = run_data["font"]["name"]
            font.size = Pt(run_data["font"]["size"])
            font.bold = run_data["font"].get("bold", False)
            font.color.rgb = hex_to_rgb(run_data["font"]["color"])

5. 主函数:json_to_pptx

读取JSON文件,遍历每页和每个形状,完成PPT重建。

关键步骤:
  1. 创建空白幻灯片slide_layout = prs.slide_layouts[6](索引6对应空白版式)。

  2. 遍历形状数据

    python 复制代码
    for shape_data in slide_data["shapes"]:
        shape = create_shape(slide, shape_data)
        apply_style(shape, style_data)
        if "text_style" in shape_data:
            apply_text_style(text_frame, shape_data["text_style"])
        if "table" in shape_data:
            # 填充表格内容
            for row_idx, row in enumerate(shape_data["table"]):
                for col_idx, cell_data in enumerate(row):
                    cell = table.cell(row_idx, col_idx)
                    cell.text = cell_data["text"]

使用示例

1. 输入JSON结构

假设我们有以下JSON片段(来自上篇博客的输出):

json 复制代码
{
  "slides": [
    {
      "shapes": [
        {
          "type": 1,  // MSO_SHAPE_TYPE.TEXT_BOX
          "left": 1143000,
          "top": 1143000,
          "width": 6858000,
          "height": 1683600,
          "fill": {"type": "MSO_FILL.SOLID", "color": "#FF0000"},
          "text_style": {
            "paragraphs": [
              {
                "text": "Hello World",
                "alignment": "PP_ALIGN.CENTER",
                "runs": [
                  {
                    "font": {
                      "name": "Arial",
                      "size": 24,
                      "color": "#FFFFFF"
                    }
                  }
                ]
              }
            ]
          }
        }
      ]
    }
  ]
}

2. 生成PPT

运行代码后,将得到一个包含红色文本框的PPT文件:


关键注意事项

1. 图片路径问题

代码中图片路径为硬编码:

python 复制代码
image_path = "path/to/your/image.png"

需根据JSON中的图片信息动态指定路径,或添加图片路径映射逻辑。

2. 表格合并单元格

当前代码仅填充单元格文本,未处理跨行/列合并。需扩展逻辑:

python 复制代码
row_span = cell_data.get("row_span", 1)
if row_span > 1:
    cell.merge(table.cell(row_idx + 1, col_idx))

3. 形状类型兼容性

  • 未支持的形状 :如线条、箭头等需扩展create_shape
  • 默认形状:非文本框/表格/图片的形状默认为矩形。

应用场景

  1. 自动化报告生成

    结合数据库或API数据,动态生成标准化报告(如财务月报、项目进度)。

  2. 样式复用

    将PPT模板解析为JSON后,可快速生成符合规范的新PPT。

  3. 内容迁移

    将老旧PPT内容迁移到新模板,或跨平台导出(如从PPTX到Google Slides)。


完整工具链演示

通过上篇博客的解析功能和本篇的生成功能,可实现PPT ↔ JSON的双向转换

bash 复制代码
# 步骤1:解析现有PPT为JSON
python parse_pptx.py input.pptx > parsed.json

# 步骤2:修改JSON数据
# 例如:修改文本内容、调整样式

# 步骤3:生成新PPT
python generate_pptx.py parsed.json > output.pptx

总结

通过本文的代码,开发者可将结构化JSON数据还原为PPT文件,实现自动化内容生成与样式复用。结合上篇解析功能,这一工具链可应用于:

  • 数据驱动的PPT创建:根据实时数据生成动态报告。
  • 样式标准化:确保所有PPT符合企业模板规范。
  • 版本控制:将PPT内容纳入Git等版本控制系统。

未来可进一步扩展功能,例如:

  • 支持更多形状类型(如线条、SmartArt)。
  • 智能布局调整:根据内容自适应排版。
  • API集成:与AI模型结合,生成内容并直接渲染为PPT。

通过Python和python-pptx库,PPT的自动化处理从未如此灵活!

python 复制代码
from pptx import Presentation
from pptx.util import Emu, Pt
from pptx.enum.shapes import MSO_SHAPE, MSO_SHAPE_TYPE
from pptx.enum.text import PP_ALIGN
from pptx.enum.dml import MSO_FILL, MSO_LINE_DASH_STYLE
from pptx.dml.color import RGBColor
import json


def hex_to_rgb(rgb_tuple):
    if not rgb_tuple:
        return None
    return RGBColor(*rgb_tuple)


def get_alignment(alignment_str):
    if alignment_str == "PP_ALIGN.LEFT":
        return PP_ALIGN.LEFT
    elif alignment_str == "PP_ALIGN.CENTER":
        return PP_ALIGN.CENTER
    elif alignment_str == "PP_ALIGN.RIGHT":
        return PP_ALIGN.RIGHT
    return PP_ALIGN.LEFT


def create_shape(slide, shape_data):
    shape_type = shape_data["type"]
    left = Emu(shape_data["left"])
    top = Emu(shape_data["top"])
    width = Emu(shape_data["width"])
    height = Emu(shape_data["height"])

    if shape_type == MSO_SHAPE_TYPE.TEXT_BOX:
        shape = slide.shapes.add_textbox(left, top, width, height)
    elif shape_type == MSO_SHAPE_TYPE.TABLE:
        rows = len(shape_data.get("table", []))
        cols = max(len(row) for row in shape_data["table"]) if shape_data.get("table") else 1
        shape = slide.shapes.add_table(rows, cols, left, top, width, height).table
    elif shape_type == MSO_SHAPE_TYPE.PICTURE:
        image_path = "path/to/your/image.png"  # 替换为实际图片路径
        shape = slide.shapes.add_picture(image_path, left, top, width, height)
    else:
        shape = slide.shapes.add_shape(
            MSO_SHAPE.RECTANGLE,  # 修正后的默认形状类型
            left,
            top,
            width,
            height
        )

    shape.rotation = shape_data.get("rotation", 0)
    return shape


def apply_style(shape, style_data):
    fill_data = style_data["fill"]
    line_data = style_data["line"]

    # 填充样式
    fill = shape.fill
    fill_type_str = fill_data["type"]
    if fill_type_str == "MSO_FILL.SOLID":
        fill.type = MSO_FILL.SOLID
        fill.fore_color.rgb = hex_to_rgb(fill_data["color"])
    elif fill_type_str == "MSO_FILL.BACKGROUND":
        fill.type = MSO_FILL.BACKGROUND

    # 边框样式
    line = shape.line
    color = hex_to_rgb(line_data["color"])
    if color:
        line.color.rgb = color
    line.width = Emu(line_data["width"])
    # 处理虚线样式(示例)
    if line_data.get("dash_style"):
        dash_style_str = line_data["dash_style"]
        line.dash_style = getattr(MSO_LINE_DASH_STYLE, dash_style_str.split(" ")[0])


def apply_text_style(text_frame, text_style_data):
    for paragraph_data in text_style_data.get("paragraphs", []):
        paragraph = text_frame.add_paragraph()
        paragraph.text = paragraph_data["text"]
        paragraph.level = paragraph_data.get("level", 0)
        paragraph.alignment = get_alignment(paragraph_data.get("alignment"))

        for run_data in paragraph_data.get("runs", []):
            run = paragraph.add_run()
            run.text = run_data["text"]
            font = run.font
            font.name = run_data["font"]["name"]
            font.size = Pt(run_data["font"]["size"]) if run_data["font"]["size"] else None
            font.bold = run_data["font"].get("bold", False)
            font.italic = run_data["font"].get("italic", False)
            font.color.rgb = hex_to_rgb(run_data["font"].get("color"))


def json_to_pptx(json_path, output_pptx):
    prs = Presentation()
    with open(json_path, "r", encoding="utf-8") as f:
        data = json.load(f)

    for slide_data in data["slides"]:
        slide_layout = prs.slide_layouts[6]  # 使用空白版式
        slide = prs.slides.add_slide(slide_layout)

        for shape_data in slide_data["shapes"]:
            shape = create_shape(slide, shape_data)
            apply_style(shape, {
                "fill": shape_data["fill"],
                "line": shape_data["line"]
            })

            if "text_style" in shape_data and hasattr(shape, "text_frame"):
                text_frame = shape.text_frame
                apply_text_style(text_frame, shape_data["text_style"])

            if "table" in shape_data and hasattr(shape, "table"):
                table = shape.table
                for row_idx, row in enumerate(shape_data["table"]):
                    for col_idx, cell_data in enumerate(row):
                        cell = table.cell(row_idx, col_idx)
                        cell.text = cell_data["text"]
                        row_span = cell_data.get("row_span", 1)
                        if row_span > 1:
                            cell.merge(table.cell(row_idx + 1, col_idx))

    prs.save(output_pptx)


if __name__ == "__main__":
    input_json = "presentation_info.json"
    output_pptx = "reconstructed.pptx"
    json_to_pptx(input_json, output_pptx)
相关推荐
小和尚同志5 分钟前
3. Github Actions 自动部署
程序员·开源·github
说私域1 小时前
定制开发开源AI智能名片S2B2C商城小程序:数字营销时代的话语权重构
人工智能·小程序·开源·零售
说私域3 小时前
基于开源AI大模型AI智能名片S2B2C商城小程序源码的私域流量运营与内容定位策略研究
人工智能·小程序·开源·产品运营·流量运营·零售
说私域6 小时前
基于开源AI大模型AI智能名片S2B2C商城小程序源码的销售环节数字化实现路径研究
人工智能·小程序·开源·零售
MILI元宇宙6 小时前
DeepSeek R1开源模型的技术突破与AI产业格局的重构
人工智能·重构·开源
FIT2CLOUD飞致云1 天前
飞致云开源社区月度动态报告(2025年5月)
开源
说私域1 天前
基于定制开发开源AI智能名片S2B2C商城小程序的大零售渗透策略研究
人工智能·小程序·开源·零售
xdpcxq10291 天前
.NET 开源工业视觉系统 OpenIVS 快速搭建自动化检测平台
开源·自动化·.net
别惹CC2 天前
AI赋能开源:如何借助MCP快速解锁开源项目并提交你的首个PR
人工智能·开源