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,XL_LABEL_POSITION,XL_LEGEND_POSITION from pptx.table import Table from lxml import etree from pptx.oxml.xmlchemy import OxmlElement from parse_html import parse_html_to_ppt from init import gcfg #颜色组 g_colors =[ {"name": "深空蓝", "hex": "#0D4D4B", "rgb": (13, 77, 75)}, {"name": "紫罗兰", "hex": "#4A306D", "rgb": (74, 48, 109)}, {"name": "海军蓝", "hex": "#003366", "rgb": (0, 51, 102)}, {"name": "森林绿", "hex": "#22577A", "rgb": (34, 87, 122)}, {"name": "暗玫瑰红", "hex": "#E0115F", "rgb": (224, 17, 95)}, {"name": "橄榄绿", "hex": "#556B2F", "rgb": (85, 107, 47)}, {"name": "深紫", "hex": "#35063E", "rgb": (53, 6, 62)}, {"name": "宝石蓝", "hex": "#0F52BA", "rgb": (15, 82, 186)}, ] g_colors = g_colors*4 #背景 def apply_gradient_background(prs,slide,style={}): """应用统一的背景""" # background = slide.background # fill = background.fill # fill.gradient() # #fill.gradient_angle = 270 # 从上倒下 # #fill.gradient_angle = 45 # 从左下到右上 # fill.gradient_stops[0].color.rgb = RGBColor(mc[0], mc[1], mc[2]) # 深蓝 # fill.gradient_stops[1].color.rgb = RGBColor(255,255,255) # 蓝色 if "bg_image" in style: # 设置背景图片 if style['bg_image'].startswith("/api/img"): image_path = f"{gcfg['fs']['path']}/img/{style['bg_image'].split('/')[-1]}" else: image_path = f"pic/{style['bg_image']}" left = top = Inches(0) pic = slide.shapes.add_picture(image_path, left, top, width=prs.slide_width, height=prs.slide_height) pass """0. 图片纯色背景标题""" def draw_title_by_image(prs,slide): # 将标题图片添加到幻灯片中 image_path = "pic/101_title.png" left = top = 0 pic = slide.shapes.add_picture(image_path, left, top) # 获取幻灯片尺寸 slide_width = prs.slide_width slide_height = prs.slide_height # 调整图片大小以填充整个幻灯片 pic.width = slide_width pic.height = Cm(3.2) # 可选:将图片置于底层(放在所有形状之后) # slide.shapes._spTree.remove(pic._element) # slide.shapes._spTree.insert(2, pic._element) """1. 竖道矩形标题""" def draw_title_by_range(prs,slide,mc): # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, Cm(0.9),Cm(0.5),Cm(0.5),Cm(2.8) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) """2. 竖道矩形+灰色标题框""" def draw_title_by_range2(prs,slide,mc): # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, Cm(0.7),Cm(0.5),Cm(0.5),Cm(2.8) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 灰色标题框 shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, Cm(1.5),Cm(0.5),Cm(39),Cm(2.8) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() #fill.fore_color.rgb = RGBColor(192, 192, 192) # 浅灰色填充 fill.fore_color.rgb = RGBColor(245, 245, 245) # 浅灰色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line #line.color.rgb = RGBColor(192, 192, 192) # 浅灰色填充 line.color.rgb = RGBColor(245, 245, 245) # 浅灰色填充 line.width = Pt(1) """3. 两个重叠的正方形标题框""" def draw_title_by_square2(prs,slide,mc): # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, Cm(0.3),Cm(0.9),Cm(1.4),Cm(1.4) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 灰色标题框 shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, Cm(0.9),Cm(1.7),Cm(0.9),Cm(0.9) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(192, 192, 192) # 浅灰色填充 #fill.fore_color.rgb = RGBColor(245, 245, 245) # 浅灰色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(192, 192, 192) # 浅灰色填充 #line.color.rgb = RGBColor(245, 245, 245) # 浅灰色填充 line.width = Pt(1) """4. 横线分割标题""" def draw_title_by_line(prs,slide,mc): # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, Cm(1.5),Cm(3.5),Cm(38),Cm(0.05) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) """5. 三角形标题""" def draw_title_by_triangle(prs,slide,mc): # 先添加三角形标题框(使用矩形形状 MSO_SHAPE.TRIANGLE) triangle = slide.shapes.add_shape( MSO_SHAPE.ISOSCELES_TRIANGLE, Cm(0.1),Cm(1.2),Cm(2.4),Cm(1.3) ) # 旋转三角形(角度:0-360) triangle.rotation = 90 # 旋转180度(顶点朝下) # 设置填充颜色 fill = triangle.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # fill.gradient() # fill.gradient_angle = 90 # 从左到右 # fill.gradient_stops[0].color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色 # fill.gradient_stops[1].color.rgb = RGBColor(255,255,255) # 白色 # fill.gradient_stops[1].color.alpha = 0.5 * 100000 # 50 %透明度 #获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = triangle.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(0) #创建一个只有标题的空白页 def create_content_blank_slide(prs, title_text, subtitle_text=None,style={}): """创建一个只有标题的空白页""" slide_layout = prs.slide_layouts[6] # 空白布局 slide = prs.slides.add_slide(slide_layout) #开始 main_color = style["main_color"] apply_gradient_background(prs,slide,style) if style["title_style"]==0: #白色 title_font_color = RGBColor(255, 255, 255) draw_title_by_image(prs,slide) else: #主色 title_font_color = RGBColor(main_color[0],main_color[1],main_color[2]) if style["title_style"]==1: draw_title_by_range(prs,slide,main_color) elif style["title_style"]==2: draw_title_by_range2(prs,slide,main_color) elif style["title_style"]==3: draw_title_by_square2(prs,slide,main_color) elif style["title_style"]==4: draw_title_by_line(prs,slide,main_color) elif style["title_style"]==5: draw_title_by_triangle(prs,slide,main_color) else: draw_title_by_image(prs,slide) # 添加主标题 left = Cm(1.6) top = Cm(-0.3) if subtitle_text else Cm(0.2) width = Cm(36) height = Cm(2) title_box = slide.shapes.add_textbox(left, top, width, height) tf = title_box.text_frame tf.word_wrap = True tf.clear() p = tf.add_paragraph() if subtitle_text: p.text = title_text else: p.text = title_text p.font.name="微软雅黑" p.font.size = Pt(24) p.font.color.rgb = title_font_color p.font.bold = True # 添加二级标题(如果有) if subtitle_text: #left = Cm(8.5 if len(title_text)==4 else 8.5+(len(title_text)-4)) left = Cm(1.6) top = Cm(1) width = Cm(36) height = Cm(1.5) subtitle_box = slide.shapes.add_textbox(left, top, width, height) tf = subtitle_box.text_frame tf.word_wrap = True tf.clear() p = tf.add_paragraph() p.text = subtitle_text p.font.name="微软雅黑" p.font.size = Pt(30) p.font.color.rgb = title_font_color #p.font.italic = True return slide def create_content_list_slide(prs, title_text, subtitle_text=None, content_items=None,style={},index=6): "一级内容列表" slide = create_content_blank_slide(prs, title_text, subtitle_text,style) main_color = style["main_color"] # 添加内容区域,多级列表的内容 # 布局起始位置 left_text = Cm(5) top_text = Cm(2) width_text = Cm(32) height_text = Cm(2) mc = main_color for i,item in enumerate(content_items[0:6]): if style["style"]==1: mc = g_colors[index]["rgb"] # 添加内容 index += 1 top_text += Cm(2.5) # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text-Cm(2), top_text, Cm(2), height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) #添加顺序号 text_box = slide.shapes.add_textbox(left_text-Cm(2), top_text, Cm(3), height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True #tf.clear() # 删除所有段落 tf_clean_all(tf) p = tf.add_paragraph() p.text = str(index) p.font.size = Pt(36) p.font.color.rgb = RGBColor(255, 255, 255) #白色字体 p.font.bold = True # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text, width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) #添加内容文字 text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True # 删除所有段落 tf_clean_all(tf) p = tf.add_paragraph() p.text = item["text"] p.font.size = Pt(24) if len(p.text) >70: p.font.size = Pt(18) p.font.color.rgb = RGBColor(0, 0, 0) p.font.bold = True if len(content_items) >6: slide = create_content_list_slide(prs, title_text, subtitle_text,content_items[6:],style,index) def create_content_slide(prs, title_text, subtitle_text=None, content_items=None,style={}): """创建带二级标题的内容页""" def layout_card_2_4(slide,count,content_items,mc): """横向卡片式布局, 一级level """ #起始位置 left_text = Cm(3) top_text = Cm(6) height_text = Cm(14) space_width = Cm(1) if count==2: space_width = Cm(3) width_text = Cm(15) height_text = Cm(13) elif count==3: space_width = Cm(2) width_text = Cm(10) height_text = Cm(10) elif count==4: top_text = Cm(7) width_text = Cm(8) height_text = Cm(8) index = 0 for i,item in enumerate(content_items): level = item.get("level", 0) if level ==1: #一级标题 if style["style"]==1: mc = g_colors[index]["rgb"] index +=1 ol_li = 1 # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.ROUNDED_RECTANGLE, left_text, top_text-Cm(1), width_text, Cm(3) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text-Cm(0.8), width_text, Cm(1)) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) p = tf.add_paragraph() p.text = item["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 p.font.size = Pt(22) p.font.color.rgb = RGBColor(255, 255, 255) # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text+Cm(0.5), width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加内容文字 text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True tf.clear() left_text += width_text+space_width #一级标题结束 continue #添加二级一下的文字 p = tf.add_paragraph() p.font.size = Pt(item.get("size", 18)) p.font.color.rgb = RGBColor(0, 0, 0) p.space_after = Pt(item.get("space_after", 8)) p.level = item.get("level", 2)-2 ol_li = output_text_style(p,item,RGBColor(mc[0],mc[1],mc[2]),ol_li,) def layout_seq_2_4(slide,count,content_items,mc): """横向卡片式布局, 二级level 数字序号""" #起始位置 left_text = Cm(3) top_text = Cm(6) height_text = Cm(14) space_width = Cm(1) if count==2: space_width = Cm(3) width_text = Cm(15) height_text = Cm(15) elif count==3: space_width = Cm(2) width_text = Cm(10) height_text = Cm(14) elif count==4: top_text = Cm(7) width_text = Cm(8) height_text = Cm(13) ol_li = 0 index=0 for i,item in enumerate(content_items): level = item.get("level", 0) if level ==2: #二级标题 ol_li += 1 if style["style"]==1: mc = g_colors[index]["rgb"] index +=1 # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text-Cm(0.5), width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.background() #fill.solid() #fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 圆形顺序号 shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text+(width_text-Cm(3))//2, top_text-Cm(1.5), Cm(3), Cm(3) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加序号 title_box = slide.shapes.add_textbox(left_text+(width_text-Cm(3))//2, top_text-Cm(1), Cm(3), Cm(3)) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) p = tf.add_paragraph() p.text = f'{ol_li:02d}' p.alignment = PP_ALIGN.CENTER # 设置段落居中 p.font.size = Pt(42) p.font.color.rgb = RGBColor(255, 255, 255) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text+Cm(1.5), width_text, Cm(1)) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = item["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 p.font.size = Pt(22) p.font.bold = True p.font.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 添加内容文字 text_box = slide.shapes.add_textbox(left_text, top_text+Cm(2), width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True tf.clear() left_text += width_text+space_width #一级标题结束 continue #添加二级一下的文字 p = tf.add_paragraph() p.font.size = Pt(item.get("size", 18)) p.font.color.rgb = RGBColor(0, 0, 0) p.space_after = Pt(item.get("space_after", 8)) p.level = item.get("level", 2)-2 ol_li = output_text_style(p,item,RGBColor(mc[0],mc[1],mc[2]),ol_li,) def layout_card_5(slide,count,content_items,mc): """五个圆圈, 一级level+矩形的二级 """ #起始位置 left_text = Cm(3) top_text = Cm(6) height_text = Cm(8) space_width = Cm(1) width_text = Cm(6) index=0 for i,item in enumerate(content_items): level = item.get("level", 0) if level ==1: #一级标题 if style["style"]==1: mc = g_colors[index]["rgb"] index +=1 # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text, top_text, Cm(5), Cm(5) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text+Cm(1.5), Cm(5), Cm(1)) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = item["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 p.font.size = Pt(22) p.font.color.rgb = RGBColor(255, 255, 255) # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text-Cm(0.3), top_text+Cm(6), width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill # fill.solid() # fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 fill.background() # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加内容文字 text_box = slide.shapes.add_textbox(left_text-Cm(0.3), top_text+Cm(6), width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True tf.clear() left_text += width_text+space_width #一级标题结束 continue #添加二级一下的文字 p = tf.add_paragraph() p.text = item["text"] p.font.size = Pt(item.get("size", 18)) p.font.color.rgb = RGBColor(0, 0, 0) p.space_after = Pt(item.get("space_after", 8)) p.level = 0 if item.get("bold", False): p.font.bold = True if item.get("bullet", False): p.text = "• " + p.text def layout_list_seq(slide,content_items,mc): """带序号的相同列表布局,""" # 布局起始位置 left_text = Cm(5) top_text = Cm(2) width_text = Cm(32) height_text = Cm(2) index = 0 if len(content_items)==1: layout_oval_1(slide,content_items[0],mc) elif len(content_items)==2: layout_oval_2(slide,content_items,mc) elif len(content_items)==3: layout_oval_3(slide,content_items,mc) elif len(content_items)==4: layout_oval_4(slide,content_items,mc) elif len(content_items)==5: layout_oval_5(slide,content_items,mc) elif len(content_items) >=6: for i,item in enumerate(content_items[0:6]): if style["style"]==1: mc = g_colors[i]["rgb"] # 添加内容 top_text += Cm(2.5) index += 1 # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text-Cm(2), top_text, Cm(2), height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) #添加顺序号 text_box = slide.shapes.add_textbox(left_text-Cm(2), top_text, Cm(2), height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True #tf.clear() # 删除所有段落 tf_clean_all(tf) p = tf.add_paragraph() p.text = str(index) p.font.size = Pt(36) p.font.color.rgb = RGBColor(255, 255, 255) #白色字体 p.font.bold = True # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text, width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) #添加内容文字 text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True # 删除所有段落 tf_clean_all(tf) p = tf.add_paragraph() p.text = item["text"] p.font.size = Pt(24) if len(p.text) >70: p.font.size = Pt(18) p.font.color.rgb = RGBColor(0, 0, 0) p.font.bold = True if len(content_items) >6: slide = create_content_list_slide(prs, title_text, subtitle_text,content_items[6:],style) #一级标题,一个圆 def layout_oval_1(slide,item,mc): # 布局起始位置 left_text = Cm(12) top_text = Cm(6) width_text = Cm(15) height_text = Cm(15) # 先添加圆形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text, top_text, width_text,height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text+height_text/2-Cm(2), width_text,height_text) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = item["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 p.font.size = Pt(22) p.font.color.rgb = RGBColor(255, 255, 255) #一级标题,两个圆 def layout_oval_2(slide,items,mc): # 布局起始位置 left_text = Cm(6) top_text = Cm(6) width_text = Cm(14) height_text = Cm(14) for i,item in enumerate(items): if style["style"]==1: mc = g_colors[i]["rgb"] # 先添加圆形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text, top_text, width_text,height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text+i*Cm(2), top_text+height_text/2-Cm(3), width_text-Cm(2),height_text) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = item["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 if len(item["text"]) <150: p.font.size = Pt(22) else: p.font.size = Pt(16) p.font.color.rgb = RGBColor(255, 255, 255) left_text += width_text -Cm(2) #一级标题,三个圆 def layout_oval_3(slide,items,mc): # 布局起始位置 left_text = Cm(15.5) top_text = Cm(4.3) width_text = Cm(9) height_text = Cm(9) # 先添加圆形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text, top_text, width_text,height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text+height_text/2-Cm(2), width_text,height_text) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = items[0]["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 if len(p.text) <50: p.font.size = Pt(20) else: p.font.size = Pt(16) p.font.color.rgb = RGBColor(255, 255, 255) # 布局起始位置 left_text = Cm(11) top_text = Cm(12) width_text = Cm(9) height_text = Cm(9) for i,item in enumerate(items[1:],1): if style["style"]==1: mc = g_colors[i]["rgb"] # 先添加圆形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text, top_text, width_text,height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text+height_text//2-Cm(2), width_text-Cm(1),height_text) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = item["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 if len(item["text"]) <50: p.font.size = Pt(20) else: p.font.size = Pt(16) p.font.color.rgb = RGBColor(255, 255, 255) left_text += width_text #一级标题,四个圆 def layout_oval_4(slide,items,mc): # 布局起始位置 left_text = Cm(6.5) top_text = Cm(4.5) width_text = Cm(8) height_text = Cm(8) for i,item in enumerate(items[0:2]): if style["style"]==1: mc = g_colors[i]["rgb"] # 先添加圆形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text, top_text, width_text,height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text+height_text/2-Cm(2), width_text,height_text) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = item["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 if len(item["text"]) <40: p.font.size = Pt(20) else: p.font.size = Pt(16) p.font.color.rgb = RGBColor(255, 255, 255) left_text += width_text +Cm(2) # 布局起始位置 left_text = Cm(17) top_text = Cm(13) width_text = Cm(8) height_text = Cm(8) for i,item in enumerate(items[2:],2): if style["style"]==1: mc = g_colors[i]["rgb"] # 先添加圆形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text, top_text, width_text,height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text+height_text/2-Cm(2), width_text,height_text) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = item["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 if len(item["text"]) < 50: p.font.size = Pt(20) else: p.font.size = Pt(16) p.font.color.rgb = RGBColor(255, 255, 255) left_text += width_text +Cm(2) #一级标题,5个圆 def layout_oval_5(slide,items,mc): # 布局起始位置 left_text = Cm(3) top_text = Cm(8) width_text = Cm(6) height_text = Cm(6) for i,item in enumerate(items): if style["style"]==1: mc = g_colors[i]["rgb"] # 先添加圆形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text, top_text, width_text,height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text+height_text/2-Cm(1.5), width_text,height_text) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = item["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 if len(item["text"]) <40: p.font.size = Pt(18) else: p.font.size = Pt(14) p.font.color.rgb = RGBColor(255, 255, 255) left_text += width_text + Cm(1) #一级标题+两个二级标题, 天秤 def layout_1_2(slide,items,mc): # 布局起始位置 left_text = Cm(4) top_text = Cm(6) width_text = Cm(10) height_text = Cm(10) mc0 = mc for i,item in enumerate(items[1:]): if style["style"]==1: mc = g_colors[i]["rgb"] # 先添加圆形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text, top_text, width_text,height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text+height_text/2-Cm(2), width_text,height_text) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = item["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 p.font.size = Pt(22) p.font.color.rgb = RGBColor(255, 255, 255) left_text += width_text+Cm(14) mc = mc0 #绘制天平 # 先添加矩形形状(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, Cm(5), top_text+height_text, Cm(32), Cm(0.5) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 先添加三角形标题框(使用矩形形状 MSO_SHAPE.TRIANGLE) triangle = slide.shapes.add_shape( MSO_SHAPE.ISOSCELES_TRIANGLE, Cm(20),top_text+height_text+Cm(0.5),Cm(2),Cm(2) ) # 旋转三角形(角度:0-360) #triangle.rotation = 90 # 旋转180度(顶点朝下) # 设置填充颜色 fill = triangle.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 #获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = triangle.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(0) #一级标题文字 # 添加标题 title_box = slide.shapes.add_textbox(Cm(18), top_text+height_text/2, Cm(5),height_text) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = items[0]["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居左 p.font.size = Pt(24) p.font.color.rgb = RGBColor(mc[0],mc[1],mc[2]) #一级标题+3或5个二级标题, 晾衣杆 def layout_1_3_5(slide,content_items,count,mc): """""" #起始位置 left_text = Cm(3) top_text = Cm(10) height_text = Cm(14) space_width = Cm(1) if count==3: space_width = Cm(2) width_text = Cm(10) height_text = Cm(8) elif count==5: space_width = Cm(1) width_text = Cm(6) height_text = Cm(6) mc0 = mc for i,item in enumerate(content_items[1:]): level = item.get("level", 0) if level ==2: #二级标题 if style["style"]==1: mc = g_colors[i]["rgb"] #晾衣杆-竖子梁 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text+width_text//2, Cm(7.5), Cm(0.2), Cm(1.5) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.ROUNDED_RECTANGLE, left_text, top_text-Cm(1), width_text, Cm(3) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text-Cm(0.8), width_text, Cm(1)) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) #标题内容少则放入标题框 if len(item["text"])<=6: p = tf.add_paragraph() p.text = item["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 p.font.size = Pt(22) p.font.color.rgb = RGBColor(255, 255, 255) else: # 白色圆点装饰 # 先添加圆形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text+width_text-Cm(1), top_text-Cm(0.5), Cm(0.5), Cm(0.5) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(255, 255, 255) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(255, 255, 255) # 主色填充 line.width = Pt(1) # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text+Cm(0.5), width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加内容文字 text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True tf.clear() #标题内容多则放入如容框 if len(item["text"])>6: p = tf.add_paragraph() p.text = item["text"] p.font.size = Pt(22) if count==5: p.font.size = Pt(20) p.font.color.rgb = RGBColor(0, 0, 0) left_text += width_text+space_width #一级标题结束 continue #添加二级一下的文字 p = tf.add_paragraph() p.text = item["text"] p.font.size = Pt(item.get("size", 18)) p.font.color.rgb = RGBColor(0, 0, 0) p.space_after = Pt(item.get("space_after", 8)) if item.get("bold", False): p.font.bold = True if item.get("bullet", False): p.text = "• " + p.text mc = mc0 #一级标题 # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.ROUNDED_RECTANGLE, Cm(15), Cm(4), Cm(10), Cm(2) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(Cm(15), Cm(4.5), Cm(10), Cm(2)) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) p = tf.add_paragraph() p.text = content_items[0]["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 p.font.size = Pt(24) p.font.color.rgb = RGBColor(255, 255, 255) #晾衣杆-竖主梁 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, Cm(20), Cm(6), Cm(0.2), Cm(1.5) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) #晾衣杆-横梁 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, Cm(4), Cm(7.5), Cm(32), Cm(0.3) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) #一个主圆+n个矩形 def layout_1_4_6(slide,content_items,n,main_color): """1级的一个框+二级的4个横向布局""" #二级框列表 index=0 width_text = Cm(12) if n==4: height_text = Cm(5) elif n==6: height_text = Cm(3) top_start = Cm(7) left_text = Cm(3) mc0 = main_color for item in content_items[1:]: level = item.get("level", 0) if level ==2: if style["style"]==1: main_color = g_colors[index]["rgb"] if index %2==0: #左边 left_text = Cm(3) else: left_text = Cm(3+12+10) index_level = index//2 top_text = top_start + index_level*height_text+ Cm(1)*index_level #print(index,top_text,index_level) # 先添加矩形形状(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text, width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(main_color[0],main_color[1],main_color[2]) # 主色填充 line = shape.line line.color.rgb = RGBColor(main_color[0],main_color[1],main_color[2]) # 主色填充 line.width = Pt(1) text_box = slide.shapes.add_textbox(left_text+Cm(index%2), top_text, width_text-Cm(1), height_text) hr = text_box.text_frame # 启用自动换行 hr.word_wrap = True tf_clean_all(hr) p = hr.add_paragraph() p.text = item["text"] p.font.name="微软雅黑" p.font.size = Pt(22) p.font.color.rgb = RGBColor(255, 255, 255) index +=1 else: p = hr.add_paragraph() p.text = item["text"] p.font.name="微软雅黑" p.font.size = Pt(item.get("size", 18)) #白色 p.font.color.rgb = RGBColor(255, 255, 255) if item.get("bold", False): p.font.bold = True if item.get("bullet", False): p.text = "• " + p.text # 最后画园,布局起始位置 left_text = Cm(15) top_text = Cm(7) width_text = Cm(10) height_text = Cm(10) #外面的白色大圆 main_color = mc0 # 先添加圆形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text-Cm(1), top_text-Cm(1), width_text+Cm(2),height_text+Cm(2) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(255,255,255) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(255,255,255) # 主色填充 line.width = Pt(0) # 先添加圆形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.OVAL, left_text, top_text, width_text,height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(main_color[0],main_color[1],main_color[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(main_color[0],main_color[1],main_color[2]) # 主色填充 line.width = Pt(1) # 添加标题 title_box = slide.shapes.add_textbox(left_text, top_text+height_text/2-Cm(1), width_text,height_text) tf = title_box.text_frame # 清楚之前的格式 tf_clean_all(tf) tf.word_wrap = True p = tf.add_paragraph() p.text = content_items[0]["text"] p.alignment = PP_ALIGN.CENTER # 设置段落居中 p.font.size = Pt(36) p.font.bold = True p.font.color.rgb = RGBColor(255, 255, 255) def create_codes_slide(): #根据code内容合理的划分slide codes=[] code_index=0 for item in content_items: codes.append(item) if item.get("code",False): if code_index==0: layout_blockquote_code(prs,slide,title_text,subtitle_text,codes,main_color,style) code_index +=1 codes=[] else: create_content_slide(prs, title_text, subtitle_text, codes,style) #end for #开始 main_color = style["main_color"] slide = create_content_blank_slide(prs,title_text,subtitle_text,style) # 添加内容区域,多级列表的内容 if content_items: #识别列表内容 level_1=0 level_2=0 level_3=0 blockquote_code=False codes=0 #代码块数量 for item in content_items: level = item.get("level",0) if level==1: level_1 +=1 elif level==2: level_2 +=1 elif level==3: level_3 +=1 if item.get("blockquote",False): blockquote_code = True if item.get("code",False): blockquote_code = True codes +=1 #布局 if blockquote_code: if codes >=2: create_codes_slide() #需要根据内容切成多张ppt else: layout_blockquote_code(prs,slide,title_text,subtitle_text,content_items,main_color,style) elif content_items[0].get("number",False) and level_2 in (2,3,4): #数字需要的二级 layout_seq_2_4(slide,level_2,content_items,main_color) elif ((level_1>0 and level_2==0 and level_3==0) or (level_1==0 and level_2>0 and level_3==0) or (level_1==0 and level_2==0 and level_3>0)) : #级别都相同,按顺序列表处理 layout_list_seq(slide,content_items,main_color) elif content_items[0].get("level",0)==1 and level_1 >=2 and level_1<=4 and (level_2 >0 or level_3 >0): layout_card_2_4(slide,level_1,content_items,main_color) elif content_items[0].get("level",0)==1 and level_1==5 and (level_2 >0 or level_3 >0): layout_card_5(slide,level_1,content_items,main_color) elif content_items[0].get("level",0)==1 and level_1==1 and level_2 in (4,6): layout_1_4_6(slide,content_items,level_2,main_color) elif content_items[0].get("level",0)==1 and level_1==1 and level_2 ==2: layout_1_2(slide,content_items,main_color) elif content_items[0].get("level",0)==1 and level_1==1 and level_2 in (3,5): layout_1_3_5(slide,content_items,level_2,main_color) else: if len(content_items)<=12: layout_normal(slide,subtitle_text,content_items,style) else: i=0 while 1: layout_normal(slide,subtitle_text,content_items[i:i+12],style) i +=12 if i< len(content_items): slide = create_content_blank_slide(prs,title_text,subtitle_text,style) else: break return slide #引用提示的布局,这个需要单独处理,引用的矩形框 def layout_blockquote_code(prs,slide,title_text,subtitle_text,content_items,mc,style): """文字列表布局""" # 起始未知 left_text = Cm(2) top_text = Cm(4) width_text = Cm(36) height_text = Cm(2) ol_li = 1 if "ol" in style: ol_li = style["ol"] for i,item in enumerate(content_items): left_text_0 = left_text width_text_0 = width_text height_text_0 = height_text if top_text+i*height_text > Cm(20): #还有内容,则放到一页处理 #print(len(content_items[i:]),content_items[i:]) style["ol"] = ol_li create_content_slide(prs,title_text, subtitle_text,content_items[i:],style) break if item.get("blockquote",False): left_text_0 = left_text+Cm(4.5) width_text_0 = width_text-Cm(6) # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text_0-Cm(0.5), top_text+i*height_text, Cm(0.5), height_text+Cm(0.5) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text_0, top_text+i*height_text, width_text_0, height_text+Cm(0.5) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) #代码框 if item.get("code",False): left_text_0 = left_text+Cm(4.5) width_text_0 = width_text-Cm(6) height_text_0 = Cm(12) # 灰色标题框 shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text_0, top_text+i*height_text, width_text_0, height_text_0 ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() #fill.fore_color.rgb = RGBColor(192, 192, 192) # 浅灰色填充 fill.fore_color.rgb = RGBColor(245, 245, 245) # 浅灰色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line #line.color.rgb = RGBColor(192, 192, 192) # 浅灰色填充 line.color.rgb = RGBColor(245, 245, 245) # 浅灰色填充 line.width = Pt(1) #文字内容 text_box = slide.shapes.add_textbox(left_text_0, top_text+i*height_text, width_text_0, height_text_0) tf = text_box.text_frame # 启用自动换行 tf_clean_all(tf) tf.word_wrap = True if item.get("level", 0)==1: ol_li = 1 p = tf.add_paragraph() p.font.name="微软雅黑" p.font.size = Pt(item.get("size", 18)) #默认黑色 p.font.color.rgb = RGBColor(0, 0, 0) p.space_after = Pt(item.get("space_after", 8)) p.level = item.get("level", 0) if p.level==3: p.font.color.rgb = RGBColor(102, 102, 102) #浅灰色 ol_li = output_text_style(p,item,RGBColor(mc[0],mc[1],mc[2]),ol_li) #下方保持点距离 if item.get("blockquote",False): top_text +=Cm(1) if item.get("code",False): top_text +=Cm(13) #按照段落的样式进行输出 def output_text_style(p,item,color,index=0): if item.get("number", False): run2 = p.add_run() run2.text = f'{index:02d}. ' font2 = run2.font font2.color.rgb = color font2.size = Pt(18) run3 = p.add_run() run3.text = item["text"] index += 1 elif item.get("bullet", False): run2 = p.add_run() run2.text = "• " font2 = run2.font font2.color.rgb = color font2.size = Pt(18) run3 = p.add_run() run3.text = item["text"] else: p.text = item["text"] #普通 if item.get("bold", False):#粗体 p.font.bold = True return index def layout_normal(slide,subtitle_text,content_items,style): """文字列表布局""" mc = style["main_color"] # 添加内容文字 left_text = Cm(2) top_text = Cm(4.5 if subtitle_text else 3.5) width_text = Cm(36) height_text = Cm(8) text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True tf.clear() ol_li = 1 if "ol" in style: ol_li = style["ol"] for item in content_items: if item.get("level", 0)==1: ol_li = 1 p = tf.add_paragraph() p.font.name="微软雅黑" p.font.size = Pt(item.get("size", 18)) #默认黑色 p.font.color.rgb = RGBColor(0, 0, 0) p.space_after = Pt(item.get("space_after", 8)) p.level = item.get("level", 0) if p.level==3: p.font.color.rgb = RGBColor(102, 102, 102) #浅灰色 ol_li = output_text_style(p,item,RGBColor(mc[0],mc[1],mc[2]),ol_li) style["ol"] = ol_li def create_table_slide(prs, title_text, subtitle_text, headers, data,content,style=None): """创建带表格的数据页""" slide = create_content_slide(prs, title_text, subtitle_text,None,style) mc = style["main_color"] if len(content) >5: #新的一页单独放表格 slide = create_content_slide(prs, title_text, subtitle_text,None,style) else: if len(content)>=1: #直接在表格旁做个sumari的总结 # 添加内容位置 left_text = Cm(30) top_text = Cm(5.5 if subtitle_text else 4.5) width_text = Cm(10) height_text = Cm(14) # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text, width_text, Cm(0.7) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text+Cm(0.7), width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill #fill.solid() #fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 fill.background() # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加内容文字 text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True tf.clear() ol_li = 1 for item in content: p = tf.add_paragraph() p.font.size = Pt(item.get("size", 18)) p.font.color.rgb = RGBColor(0, 0, 0) #p.space_after = Pt(item.get("space_after", 8)) #p.level = item.get("level", 0) ol_li = output_text_style(p,item,RGBColor(mc[0],mc[1],mc[2]),ol_li) # 计算表格位置和大小 left = Cm(2) top = Cm(4 if len(content) >3 else 8) #内容多就新的一页 width = Cm(26.5) height = Cm(12 if len(data) >10 else 8) #表格数据比较多 # 创建表格 (行数=数据行数+1,列数=标题数) if not data[0]: #为空 data=data[1:] #去掉第一行的空行 if headers == data[0]: # 和表头相同 data=data[1:] #去掉第一行的空行 rows = len(data) + 1 cols = len(headers) shape = slide.shapes.add_table(rows, cols, left, top, width, height) table = shape.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(mc[0],mc[1],mc[2]) # 主色填充 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(245, 245, 245) #浅灰色 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.LEFT # #边框线(赞不支持) # for border_side in ["top", "bottom", "left", "right"]: # border = getattr(cell, f"{border_side}_border") # border.fill.background() # 清除任何填充色,确保只应用线条样式 # border.color.rgb = RGBColor(0, 64, 128) # border.size = Cm(0.1) # 设置表格边框 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 #设置表格动画 # if content: # # 获取表格的 XML 元素 # graphic_frame = shape._element # # 创建飞入动画(从左侧进入的路径动画) # anim = OxmlElement("p:anim") # anim.set("xmlns:p", "http://schemas.openxmlformats.org/presentationml/2006/main") # anim.set("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main") # anim.set("type", "entr") # 进入动画类型 # anim.set("effect", "flyIn") # 飞入效果 # anim.set("from", "left") # 从左侧进入 # # 设置动画参数(可选) # anim_motion = OxmlElement("p:animMotion") # anim_motion.set("path", "M 0 0 L 0.5 0") # 路径参数(水平移动) # anim_motion.set("origin", "layout") # anim.append(anim_motion) # # 设置触发方式(单击时触发) # anim.set("trigger", "onClick") # # 附加动画到表格对象 # graphic_frame.append(anim) return slide def create_chart_slide(prs, title_text, subtitle_text, chart_type, data,style): """创建图表的数据页""" slide = create_content_slide(prs, title_text, subtitle_text,None,style) #半透明白色背景 left_content = Cm(2) top_content = Cm(7 if subtitle_text else 6) # 根据是否有二级标题调整位置 width_content = Cm(28.5) height_content = Cm(15 if len(data) >10 else 12 ) content_box = slide.shapes.add_shape( MSO_SHAPE.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) # 和前端颜色一致 colors = [ "#FF6384", # 对应 rgba(255,99,132,1) "#36A2EB", # 对应 rgba(54, 162, 235, 1) "#FFCE56", # 对应 rgba(255, 206, 86, 1) "#4BC0C0", # 对应 rgba(75, 192, 192, 1) "#9966FF", # 对应 rgba(153, 102, 255, 1) "#FF9F40", # 对应 rgba(255, 159, 64, 1) "#FF6347", # 新增:对应 rgba(255, 99, 71, 1),番茄红 "#90EE90", # 新增:对应 rgba(144, 238, 144, 1),淡绿 "#ADD8E6", # 新增:对应 rgba(173, 216, 230, 1),浅天蓝 "#FFC0CB" # 新增:对应 rgba(255, 192, 203, 1),浅粉 ] # 添加图表数据 if data: chart_data = ChartData() chart_data.categories = data["categories"] del data["categories"] for lable, series in data.items(): chart_data.add_series(lable, series) # 添加图表 left_chart = Cm(3) top_chart = Cm(8) width_chart = Cm(25) height_chart = Cm(12 if len(data) >10 else 10 ) if chart_type=="[chart][bar]": xl_chart_type=XL_CHART_TYPE.COLUMN_CLUSTERED elif chart_type=="[chart][line]": xl_chart_type=XL_CHART_TYPE.LINE elif chart_type=="[chart][bar_line]": xl_chart_type=XL_CHART_TYPE.BAR_CLUSTERED elif chart_type=="[chart][area]": xl_chart_type=XL_CHART_TYPE.AREA else: xl_chart_type=XL_CHART_TYPE.BAR_STACKED chart = slide.shapes.add_chart( xl_chart_type,left_chart, top_chart, width_chart, height_chart, chart_data ) # 设置数据标签 plot = chart.chart.plots[0] plot.has_data_labels = True data_labels = plot.data_labels data_labels.show_value = True # 显示数值 data_labels.position = XL_LABEL_POSITION.OUTSIDE_END # 标签位置 # 设置数据标签的字体大小 data_labels.font.size = Pt(6) # 假设你想要设置字体大小为12磅 # 设置图例 chart.chart.has_legend = True # 确保图例可见 chart.chart.legend.position = XL_LEGEND_POSITION.BOTTOM # 设置图例位置为底部 chart.chart.legend.include_in_layout = False # 不让图例覆盖图表 # 设置图表颜色 if len(chart.chart.series) ==1: #只有一个series for idx, point in enumerate(chart.chart.series[0].points): if idx < len(colors): # 确保颜色数量足够 fill = point.format.fill fill.solid() fill.fore_color.alpha = 0.2 # 20%透明度 fill.fore_color.rgb = RGBColor.from_string(colors[idx][1:]) else: data_labels.show_value = False # 显示数值 data_labels.position = XL_LABEL_POSITION.OUTSIDE_END # 标签位置 #设置图表颜色 - 为每个系列分配一种颜色 for idx, serie in enumerate(chart.chart.series): if idx < len(colors): # 确保颜色数量足够 fill = serie.format.fill fill.solid() fill.fore_color.rgb = RGBColor.from_string(colors[idx][1:]) # 移除前缀'#' # # 设置图表颜色以匹配主题 # 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 tf_clean_all(tf): for para in list(tf.paragraphs): tf._element.remove(para._element) def create_image_layout_slide(prs, title_text, subtitle_text, images,content_items=None,style=None): """创建图片布局页面""" slide = create_content_slide(prs, title_text, subtitle_text,None,style) mc = style["main_color"] # 清除默认内容区域 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)+Cm(0.5) width = Cm(26) height = Cm(15) pic = slide.shapes.add_picture(images[0]["path"], left, top, width, height) # 添加图片说明 if "caption" in images[0]: left_cap = Cm(3) top_cap = Cm(20 if subtitle_text else 19) 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() if images[0]["caption"]: p.text = images[0]["caption"] else: p.text = "主图" p.font.size = Pt(18) p.font.color.rgb = RGBColor(mc[0],mc[1],mc[2]) p.alignment = PP_ALIGN.CENTER # 在图片的右侧添加内容区域,可以多级列表 if content_items: # 添加内容位置 left_text = Cm(30) top_text = Cm(5.5 if subtitle_text else 4.5) width_text = Cm(10) height_text = Cm(14) # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text, width_text, Cm(0.7) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text+Cm(0.7), width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill # fill.solid() # fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 fill.background() # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 添加内容文字 text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True tf.clear() ol_li = 1 for item in content_items: p = tf.add_paragraph() p.font.size = Pt(item.get("size", 18)) p.font.color.rgb = RGBColor(0, 0, 0) #p.space_after = Pt(item.get("space_after", 8)) #p.level = item.get("level", 0) ol_li = output_text_style(p,item,RGBColor(mc[0],mc[1],mc[2]),ol_li) elif len(images) == 2: # 两张图片并排布局 # 第一张图片 left1 = Cm(2) top1 = Cm(5 if subtitle_text else 4)+Cm(0.5) width1 = Cm(13) height1 = Cm(15) pic1 = slide.shapes.add_picture(images[0]["path"], left1, top1, width1, height1) # 第二张图片 left2 = Cm(16) top2 = Cm(5 if subtitle_text else 4)+Cm(0.5) width2 = Cm(13) height2 = Cm(15) 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 19) top_cap = Cm(20 if subtitle_text else 19) 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() if img["caption"]: p.text = img["caption"] else: p.text = f"图片{i+1}" p.font.size = Pt(12) p.font.color.rgb = RGBColor(mc[0],mc[1],mc[2]) p.alignment = PP_ALIGN.CENTER # 在图片的右侧添加内容区域,可以多级列表 if content_items: # 添加内容文字 left_text = Cm(30) top_text = Cm(5.5 if subtitle_text else 4.5) width_text = Cm(10) height_text = Cm(14) # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text, width_text, Cm(0.7) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text+Cm(0.7), width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill # fill.solid() # fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 fill.background() # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True tf.clear() ol_li = 1 for item in content_items: p = tf.add_paragraph() p.font.size = Pt(item.get("size", 18)) p.font.color.rgb = RGBColor(0, 0, 0) #p.space_after = Pt(item.get("space_after", 8)) #p.level = item.get("level", 0) ol_li = output_text_style(p,item,RGBColor(mc[0],mc[1],mc[2]),ol_li) elif len(images) >= 3: # 三张级以上图片网格布局 #仅三张图片的相关配置和内容布局 if len(images)==3: #图变大 img_size = Cm(12) #位置下移 top = Cm(8 if subtitle_text else 7) # 在图片的上方添加内容区域,可以多级列表 if content_items: # 添加内容 left_text = Cm(3) top_text = Cm(4) width_text = Cm(36) height_text = Cm(3.5) # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text-Cm(0.5), top_text, Cm(0.5), height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text, width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill # fill.solid() # fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 fill.background() # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) #添加内容文字 text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True #tf.clear() # 删除所有段落 tf_clean_all(tf) ol_li = 1 for item in content_items: p = tf.add_paragraph() p.font.size = Pt(item.get("size", 18)) p.font.color.rgb = RGBColor(0, 0, 0) #p.space_after = Pt(item.get("space_after", 8)) #p.level = item.get("level", 0) ol_li = output_text_style(p,item,RGBColor(mc[0],mc[1],mc[2]),ol_li) else: #图变小 img_size = Cm(8) #位置考上 top = Cm(5 if subtitle_text else 4)+Cm(0.5) #内容在右侧 # 在图片的右侧添加内容区域,可以多级列表 if content_items: # 添加内容文字 left_text = Cm(30) top_text = Cm(5.5 if subtitle_text else 4.5) width_text = Cm(10) height_text = Cm(16) # 先添加矩形标题框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text-Cm(0.7), width_text, Cm(0.7) ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) # 先添加矩形框(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left_text, top_text, width_text, height_text ) # 获取矩形的填充对象并设置为白色 fill = shape.fill # fill.solid() # fill.fore_color.rgb = RGBColor(255,255,255) # 白色填充 fill.background() # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(mc[0],mc[1],mc[2]) # 主色填充 line.width = Pt(1) text_box = slide.shapes.add_textbox(left_text, top_text, width_text, height_text) tf = text_box.text_frame # 启用自动换行 tf.word_wrap = True tf.clear() ol_li = 1 for item in content_items: p = tf.add_paragraph() p.font.size = Pt(item.get("size", 18)) p.font.color.rgb = RGBColor(0, 0, 0) #p.space_after = Pt(item.get("space_after", 8)) #p.level = item.get("level", 0) ol_li = output_text_style(p,item,RGBColor(mc[0],mc[1],mc[2]),ol_li) gap = Cm(1) #开始画图 # 第一行 for i in range(min(3, len(images))): left = Cm(2) + (img_size + gap) * i 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() if images[i]["caption"]: p.text = images[i]["caption"] else: p.text = f"图片{i+1}" p.font.size = Pt(12) p.font.color.rgb = RGBColor(mc[0],mc[1],mc[2]) 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] and images[i]["caption"]: 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(12) p.font.color.rgb = RGBColor(mc[0],mc[1],mc[2]) p.alignment = PP_ALIGN.CENTER return slide # ===== 封面幻灯片 ===== def create_main_slide(prs, title_text, subject_text,content=None,style={}): # ===== 封面幻灯片 ===== slide_layout = prs.slide_layouts[6] # 空白布局 slide = prs.slides.add_slide(slide_layout) apply_gradient_background(prs,slide,style) #主图 image_path = "pic/101_main.png" # 将图片添加到幻灯片中 left = top = 0 pic = slide.shapes.add_picture(image_path, left, top) # 获取幻灯片尺寸 slide_width = prs.slide_width slide_height = prs.slide_height # 调整图片大小以填充整个幻灯片 pic.width = slide_width pic.height = slide_height #添加宽屏主题 left = Cm(2) top = Cm(5) width = Cm(36) height = Cm(6) subtitle_box = slide.shapes.add_textbox(left, top, width, height) tf = subtitle_box.text_frame tf.word_wrap = True p = tf.add_paragraph() #粗体 p.font.bold = True p.text = title_text p.font.name="微软雅黑" p.font.size = Pt(66) p.font.color.rgb = RGBColor(255, 255, 255) p.alignment = PP_ALIGN.LEFT top = Cm(8.5) if len(title_text)>15: top = Cm(11) # 添加副标题 if subject_text: left = Cm(2) width = Cm(36) height = Cm(4) title_box = slide.shapes.add_textbox(left, top, width, height) tf = title_box.text_frame tf.word_wrap = True p = tf.add_paragraph() p.text = subject_text p.font.name="微软雅黑" #非粗体 p.font.bold = False p.font.size = Pt(34) p.font.color.rgb = RGBColor(255, 255, 255) p.alignment = PP_ALIGN.LEFT top +=Cm(1) #白色分割线 left = Cm(2.5) top = top+Cm(2) width = Cm(3) height = Cm(0.5) # 添加矩形形状(使用矩形形状 MSO_SHAPE.RECTANGLE) shape = slide.shapes.add_shape( MSO_SHAPE.RECTANGLE, left, top, width, height ) # 获取矩形的填充对象并设置为白色 fill = shape.fill fill.solid() fill.fore_color.rgb = RGBColor(255, 255, 255) # 白色填充 # 获取矩形的轮廓(边框)并可选地设置颜色或隐藏 line = shape.line line.color.rgb = RGBColor(255, 255, 255) # 默认黑色边框 line.width = Pt(1) # 边框宽度为 1 磅 top_begin=top # 添加其它标题或内容 if content: for i, line in enumerate(content): left = Cm(2) top = top_begin+Cm(1)*i width = Cm(36) height = Cm(4) subtitle_box = slide.shapes.add_textbox(left, top, width, height) tf = subtitle_box.text_frame #换行 tf.word_wrap = True p = tf.add_paragraph() p.font.name="微软雅黑" p.text = line["text"] p.font.size = Pt(20) p.font.color.rgb = RGBColor(255, 255, 255) p.alignment = PP_ALIGN.LEFT #end # ===== 目录幻灯片 ===== def create_catalog_slide(prs,catalogs,main_color,style): slide_layout = prs.slide_layouts[6] # 空白布局 slide = prs.slides.add_slide(slide_layout) apply_gradient_background(prs,slide,style) #背景图 image_path = "pic/101_catalog.png" # 将图片添加到幻灯片中 left =0 top = 0 pic = slide.shapes.add_picture(image_path, left, top) # 获取幻灯片尺寸 slide_width = prs.slide_width slide_height = prs.slide_height # 调整图片大小以填充整个幻灯片 pic.width = Cm(12) pic.height = slide_height if len(catalogs) <=8: start = Cm(2) line_h = Cm(2.5) height = Cm(2) else: start = Cm(1) line_h = Cm(1.5) height = Cm(1.5) # 添加目录 for i,catalog in enumerate(catalogs): top = start + line_h*i left = Cm(16) width = Cm(24) title_box = slide.shapes.add_textbox(left, top, width, height) tf = title_box.text_frame tf.word_wrap = True tf.clear() #一段的第一行 p = tf.add_paragraph() #前面部分 run1 = p.add_run() run1.text = f"{i+1:02d}" run1.font.name="微软雅黑" run1.font.size = Pt(32) run1.font.color.rgb = RGBColor(main_color[0],main_color[1],main_color[2]) run1.font.bold = True run2 = p.add_run() run2.text = " "+catalog run2.font.name="微软雅黑" run2.font.size = Pt(22) run2.font.color.rgb = RGBColor(0, 0, 0) run2.font.bold = True # 目录装饰字样 left = Cm(0.5) top = Cm(0.5) width = Cm(8) height = Cm(15) contact_box = slide.shapes.add_textbox(left, top, width, height) tf = contact_box.text_frame p = tf.add_paragraph() p.text = "content\n目录" p.font.name="微软雅黑" p.font.size = Pt(60) p.font.color.rgb = RGBColor(255, 255, 255) p.font.bold = True p.alignment = PP_ALIGN.LEFT p.space_after = Pt(16) # ===== 引导幻灯片 ===== def create_guide_slide(prs,title,guide,style): slide_layout = prs.slide_layouts[6] # 空白布局 slide = prs.slides.add_slide(slide_layout) apply_gradient_background(prs,slide,style) #背景图 image_path = "pic/101_catalog_w.png" # 将图片添加到幻灯片中 left =0 top = Cm(6) pic = slide.shapes.add_picture(image_path, left, top) # 获取幻灯片尺寸 slide_width = prs.slide_width slide_height = prs.slide_height # 调整图片大小以填充整个幻灯片 pic.width = slide_width pic.height = Cm(10) # 序号 left = Cm(2) top = Cm(6) width = Cm(16) height = Cm(10) contact_box = slide.shapes.add_textbox(left, top, width, height) tf = contact_box.text_frame p = tf.add_paragraph() p.text = guide p.font.name="微软雅黑" p.font.size = Pt(240) p.font.color.rgb = RGBColor(255, 255, 255) p.font.bold = True p.alignment = PP_ALIGN.CENTER p.space_after = Pt(16) # 添加副标题 left = Cm(18) top = Cm(12) if len(title) <10 else Cm(10) width = Cm(22) height = Cm(4) title_box = slide.shapes.add_textbox(left, top, width, height) tf = title_box.text_frame tf.word_wrap = True tf.clear() p = tf.add_paragraph() p.text = title p.font.name="微软雅黑" p.font.size = Pt(60) if len(title) >10: p.font.size = Pt(50) if len(title) >20: p.font.size = Pt(40) if len(title) >30: p.font.size = Pt(26) p.font.color.rgb = RGBColor(255, 255, 255) p.font.bold = True # ===== 结束幻灯片 ===== def create_end_slide(prs,style): slide_layout = prs.slide_layouts[6] # 空白布局 slide = prs.slides.add_slide(slide_layout) apply_gradient_background(prs,slide,style) #背景图 image_path = "pic/101_main.png" # 将图片添加到幻灯片中 left = top = 0 pic = slide.shapes.add_picture(image_path, left, top) # 获取幻灯片尺寸 slide_width = prs.slide_width slide_height = prs.slide_height # 调整图片大小以填充整个幻灯片 pic.width = slide_width pic.height = slide_height # 添加主标题 left = Cm(prs.slide_width/Cm(1)/2-5) top = Cm(15) width = Cm(30) height = Cm(2) title_box = slide.shapes.add_textbox(left, top, width, height) tf = title_box.text_frame tf.word_wrap = True tf.clear() p = tf.add_paragraph() p.text = "欢迎指正,感谢聆听!" p.font.name="微软雅黑" p.font.size = Pt(36) p.font.color.rgb = RGBColor(255, 255, 255) p.font.bold = True #产品logo img_width = Cm(8) img_height = Cm(4) print(prs.slide_width,prs.slide_width/Cm(1),prs.slide_width/Cm(1)/2-3) left = Cm(prs.slide_width/Cm(1)/2-4) #屏幕中央 top = Cm(6) #添加logo if gcfg["fs"]["logo"]!="": pic = slide.shapes.add_picture(f'{gcfg["fs"]["path"]}/img/{gcfg["fs"]["logo"]}', left, top, img_width, img_height) else: pic = slide.shapes.add_picture(f'ui/images/logo2.jpg', left, top, img_width, img_height) # 在内容区域添加slogan和网址 left = Cm(12) top = Cm(11) 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 = gcfg["fs"]["slogan"] p.font.size = Pt(28) 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 = gcfg["fs"]["url"] p.font.size = Pt(18) p.font.color.rgb = RGBColor(200, 230, 255) p.alignment = PP_ALIGN.CENTER p.space_before = Pt(10) #入口函数,根据html创建ppt def create_unified_ppt(html,output_filename,style): # 创建一个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的高度 ppt = parse_html_to_ppt(html) for slide in ppt: print(slide) if slide["type"]=="main": create_main_slide(prs,slide["title"],slide["subtitle"],slide["content"],style) elif slide["type"]=="text": create_content_slide( prs,slide["title"],slide["subtitle"],slide["content"],style ) elif slide["type"]=="image": create_image_layout_slide( prs,slide["title"],slide["subtitle"],slide["images"],slide["content"],style ) elif slide["type"]=="chart": create_chart_slide( prs,slide["title"],slide["subtitle"],slide["chart_type"],slide["data"],style ) elif slide["type"]=="table": create_table_slide( prs,slide["title"],slide["subtitle"],slide["header"],slide["data"],slide["content"],style ) elif slide["type"]=="guide": create_guide_slide( prs,slide["title"],slide["guide"],style ) elif slide["type"]=="catalog": create_catalog_slide( prs,slide["data"],style["main_color"],style ) else: pass create_end_slide(prs,style) # 保存演示文稿 prs.save(output_filename) if __name__ == "__main__": html_string ="""

K3GPT数据分析智能体

三国工资表分析

制作日期: 2024-12-24

要求

按如下分析三国详情:1不同集团的人数,2不同集团不同级别的人数,3不同集团的平均服务年龄,4不同集团工种帝王人数

数据分析

集团分布

[chart][bar]

{\"categories\":[\"魏\",\"吴\",\"无\",\"蜀\"],\"count\":[3,3,3,2]}

集团->职级的分布

[chart][bar]

{\"L4\":[10,9,7,1],\"L3\":[8,0,4,1],\"L5\":[6,9,6,3],\"L6\":[4,5,3,2],\"L7\":[3,4,3,2],\"L8\":[2,2,2,0],\"L9\":[1,1,1,0],\"L2\":[0,0,1,0],\"categories\":[\"吴\",\"魏\",\"蜀\",\"无\"]}

不同集团对应的司龄(年)的常见六指标分析

[chart][bar]

{\"categories\":[\"蜀\",\"魏\",\"无\",\"吴\"],\"总和\":[397,586,179,560],\"平均值\":[14.703703703703704,19.533333333333335,19.88888888888889,16.470588235294116],\"中位数\":[12,19,20,15],\"最小值\":[5,10,8,5],\"最大值\":[40,35,30,40],\"个数\":[27,30,9,34]}

表格1

序号姓名集团工种职级工资(万)司龄(年)
1曹操帝王L91030
2刘备帝王L99.825
3孙权帝王L99.540
53孙策帝王L8810
54孙坚帝王L7715
55刘禅帝王L7640
56曹丕帝王L88.515
57曹叡帝王L7710
97袁绍帝王L7620
98袁术帝王L6515
100刘表帝王L64.525

小结

根据分析结果,三国工资表的详细情况如下:

  1. 集团人数分布 吴国:34人 魏国:30人 蜀国:27人 无集团:9人
  2. 集团-职级人数分布 吴国主要职级为L4(10人)、L3(8人)、L5(6人) 魏国最高职级达L9(1人),L5(9人)占比较大 蜀国职级分布较均衡,L4(7人)、L5(6人)为主
  3. 平均服务年龄 魏国平均19.53年(最高) 吴国16.47年 蜀国14.70年(最低) 无集团19.89年(可能包含临时人员)
  4. 帝王工种分布 吴国、魏国、无集团各有3名帝王,蜀国2名 帝王多集中在高级职级(L6-L9)

分析点评:  

", """ #自定义的目录和引导 html_string2 ="""

K3GPT数据分析智能体

三国工资表分析

制作日期: 2024-12-24

[catalogs]

["要求","数据分析","结论"]

要求

要求

按如下分析三国详情:1不同集团的人数,2不同集团不同级别的人数,3不同集团的平均服务年龄,4不同集团工种帝王人数
数据分析过程

数据分析

集团分布

[chart][bar]

{\"categories\":[\"魏\",\"吴\",\"无\",\"蜀\"],\"count\":[3,3,3,2]}

集团->职级的分布

[chart][bar]

{\"L4\":[10,9,7,1],\"L3\":[8,0,4,1],\"L5\":[6,9,6,3],\"L6\":[4,5,3,2],\"L7\":[3,4,3,2],\"L8\":[2,2,2,0],\"L9\":[1,1,1,0],\"L2\":[0,0,1,0],\"categories\":[\"吴\",\"魏\",\"蜀\",\"无\"]}

不同集团对应的司龄(年)的常见六指标分析

[chart][bar]

{\"categories\":[\"蜀\",\"魏\",\"无\",\"吴\"],\"总和\":[397,586,179,560],\"平均值\":[14.703703703703704,19.533333333333335,19.88888888888889,16.470588235294116],\"中位数\":[12,19,20,15],\"最小值\":[5,10,8,5],\"最大值\":[40,35,30,40],\"个数\":[27,30,9,34]}

表格1

序号姓名集团工种职级工资(万)司龄(年)
1曹操帝王L91030
2刘备帝王L99.825
3孙权帝王L99.540
53孙策帝王L8810
54孙坚帝王L7715
55刘禅帝王L7640
56曹丕帝王L88.515
57曹叡帝王L7710
97袁绍帝王L7620
98袁术帝王L6515
100刘表帝王L64.525
结论

小结

根据分析结果,三国工资表的详细情况如下:

  1. 集团人数分布 吴国:34人 魏国:30人 蜀国:27人 无集团:9人
  2. 集团-职级人数分布 吴国主要职级为L4(10人)、L3(8人)、L5(6人) 魏国最高职级达L9(1人),L5(9人)占比较大 蜀国职级分布较均衡,L4(7人)、L5(6人)为主
  3. 平均服务年龄 魏国平均19.53年(最高) 吴国16.47年 蜀国14.70年(最低) 无集团19.89年(可能包含临时人员)
  4. 帝王工种分布 吴国、魏国、无集团各有3名帝王,蜀国2名 帝王多集中在高级职级(L6-L9)

分析点评:  

", """ # 使用前请替换示例图片路径为实际图片路径 create_unified_ppt(html_string2,"test2.pptx") print("带生成完成!")