diff --git a/main/make_ppt2.py b/main/make_ppt2.py new file mode 100644 index 0000000..e0163c8 --- /dev/null +++ b/main/make_ppt2.py @@ -0,0 +1,2788 @@ +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("带生成完成!")