Files
k3GPT/main/make_ppt2.py
2025-11-19 19:42:58 +08:00

2789 lines
110 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 ="""
<h1>K3GPT数据分析智能体</h1>
<h3>三国工资表分析</h3>
<p>制作日期: 2024-12-24</p>
<h2>要求</h2><h5>按如下分析三国详情1不同集团的人数2不同集团不同级别的人数3不同集团的平均服务年龄4不同集团工种帝王人数</h5>
<h2>数据分析</h2><h3>集团分布</h3><p>[chart][bar]</p><pre><code >{\"categories\":[\"\",\"\",\"\",\"\"],\"count\":[3,3,3,2]}</code></pre>
<h3>集团-&gt;职级的分布</h3><p>[chart][bar]</p><pre><code >{\"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\":[\"\",\"\",\"\",\"\"]}</code></pre>
<h3>不同集团对应的司龄(年)的常见六指标分析</h3><p>[chart][bar]</p><pre><code >{\"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]}</code></pre>
<h3>表格1</h3><table style=\"width: auto;\"><tbody><tr><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">序号</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">姓名</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">集团</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">工种</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">职级</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">工资(万)</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">司龄(年)</th></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">1</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">曹操</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">魏</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L9</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">10</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">30</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">2</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">刘备</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">蜀</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L9</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">9.8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">25</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">3</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">孙权</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">吴</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L9</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">9.5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">40</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">53</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">孙策</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">吴</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">10</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">54</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">孙坚</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">吴</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">15</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">55</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">刘禅</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">蜀</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">40</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">56</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">曹丕</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">魏</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">8.5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">15</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">57</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">曹叡</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">魏</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">10</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">97</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">袁绍</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">无</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">20</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">98</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">袁术</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">无</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">15</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">100</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">刘表</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">无</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">4.5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">25</td></tr></tbody></table>
<h2>小结</h2><p>根据分析结果,三国工资表的详细情况如下:</p><ol><li>集团人数分布 吴国34人 魏国30人 蜀国27人 无集团9人</li><li>集团-职级人数分布 吴国主要职级为L410人、L38人、L56人 魏国最高职级达L91人L59人占比较大 蜀国职级分布较均衡L47人、L56人为主</li><li>平均服务年龄 魏国平均19.53年(最高) 吴国16.47年 蜀国14.70年(最低) 无集团19.89年(可能包含临时人员)</li><li>帝王工种分布 吴国、魏国、无集团各有3名帝王蜀国2名 帝王多集中在高级职级L6-L9</li></ol><p><strong>分析点评</strong> &nbsp;</p><ul><li>魏国和无集团的平均服务年龄显著高于其他集团,可能与人员稳定性或招聘策略有关。 &nbsp;</li><li>帝王工种在吴、魏、无集团分布较均但蜀国仅2人可能需关注其人才结构。 &nbsp;</li><li>职级分布显示魏国存在较高职级人员,而蜀国职级整体偏低,可能反映组织架构差异。</li></ul>",
"""
#自定义的目录和引导
html_string2 ="""
<h1>K3GPT数据分析智能体</h1>
<h3>三国工资表分析</h3>
<p>制作日期: 2024-12-24</p>
<p>[catalogs]<pre><code>["要求","数据分析","结论"]</code></pre></p>
<guide>要求</guide>
<h2>要求</h2><h5>按如下分析三国详情1不同集团的人数2不同集团不同级别的人数3不同集团的平均服务年龄4不同集团工种帝王人数</h5>
<guide>数据分析过程</guide>
<h2>数据分析</h2><h3>集团分布</h3><p>[chart][bar]</p><pre><code >{\"categories\":[\"\",\"\",\"\",\"\"],\"count\":[3,3,3,2]}</code></pre>
<h3>集团-&gt;职级的分布</h3><p>[chart][bar]</p><pre><code >{\"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\":[\"\",\"\",\"\",\"\"]}</code></pre>
<h3>不同集团对应的司龄(年)的常见六指标分析</h3><p>[chart][bar]</p><pre><code >{\"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]}</code></pre>
<h3>表格1</h3><table style=\"width: auto;\"><tbody><tr><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">序号</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">姓名</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">集团</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">工种</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">职级</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">工资(万)</th><th colSpan=\"1\" rowSpan=\"1\" width=\"auto\">司龄(年)</th></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">1</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">曹操</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">魏</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L9</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">10</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">30</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">2</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">刘备</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">蜀</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L9</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">9.8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">25</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">3</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">孙权</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">吴</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L9</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">9.5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">40</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">53</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">孙策</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">吴</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">10</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">54</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">孙坚</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">吴</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">15</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">55</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">刘禅</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">蜀</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">40</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">56</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">曹丕</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">魏</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L8</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">8.5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">15</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">57</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">曹叡</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">魏</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">10</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">97</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">袁绍</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">无</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L7</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">20</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">98</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">袁术</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">无</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">15</td></tr><tr><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">100</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">刘表</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">无</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">帝王</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">L6</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">4.5</td><td colSpan=\"1\" rowSpan=\"1\" width=\"auto\">25</td></tr></tbody></table>
<guide>结论</guide>
<h2>小结</h2><p>根据分析结果,三国工资表的详细情况如下:</p><ol><li>集团人数分布 吴国34人 魏国30人 蜀国27人 无集团9人</li><li>集团-职级人数分布 吴国主要职级为L410人、L38人、L56人 魏国最高职级达L91人L59人占比较大 蜀国职级分布较均衡L47人、L56人为主</li><li>平均服务年龄 魏国平均19.53年(最高) 吴国16.47年 蜀国14.70年(最低) 无集团19.89年(可能包含临时人员)</li><li>帝王工种分布 吴国、魏国、无集团各有3名帝王蜀国2名 帝王多集中在高级职级L6-L9</li></ol><p><strong>分析点评</strong> &nbsp;</p><ul><li>魏国和无集团的平均服务年龄显著高于其他集团,可能与人员稳定性或招聘策略有关。 &nbsp;</li><li>帝王工种在吴、魏、无集团分布较均但蜀国仅2人可能需关注其人才结构。 &nbsp;</li><li>职级分布显示魏国存在较高职级人员,而蜀国职级整体偏低,可能反映组织架构差异。</li></ul>",
"""
# 使用前请替换示例图片路径为实际图片路径
create_unified_ppt(html_string2,"test2.pptx")
print("带生成完成!")