from pptx import Presentation from pptx.util import Inches, Pt, Cm from pptx.dml.color import RGBColor from pptx.enum.text import PP_ALIGN from pptx.enum.text import MSO_ANCHOR # 导入正确的垂直对齐枚举 from pptx.enum.shapes import MSO_SHAPE from pptx.chart.data import ChartData from pptx.enum.chart import XL_CHART_TYPE from pptx.table import Table def apply_gradient_background(slide): """应用统一的渐变背景""" background = slide.background fill = background.fill fill.gradient() fill.gradient_stops[0].color.rgb = RGBColor(0, 32, 96) # 深蓝 fill.gradient_stops[1].color.rgb = RGBColor(0, 112, 192) # 蓝色 def create_content_slide(prs, title_text, subtitle_text=None, content_items=None): """创建带二级标题的内容页""" slide_layout = prs.slide_layouts[6] # 空白布局 slide = prs.slides.add_slide(slide_layout) apply_gradient_background(slide) # 添加主标题 left = Cm(1.5) top = Cm(1.5) width = Cm(10) height = Cm(2) title_box = slide.shapes.add_textbox(left, top, width, height) tf = title_box.text_frame tf.clear() p = tf.add_paragraph() p.text = title_text p.font.size = Pt(36) p.font.color.rgb = RGBColor(255, 255, 255) p.font.bold = True # 添加二级标题(如果有) if subtitle_text: left = Cm(1.5) top = Cm(3) width = Cm(10) height = Cm(1.5) subtitle_box = slide.shapes.add_textbox(left, top, width, height) tf = subtitle_box.text_frame tf.clear() p = tf.add_paragraph() p.text = subtitle_text p.font.size = Pt(24) p.font.color.rgb = RGBColor(200, 230, 255) # 浅蓝色 p.font.italic = True # 添加内容区域 if content_items: # 添加内容文字 left_text = Cm(2) top_text = Cm(5.5 if subtitle_text else 4.5) width_text = Cm(27.5) height_text = Cm(8) text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text) tf = text_box.text_frame tf.clear() for item in content_items: p = tf.add_paragraph() p.text = item["text"] p.font.size = Pt(item.get("size", 18)) p.font.color.rgb = RGBColor(255, 255, 255) p.space_after = Pt(item.get("space_after", 8)) p.level = item.get("level", 0) if item.get("bold", False): p.font.bold = True if item.get("bullet", False): p.text = "• " + p.text return slide def create_table_slide(prs, title_text, subtitle_text, headers, data): """创建带表格的数据页""" slide = create_content_slide(prs, title_text, subtitle_text) # 计算表格位置和大小 left = Cm(2) top = Cm(5.5 if subtitle_text else 4.5) width = Cm(26.5) height = Cm(8) # 创建表格 (行数=数据行数+1,列数=标题数) rows = len(data) + 1 cols = len(headers) table = slide.shapes.add_table(rows, cols, left, top, width, height).table # 设置表格样式 table.first_row = True # 强调第一行 table.horz_banding = True # 横向条纹 # 设置表头 for col_idx, header in enumerate(headers): cell = table.cell(0, col_idx) cell.text = header cell.fill.solid() cell.fill.fore_color.rgb = RGBColor(0, 64, 128) # 深蓝色表头 cell.text_frame.paragraphs[0].font.color.rgb = RGBColor(255, 255, 255) cell.text_frame.paragraphs[0].font.bold = True cell.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER # 填充表格数据 for row_idx, row_data in enumerate(data, start=1): for col_idx, cell_data in enumerate(row_data): cell = table.cell(row_idx, col_idx) cell.text = str(cell_data) cell.fill.solid() cell.fill.fore_color.rgb = RGBColor(255, 255, 255) cell.fill.fore_color.alpha = 0.2 # 半透明白色 cell.text_frame.paragraphs[0].font.color.rgb = RGBColor(0, 0, 0) # 黑色文字 cell.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER # 设置表格边框 for cell in table.iter_cells(): cell.margin_left = Cm(0.1) cell.margin_right = Cm(0.1) cell.margin_top = Cm(0.05) cell.margin_bottom = Cm(0.05) cell.vertical_anchor = MSO_ANCHOR.MIDDLE return slide def create_chart_slide(prs, title_text, subtitle_text, categories, data): """创建图表的数据页""" slide = create_content_slide(prs, title_text, subtitle_text) #半透明白色背景 left_content = Cm(1.5) top_content = Cm(5 if subtitle_text else 4) # 根据是否有二级标题调整位置 width_content = Cm(28.5) height_content = Cm(9) content_box = slide.shapes.add_shape( MSO_SHAPE.ROUNDED_RECTANGLE, left_content, top_content, width_content, height_content ) content_box.fill.solid() content_box.fill.fore_color.rgb = RGBColor(255, 255, 255) content_box.fill.fore_color.alpha = 0.2 # 20%透明度 content_box.line.color.rgb = RGBColor(200, 230, 255) # 添加图表数据 chart_data = ChartData() chart_data.categories = categories for lable_data in data: chart_data.add_series(lable_data[0], lable_data[1]) # 添加图表 left_chart = Cm(3) top_chart = Cm(6) width_chart = Cm(25) height_chart = Cm(7) chart = slide.shapes.add_chart( XL_CHART_TYPE.LINE, left_chart, top_chart, width_chart, height_chart, chart_data ) # 设置图表颜色以匹配主题 chart.chart.plots[0].series[0].format.fill.solid() chart.chart.plots[0].series[0].format.fill.fore_color.rgb = RGBColor(100, 180, 255) chart.chart.plots[0].series[1].format.fill.solid() chart.chart.plots[0].series[1].format.fill.fore_color.rgb = RGBColor(200, 230, 255) return slide def create_image_layout_slide(prs, title_text, subtitle_text, images): """创建图片布局页面""" slide = create_content_slide(prs, title_text, subtitle_text) # 清除默认内容区域 for shape in slide.shapes: if shape.shape_type == MSO_SHAPE.ROUNDED_RECTANGLE: sp = shape._element sp.getparent().remove(sp) # 根据图片数量决定布局 if len(images) == 1: # 单张大图布局 left = Cm(3) top = Cm(5 if subtitle_text else 4) width = Cm(25) height = Cm(12) pic = slide.shapes.add_picture(images[0]["path"], left, top, width, height) # 添加图片说明 if "caption" in images[0]: left_cap = Cm(3) top_cap = Cm(17 if subtitle_text else 16) width_cap = Cm(25) height_cap = Cm(1) cap = slide.shapes.add_textbox(left_cap, top_cap, width_cap, height_cap) tf = cap.text_frame p = tf.add_paragraph() p.text = images[0]["caption"] p.font.size = Pt(14) p.font.color.rgb = RGBColor(200, 230, 255) p.alignment = PP_ALIGN.CENTER elif len(images) == 2: # 两张图片并排布局 # 第一张图片 left1 = Cm(2) top1 = Cm(5 if subtitle_text else 4) width1 = Cm(13) height1 = Cm(12) pic1 = slide.shapes.add_picture(images[0]["path"], left1, top1, width1, height1) # 第二张图片 left2 = Cm(16) top2 = Cm(5 if subtitle_text else 4) width2 = Cm(13) height2 = Cm(12) pic2 = slide.shapes.add_picture(images[1]["path"], left2, top2, width2, height2) # 添加图片说明 for i, img in enumerate(images): if "caption" in img: left_cap = Cm(2 if i == 0 else 16) top_cap = Cm(17 if subtitle_text else 16) width_cap = Cm(13) height_cap = Cm(1) cap = slide.shapes.add_textbox(left_cap, top_cap, width_cap, height_cap) tf = cap.text_frame p = tf.add_paragraph() p.text = img["caption"] p.font.size = Pt(12) p.font.color.rgb = RGBColor(200, 230, 255) p.alignment = PP_ALIGN.CENTER elif len(images) >= 3: # 三张图片网格布局 img_size = Cm(8) gap = Cm(1) # 第一行 for i in range(min(3, len(images))): left = Cm(3) + (img_size + gap) * i top = Cm(5 if subtitle_text else 4) pic = slide.shapes.add_picture(images[i]["path"], left, top, img_size, img_size) if "caption" in images[i]: left_cap = left top_cap = top + img_size + Cm(0.5) width_cap = img_size height_cap = Cm(1) cap = slide.shapes.add_textbox(left_cap, top_cap, width_cap, height_cap) tf = cap.text_frame p = tf.add_paragraph() p.text = images[i]["caption"] p.font.size = Pt(10) p.font.color.rgb = RGBColor(200, 230, 255) p.alignment = PP_ALIGN.CENTER # 第二行(如果有4张以上图片) img_size = Cm(4) gap = Cm(1) for i in range(3, len(images)): left = Cm(3) + (img_size + gap) * (i - 3) top = Cm(16 if subtitle_text else 15) pic = slide.shapes.add_picture(images[i]["path"], left, top, img_size, img_size) if "caption" in images[i]: left_cap = left top_cap = top + img_size + Cm(0.5) width_cap = img_size height_cap = Cm(1) cap = slide.shapes.add_textbox(left_cap, top_cap, width_cap, height_cap) tf = cap.text_frame p = tf.add_paragraph() p.text = images[i]["caption"] p.font.size = Pt(10) p.font.color.rgb = RGBColor(200, 230, 255) p.alignment = PP_ALIGN.CENTER return slide def create_unified_ppt(output_filename): # 创建一个16:9宽屏演示文稿对象 prs = Presentation() #prs.slide_width = Inches(13.333) # 16:9的宽度 #prs.slide_height = Inches(7.5) # 16:9的高度 prs.slide_width = Inches(16) # 16:9的宽度 prs.slide_height = Inches(9) # 16:9的高度 # ===== 封面幻灯片 ===== slide_layout = prs.slide_layouts[6] # 空白布局 slide = prs.slides.add_slide(slide_layout) apply_gradient_background(slide) # 添加宽屏标题 left = Cm(1.5) top = Cm(4) width = Cm(30) height = Cm(4) title_box = slide.shapes.add_textbox(left, top, width, height) tf = title_box.text_frame p = tf.add_paragraph() p.text = "专业商务演示" p.font.size = Pt(48) p.font.color.rgb = RGBColor(255, 255, 255) p.font.bold = True p.alignment = PP_ALIGN.LEFT # 添加副标题 left = Cm(1.5) top = Cm(8) width = Cm(20) height = Cm(2) subtitle_box = slide.shapes.add_textbox(left, top, width, height) tf = subtitle_box.text_frame p = tf.add_paragraph() p.text = "包含表格和图片布局的演示文稿" p.font.size = Pt(20) p.font.color.rgb = RGBColor(200, 230, 255) p.alignment = PP_ALIGN.LEFT # ===== 目录幻灯片 ===== create_content_slide( prs, "内容目录", content_items=[ {"text": "1. 项目概述", "size": 24, "space_after": 12}, {"text": "2. 市场分析", "size": 24, "space_after": 12}, {"text": "3. 财务数据", "size": 24, "space_after": 12}, {"text": "4. 产品展示", "size": 24, "space_after": 12}, {"text": "5. 技术架构", "size": 24, "space_after": 12} ] ) # ===== 一级标题内容页 ===== create_content_slide( prs, "项目概述", content_items=[ {"text": "项目背景", "size": 22, "bold": True, "space_after": 8}, {"text": "随着数字化转型加速,企业需要更高效的解决方案来应对市场变化。", "bullet": True}, {"text": "本项目旨在开发一套智能化管理系统,提升企业运营效率。", "bullet": True}, {"text": "项目目标", "size": 22, "bold": True, "space_after": 8, "space_before": 12}, {"text": "构建可扩展的技术架构,支持未来5年业务增长", "bullet": True}, {"text": "实现关键业务流程自动化,减少人工干预", "bullet": True}, {"text": "提供数据分析和决策支持功能", "bullet": True} ] ) # ===== 带二级标题的内容页 ===== create_content_slide( prs, "技术架构", "核心技术组件", # 二级标题 content_items=[ {"text": "前端技术", "size": 22, "bold": True, "space_after": 8}, {"text": "采用React框架构建响应式用户界面", "bullet": True}, {"text": "使用TypeScript提高代码质量", "bullet": True}, {"text": "后端技术", "size": 22, "bold": True, "space_after": 8, "space_before": 12}, {"text": "基于Spring Boot的微服务架构", "bullet": True}, {"text": "使用Kubernetes进行容器编排", "bullet": True}, {"text": "数据库技术", "size": 22, "bold": True, "space_after": 8, "space_before": 12}, {"text": "主数据库: PostgreSQL 14", "bullet": True}, {"text": "缓存层: Redis集群", "bullet": True}, {"text": "数据分析: Elasticsearch", "bullet": True} ] ) # ===== 表格数据页面 ===== headers = ["季度", "营收(万元)", "同比增长", "利润率", "市场份额"] data = [ ["Q1 2023", 1250, "12.5%", "18.2%", "22.4%"], ["Q2 2023", 1430, "15.8%", "19.1%", "23.7%"], ["Q3 2023", 1580, "18.2%", "20.3%", "25.1%"], ["Q4 2023", 1720, "20.1%", "21.5%", "26.8%"], ["Q1 2024", 1850, "22.7%", "22.8%", "28.3%"] ] create_table_slide( prs, "财务数据", "2023-2024季度表现", headers, data ) # ===== 图片布局页面(单张大图)===== create_image_layout_slide( prs, "产品展示", "旗舰产品全景", [{ "path": "product.jpg", # 替换为实际图片路径 "caption": "图1: 公司旗舰产品XYZ系列" }] ) # ===== 图片布局页面(两张并排)===== create_image_layout_slide( prs, "技术对比", "新旧技术方案比较", [ { "path": "product.jpg", # 替换为实际图片路径 "caption": "图2: 传统技术方案" }, { "path": "product.jpg", # 替换为实际图片路径 "caption": "图3: 创新技术方案" } ] ) # ===== 图片布局页面(三栏)===== create_image_layout_slide( prs, "应用场景", "多领域解决方案", [ { "path": "product.jpg", # 替换为实际图片路径 "caption": "工业制造" }, { "path": "product.jpg", # 替换为实际图片路径 "caption": "金融服务" }, { "path": "product.jpg", # 替换为实际图片路径 "caption": "医疗健康" }, ] ) # ===== 图片布局页面(多栏)===== create_image_layout_slide( prs, "应用场景", "多领域解决方案", [ { "path": "product.jpg", # 替换为实际图片路径 "caption": "工业制造" }, { "path": "product.jpg", # 替换为实际图片路径 "caption": "金融服务" }, { "path": "product.jpg", # 替换为实际图片路径 "caption": "医疗健康" }, { "path": "product.jpg", # 替换为实际图片路径 "caption": "医疗健康" }, { "path": "product.jpg", # 替换为实际图片路径 "caption": "医疗健康" }, ] ) # ===== 图表幻灯片 ===== slide = create_chart_slide( prs, "市场分析", "近五年增长趋势", # 二级标题 categories = ['2019', '2020', '2021', '2022', '2023'], data = [ ['市场规模(亿元)', [45, 52, 61, 78, 92]], ['年增长率(%)', [8.2, 15.6, 17.3, 27.9, 17.9]], ] ) # ===== 结束幻灯片 ===== slide = create_content_slide( prs, "感谢聆听", "期待与您合作" ) # 在内容区域添加联系信息 left = Cm(12) top = Cm(12) width = Cm(16) height = Cm(3) contact_box = slide.shapes.add_textbox(left, top, width, height) tf = contact_box.text_frame p = tf.add_paragraph() p.text = "联系方式" p.font.size = Pt(24) p.font.color.rgb = RGBColor(255, 255, 255) p.font.bold = True p.alignment = PP_ALIGN.CENTER p.space_after = Pt(16) p = tf.add_paragraph() p.text = "邮箱: contact@example.com\n电话: 123-456-7890\n网址: www.example.com" p.font.size = Pt(18) p.font.color.rgb = RGBColor(200, 230, 255) p.alignment = PP_ALIGN.CENTER p.space_before = Pt(8) # 保存演示文稿 prs.save(output_filename) if __name__ == "__main__": # 使用前请替换示例图片路径为实际图片路径 create_unified_ppt("professional_presentation_with_tables_and_images.pptx") print("带表格和图片布局的PPT生成完成!")