from PIL import Image, ImageDraw, ImageFont
import os
from parse_html import parse_html_to_ppt,parse_html_to_poster



# 加载字体 - 使用系统路径
font_path_1 = "/usr/share/fonts/opentype/noto/NotoSansCJK-Thin.ttc"
font_path_2 = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
font_path_3 = "/usr/share/fonts/opentype/noto/NotoSansCJK-Black.ttc"
font_path_4 = "/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc"
try:
    title_font = ImageFont.truetype(font_path_3, 100)  # 粗体
    subtitle_font = ImageFont.truetype(font_path_1, 60)  # 细
    end_font = ImageFont.truetype(font_path_1, 50)  # 细

    section_font = ImageFont.truetype(font_path_2, 100)  # 粗体
    section_title_font = ImageFont.truetype(font_path_4, 40)  # 粗体
    section_subtitle_font = ImageFont.truetype(font_path_4, 60)  # 粗体
    content_bold_font = ImageFont.truetype(font_path_4, 35)  # 粗体
    keyword_font = ImageFont.truetype(font_path_2, 40)  # 中等

    content_font = ImageFont.truetype(font_path_2, 35)  # 中等
    footer_font = ImageFont.truetype(font_path_1, 35)  # 常规
except:
    raise Exception("缺少思源黑体字体文件")


#颜色组
card_bg_color = None

#颜色转换
def hex_to_rgb(hex_color):
    # 去掉可能的 '#' 字符
    hex_color = hex_color.lstrip('#')
    
    # 使用 int 和 base=16 将十六进制字符串转换为整数，然后用 ',' 分隔这些值，并创建一个元组
    rgb = tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
    
    return rgb

#获取相近色
def get_similar_hsv_color(rgb, dh=0.05, ds=0.1, dv=0.1):
    import colorsys
    r,g,b = rgb
    h, s, v = colorsys.rgb_to_hsv(r/255., g/255., b/255.)
    
    # 调整色调、饱和度和亮度
    h = (h + dh) % 1  # 循环
    s = max(0, min(1, s + ds))
    v = max(0, min(1, v + dv))
    
    r_new, g_new, b_new = [int(x*255) for x in colorsys.hsv_to_rgb(h, s, v)]
    return (r_new, g_new, b_new)


import re

def is_english_alpha(s):
    return bool(re.fullmatch(r'[A-Za-z]+', s))

#处理多行文本
def draw_multiline_text(draw, text, position, max_width, font, fill, line_spacing=10, only_calc=False):
    """
    在指定区域内绘制自动换行的文本
    
    参数:
    draw - ImageDraw对象
    text - 要绘制的文本
    position - 起始位置 (x, y)
    max_width - 最大行宽
    font - 字体对象
    fill - 文本颜色
    line_spacing - 行间距 (默认10)
    """
    x, y = position
    lines = []

    
    # 如果文本包含换行符，先按换行符分割
    paragraphs = text.split('\n')
    
    for paragraph in paragraphs:
        words = []
        # 中英文混合处理：将每个字符视为独立的"词"
        for char in paragraph:
            if char !='\n' and  char !='\r' and char !="\xa0" and not char.isspace():
                words.append(char)
            # # 添加空格字符作为可能的断点
            # if char.isspace():
            #     words.append('')
        
        space_width = draw.textlength(' ', font=font)
        current_line = []
        current_width = 0
        
        for i,word in enumerate(words):
            word_width = draw.textlength(word, font=font)
            #中文超宽符号的处理
            if word in ['“','”','《','》','『','』','·']:
                #print("中文",word,word_width)
                word_width += word_width
            elif word.islower() or word.isdigit(): #小写字母和数字要窄一点
                #print("字母数字",word,word_width)
                word_width -= word_width//5
            elif word=="-":
                word_width = word_width//2
            
            # 如果当前行宽度加上新词宽度超过最大宽度
            if int(current_width) + int(word_width) > int(max_width) and current_line:
                #print(''.join(current_line),int(current_width),int(word_width),int(max_width),word)
                #如果只剩下最后一个字，就放置在末尾
                if len(words) -i ==1:
                    current_line.append(word)
                    break
                # 将当前行添加到行列表
                lines.append(''.join(current_line))
                #下一行计数
                current_line = [word]
                current_width = word_width
            else:
                current_line.append(word)
                current_width += word_width
        
        # 添加最后一行
        if current_line:
            lines.append(''.join(current_line))
    
    # 计算行高
    _, _, _, line_height = font.getbbox("A")
    
    # 绘制每一行文本
    for line in lines:
        if not only_calc:
            draw.text((x, y), line, fill=fill, font=font)
        y += line_height + line_spacing
    
    return y

#绘制图片
def draw_image(path_data,image_width):
    # 如果有 data:image/...;base64, 前缀，需要去掉
    if path_data.startswith('data:image'):
        base64_str = path_data.split(',', 1)[1]  # 取逗号后面的部分

        import base64
        from io import BytesIO
        # 解码 Base64 为二进制
        image_data = base64.b64decode(base64_str)

        # 用 BytesIO 包装成“文件对象”
        image_file = BytesIO(image_data)
        content_img = Image.open(image_file)
    else:
        content_img = Image.open(path_data)

    # 获取原始尺寸
    original_width, original_height = content_img.size
    
    # 计算高度的比例
    width_ratio = image_width / original_width
    target_height = int(original_height * width_ratio)
    
    # 调整图像大小
    resized_img = content_img.resize((image_width, target_height), Image.Resampling.LANCZOS)
    return resized_img,target_height


#绘制表格
def draw_table(draw,data,table_top,table_left,table_width,header_font,data_font,text_color,header_color,tbc):
    if data is None: return table_top
    cell_height = 65  # 默认单元格高度

    headers=data[0]
    data=data[1:] #去掉第一行的空行

    rows = len(data)
    
    cols = len(headers)
    #table_height = cell_height * rows
    cell_width = table_width // cols

    # 绘制表头圆角矩形背景
    draw.rounded_rectangle(
        (table_left-10, table_top, table_left+table_width+10, table_top+cell_height+15),
        radius=40,
        fill=header_color,  # 深蓝色背景
        outline=header_color
    )

    # # 绘制表头分割线
    for i in range(1, cols):
        x = table_left + i * cell_width
        # 绘制垂直线条，稍微短一点以避开圆角
        draw.line(
            [(x, table_top + 10), (x, table_top + cell_height)],
            fill=(255, 255, 255, 180),  # 半透明白色
            width=2
        )
    

    for col in range(cols):
        text = headers[col]
        # 使用textbbox计算文本尺寸
        text_bbox = draw.textbbox((0, 0), text, font=header_font)
        text_width = text_bbox[2] - text_bbox[0]
        text_height = text_bbox[3] - text_bbox[1]
        
        x = table_left + col * cell_width + (cell_width - text_width) // 2
        y = table_top + (cell_height - text_height) // 2
        draw.text((x, y), text, fill=(255, 255, 230), font=header_font)

    #微调一下数据表格的大小和位置，下移15
    table_top +=15
    table_width = table_width - 40
    table_left +=20
    cell_width = table_width // cols

    # 绘制数据行的起始位置
    y = table_top + cell_height

    for row in range(rows):

        #计算最大行高
        max_y =  y +  cell_height
        for col in range(cols):
            text = data[row][col]
            y1 = draw_multiline_text(draw, text, (table_left,y), cell_width-20, data_font, text_color, line_spacing=10, only_calc=True)
            if y1>max_y:
                max_y=y1

        row_height = max_y - y

        for col in range(cols):
            # 计算单元格位置
            x1 = table_left + col * cell_width
            #y1 = table_top + (row + 1) * cell_height
            y1 = y
            x2 = x1 + cell_width
            y2 = y1 + row_height
            
            # 交替行颜色
            if row % 2 == 0:
                #bg_color = (248, 250, 253)  # 浅色行
                bg_color = (tbc[0],tbc[1],tbc[2],100)
            else:
                #bg_color = (240, 245, 251)  # 更浅的蓝色行
                bg_color = (tbc[0],tbc[1],tbc[2],200)
            
            # 绘制单元格背景
            draw.rectangle([x1, y1, x2, y2], fill=bg_color)
            
            # 添加数据
            text = data[row][col]

            draw_multiline_text(draw, text, (x1+15,y+10), cell_width-15, data_font, text_color, line_spacing=10, only_calc=False)
                        
            # # 使用textbbox计算文本尺寸
            # text_bbox = draw.textbbox((0, 0), text, font=data_font)
            # text_width = text_bbox[2] - text_bbox[0]
            # text_height = text_bbox[3] - text_bbox[1]
            
            # x = x1 + 15
            # # 默认y位置
            # y = y1 + (cell_height - text_height) // 2
            # draw.text((x, y), text, fill=text_color, font=data_font)

        #一行的横线
        y = max_y+10
        draw.line(
            [(table_left, y), (table_left+table_width, y)], 
            fill=(225, 232, 243), 
            width=1
        )
        y +=1 

    #表格高度
    table_height = y - table_top 
    
    # 固定高度的横线
    # for i in range(1, rows):
    #     y = table_top + i * cell_height
    #     draw.line(
    #         [(table_left, y), (table_left+table_width, y)], 
    #         fill=(225, 232, 243), 
    #         width=1
    #     )

    #竖线
    for i in range(1, cols):
        x = table_left + i * cell_width
        draw.line(
            [(x, table_top + cell_height), (x, table_top+table_height)], 
            fill=(225, 232, 243), 
            width=1
        )

    #表格边线，三条，,  # 深蓝色背景
    draw.line(
            [(table_left, table_top + cell_height-5), (table_left, table_top+table_height)], 
            fill=header_color, 
            width=2
        )
    draw.line(
            [(table_left+table_width, table_top + cell_height-5), (table_left+table_width, table_top+table_height)], 
            fill=header_color, 
            width=2
        )
    draw.line(
            [(table_left, table_top + table_height), (table_left+table_width, table_top+table_height)], 
            fill=header_color, 
            width=2
        )
    return table_top+table_height+20


# 辅助函数：获取文本尺寸
def get_text_size(draw,text, font):
    bbox = draw.textbbox((0, 0), text, font=font)
    return bbox[2] - bbox[0], bbox[3] - bbox[1]



#绘制头部样式1： 大logo+自动居中布局的标题
def draw_header_1(img,draw,poster_data,width,title_color,subtitle_color):
    # 1. 顶部标题区域,高度
    title = poster_data["主标"]
    subtitle = poster_data["副标"]
    
    #主标题和副标题的宽度
    title_w, title_h = get_text_size(draw,title, title_font)
    subtitle_w, subtitle_h = get_text_size(draw,subtitle, subtitle_font)


    # 复制logo
    logo_path = poster_data["logo_path"]  # logo图片路径
    logo = Image.open(logo_path)
    logo = logo.resize((400, 150), Image.Resampling.LANCZOS)  # 调整logo大小

    #标题很长，需要改变布局
    if title_w > width-450 or subtitle_w > width-450:
        #logo和标题上下布局

        # 这里位置是以左上角为起点的坐标(x, y)
        position = ((width - 400) // 2, 10)  # 上面居中的位置

        # 将logo复制到当前图像上
        # 使用Image.paste方法，注意如果你的logo有透明度，需要使用mask参数
        img.paste(logo, position, logo.convert('RGBA'))

        #主标
        draw.text(((width - title_w) // 2, 180), title, fill=title_color, font=title_font)

        draw.text(((width - subtitle_w) // 2, 180 + title_h + 30), 
                subtitle, fill=subtitle_color, font=subtitle_font)
        
        y = 180 + title_h + 30 + subtitle_h +60
    else:
        #logo和标题左右布局
        draw.text(((width - title_w) // 2+200, 50), title, fill=title_color, font=title_font)
        
        # 绘制副标题
        subtitle_w, subtitle_h = get_text_size(draw,subtitle, subtitle_font)
        draw.text(((width - subtitle_w) // 2+200, 50 + title_h + 30), 
                subtitle, fill=subtitle_color, font=subtitle_font)
        
        # 这里位置是以左上角为起点的坐标(x, y)
        position = (10, 10)  # 左上角的位置

        # 将logo复制到当前图像上
        # 使用Image.paste方法，注意如果你的logo有透明度，需要使用mask参数
        img.paste(logo, position, logo.convert('RGBA'))

        #固定值
        y=300

    # 装饰元素 - 金色圆点
    for i in range(5):
        x = width * (0.1 + 0.2 * i)
        size = 10 if i % 2 == 0 else 15
        draw.ellipse([(x, y),
                     (x+size, y + size)],
                    fill=title_color)

    return y



#绘制头部样式2： 小logo+ 标题居左
def draw_header_2(img,draw,poster_data,width,title_color,subtitle_color):
    # 1. 顶部标题区域,高度
    title = poster_data["主标"]
    subtitle = poster_data["副标"]
    
    #主标题和副标题的宽度
    title_w, title_h = get_text_size(draw,title, title_font)
    subtitle_w, subtitle_h = get_text_size(draw,subtitle, subtitle_font)

    # 复制logo
    image_width = 250 #总宽度的4分之一
    logo_path = poster_data["logo_path"]  # logo图片路径
    logo = Image.open(logo_path)

    # 获取原始尺寸
    original_width, original_height = logo.size
    
    # 计算高度的比例
    width_ratio = 250 / original_width
    target_height = int(original_height * width_ratio)
    
    # 调整图像大小
    logo = logo.resize((image_width, target_height), Image.Resampling.LANCZOS)
    #logo和标题上下布局

    # 这里位置是以左上角为起点的坐标(x, y)
    position = ((width - image_width)-50, 10)  # 右边的位置

    # 将logo复制到当前图像上
    # 使用Image.paste方法，注意如果你的logo有透明度，需要使用mask参数
    img.paste(logo, position, logo.convert('RGBA'))

    y = target_height +20

    #主标
    #draw.text((50, y), title, fill=title_color, font=title_font)

    y = draw_multiline_text(
                draw, 
                title,
                (50, y),
                width-100,
                title_font,
                title_color,
                line_spacing=15,
                only_calc = False
    )

    draw.text((50, y + 30), 
            subtitle, fill=subtitle_color, font=subtitle_font)
    
    y += 30 + subtitle_h +60
    
    draw.line(
            [(0, y), (width, y)], 
        
            fill = title_color,
            width=1
            )

    return y


#绘制头部样式2： 无logo+ 标题居左+ 日期
def draw_header_3(img,draw,poster_data,width,title_color,subtitle_color):
    # 1. 顶部标题区域,高度
    title = poster_data["主标"]
    subtitle = poster_data["副标"]


    from datetime import date

    # 获取当前日期
    current_date = date.today()
    # 如果需要将日期格式化为特定格式的字符串，可以使用 strftime 方法
    formatted_date = current_date.strftime("%Y-%m-%d")
    print("格式化后的日期:", formatted_date)
    
    #主标题和副标题的宽度
    date_w, date_h = get_text_size(draw,formatted_date, keyword_font)
    title_w, title_h = get_text_size(draw,title, title_font)
    subtitle_w, subtitle_h = get_text_size(draw,subtitle, subtitle_font)

    #日期
    y = 20

    #主标日期
    draw.text(((width-date_w)-40, y), formatted_date, fill=subtitle_color, font=keyword_font)

    y = 100
    #主标
    #draw.text((50, y), title, fill=title_color, font=title_font)

    y = draw_multiline_text(
                draw, 
                title,
                (50, y),
                width-100,
                title_font,
                title_color,
                line_spacing=15,
                only_calc = False
    )


    # 绘制矩形,副标题题点缀
    draw.rectangle([(50-10, y+15), (50+subtitle_w+10, y+subtitle_h+25)], 
                        fill=None,
                        outline=subtitle_color)

    draw.text((50, y), 
            subtitle, fill=subtitle_color, font=subtitle_font)
    
    y += subtitle_h +60
    
    draw.line(
            [(0, y), (width, y)], 
            fill = title_color,
            width=4
            )

    return y


"""
数字卡片，卡片没有标题，有数字，通过后面增加一个区域做标题汇总
"""
def draw_content_card_1(img,draw,poster_data,width,y_start,section_colors,card_bg_color,font_color):
        # 2. 内容区域 -多个内容块,流式布局按各自的内容大小来排
    section_y_start = y_start

    y = section_y_start #内容的绝对值是

    #内容    
    for i,slide in enumerate(poster_data["内容列表"]):

        # 计算位置,卡片的位置
        y_pos = y

        #卡片宽度
        card_width = width * 0.9
        card_x = int((width - card_width) / 2)

        #y从标题颜色后面开始测算
        y = y_pos + 50 

        #文字内容    
        if slide["content"]:
            y = draw_content_list(img,draw,slide,card_x,card_width,card_bg_color,font_color,section_colors,i,y,only_calc= True)
                
        # 卡片高度,保障一个最小值300的空间
        if y - y_pos < 150:
            y += 100

        #卡片高度
        card_height = y - y_pos+30
        # 创建圆角卡片
        card = Image.new('RGBA', (int(card_width), int(card_height)), (0, 0, 0, 0))
        card_draw = ImageDraw.Draw(card)
        
        # 圆角矩形填充
        card_draw.rounded_rectangle([(0, 0), (card_width, card_height)], 
                                   radius=40, fill=card_bg_color)
        
        # 抹去上面的圆角
        bar_height = 40
        card_draw.rectangle([(0, 0), (card_width, bar_height)], 
                           fill=card_bg_color)
        
        #添加色条
        bar_height = 20
        card_draw.rectangle([(0, 0), (card_width, bar_height)], 
                           fill=section_colors[i])
        
        # 添加装饰元素
        card_draw.ellipse([(card_width - 80, card_height - 80),
                         (card_width - 20, card_height - 20)], 
                        fill=(255, 255, 255, 30))
        
        # 粘贴卡片到海报
        img.paste(card, (int(card_x), int(y_pos)), card)
        
        # 数字标识
        num_text = str(i+1)
        num_w, num_h = get_text_size(draw,num_text, section_font)
        draw.text((card_x + 25, y_pos + 60), 
                num_text, fill=section_colors[i], font=section_font)
    
        #真正绘制内容
        y = y_pos + 50 

        #文字内容    
        if slide["content"]:
            y = draw_content_list(img,draw,slide,card_x,card_width,card_bg_color,font_color,section_colors,i,y,only_calc= False)

        
        # # 装饰元素 - 小圆点
        # for j in range(3):
        #     draw.ellipse([(card_x + card_width - 180 + j*40, y_pos + card_height/2 - 5),
        #                  (card_x + card_width - 160 + j*40, y_pos + card_height/2 + 15)], 
        #                 fill=section_colors[i])

        #下一个
        y = y_pos + card_height+60

    # 3. 底部关键字区域，和内容列表的主标对应
    keywords = [content["主标"] for content in poster_data["内容列表"]]
    keyword_y = y+10
    
    # 关键字容器
    container_height = 180
    container = Image.new('RGBA', (int(width*0.90), container_height), (0, 0, 0, 0))
    container_draw = ImageDraw.Draw(container)
    container_draw.rounded_rectangle([(0, 0), (width*0.90, container_height)], 
                                    radius=30, fill=card_bg_color)
    
    # 粘贴容器
    img.paste(container, (int(width*0.05), int(keyword_y)), container)
    
    keyword_w = int(width*0.90) // len(keywords)

    # 绘制关键字
    for idx, kw in enumerate(keywords):
        # 计算位置
        x_pos =  keyword_w //2  + keyword_w*idx + int(width*0.05)
        
        # 绘制图标背景
        icon_size = 50
        draw.ellipse([(x_pos - icon_size//2, keyword_y + 40),
                     (x_pos + icon_size//2, keyword_y + 40 + icon_size)], 
                    fill=section_colors[idx])
        
        # 绘制关键字文本
        kw_w, kw_h = get_text_size(draw,kw, keyword_font)
        draw.text((x_pos - kw_w//2, keyword_y + 100), 
                 kw, fill=font_color, font=keyword_font)

    return y+180


"""
带标题卡片，直接在卡片前放置标题
"""
def draw_content_card_2(img,draw,poster_data,width,y_start,section_colors,card_bg_color,font_color):
    # 2. 内容区域 -多个内容块,流式布局按各自的内容大小来排
    section_y_start = y_start

    #卡片宽度
    card_width = width * 0.9
    card_x = int((width - card_width) / 2)

    #内容
    y = section_y_start #内容的绝对值是
    for i,slide in enumerate(poster_data["内容列表"]):

        # 计算位置,卡片的位置
        y_pos = y

        #y从 主标
        y = y_pos + 80 + 30
       
        #文字内容    
        if slide["content"]:
            y = draw_content_list(img,draw,slide,card_x,card_width,card_bg_color,font_color,section_colors,i,y,only_calc= True)
                
        # 卡片高度,保障一个最小值300的空间
        if y - y_pos < 150:
            y += 100

        #卡片高度
        card_height = y - y_pos

        # 绘制主标,标题
        draw.rounded_rectangle([(card_x+card_width*0.055, y_pos), (card_x+card_width*0.95, y_pos+80)], 
                                   radius=40, fill=section_colors[i])
        
        num_w, num_h = get_text_size(draw,slide["主标"], section_title_font)
        draw.text((card_x + (card_width-num_w)//2, y_pos+5), 
                slide["主标"], fill=(255,255,255), font=section_title_font)

        # 创建圆角卡片
        card = Image.new('RGBA', (int(card_width), int(card_height)), (0, 0, 0, 0))
        card_draw = ImageDraw.Draw(card)
        
        # 圆角矩形填充
        card_draw.rounded_rectangle([(0, 0), (card_width, card_height)], 
                                   radius=40, fill=card_bg_color)
        
        # 抹去上面的圆角
        bar_height = 50
        card_draw.rectangle([(0, 0), (card_width, bar_height)], 
                           fill=card_bg_color)
        
        # 添加装饰元素
        card_draw.ellipse([(card_width - 80, card_height - 80),
                         (card_width - 20, card_height - 20)], 
                        fill=(255, 255, 255, 30))
        
        # 粘贴卡片到海报
        img.paste(card, (int(card_x), int(y_pos+100)), card)
        
        #真正绘制内容
        y = y_pos + 80 + 30

        #文字内容    
        if slide["content"]:
            y = draw_content_list(img,draw,slide,card_x,card_width,card_bg_color,font_color,section_colors,i,y,only_calc= False)

        
        
        #下一个
        y = y_pos +80+30+card_height+60

    return y




"""
彩色标签，直接在卡片前放置标题
"""
def draw_content_card_5(img,draw,poster_data,width,y_start,section_colors,card_bg_color,font_color):
    # 2. 内容区域 -多个内容块,流式布局按各自的内容大小来排
    section_y_start = y_start

    #卡片宽度
    card_width = width * 0.9
    card_x = int((width - card_width) / 2)

    #内容
    y = section_y_start #内容的绝对值是
    for i,slide in enumerate(poster_data["内容列表"]):

        # 计算位置,卡片的位置
        y_pos = y

        #y从 主标开始，80是主标高度
        y = y_pos +80 + 40

        #文字内容    
        if slide["content"]:
            y = draw_content_list(img,draw,slide,card_x,card_width,card_bg_color,font_color,section_colors,i,y,only_calc= True)
                
        # 卡片高度,保障一个最小值300的空间
        if y - y_pos < 150:
            y += 100

        #卡片高度
        card_height = y - y_pos -80

        # 绘制主标,标题
        # draw.rounded_rectangle([(card_x+card_width*0.055, y_pos), (card_x+card_width*0.95, y_pos+80)], 
        #                            radius=40, fill=section_colors[i])
        
        num_w, num_h = get_text_size(draw,slide["主标"], section_title_font)
        draw.text((card_x + (card_width-num_w)//2, y_pos+5), 
                slide["主标"], fill=section_colors[i], font=section_title_font)

        # 创建圆角卡片
        card = Image.new('RGBA', (int(card_width), int(card_height)), (0, 0, 0, 0))
        card_draw = ImageDraw.Draw(card)
        
        # 圆角矩形填充
        card_draw.rounded_rectangle([(0, 0), (card_width, card_height)], 
                            radius=40,
                            fill=card_bg_color)

        #抹去左边的圆角
        bar_width = 40
        card_draw.rectangle([(0, 0), (bar_width, card_height)], 
                           fill=card_bg_color)
        
        # 左边的彩带
        bar_width = 20
        card_draw.rectangle([(0, 0), (bar_width, card_height)], 
                           fill=section_colors[i])

        # 添加装饰元素
        card_draw.ellipse([(card_width - 80, 10),
                         (card_width - 20, 10+60)], 
                        #fill=(255, 255, 255, 30)
                        fill=section_colors[i]
                        )
                
        # 粘贴卡片到海报
        img.paste(card, (int(card_x), int(y_pos+100)), card)
        
        #真正绘制内容
        y = y_pos +80 + 40

        #文字内容    
        if slide["content"]:
            y = draw_content_list(img,draw,slide,card_x,card_width,card_bg_color,font_color,section_colors,i,y,only_calc= False)
        
        #下一个
        y = y_pos +80+30+card_height+60

    return y

"""
小圆角卡片，标题放置在卡片内部
"""
def draw_content_card_6(img,draw,poster_data,width,y_start,section_colors,card_bg_color,font_color):
    # 2. 内容区域 -多个内容块,流式布局按各自的内容大小来排
    section_y_start = y_start

    #卡片宽度
    card_width = width * 0.9
    card_x = int((width - card_width) / 2)

    #内容
    y = section_y_start #内容的绝对值是
    for i,slide in enumerate(poster_data["内容列表"]):

        # 计算位置,卡片的位置
        y_pos = y

        #y, 80是主标高度
        y = y_pos +80 +30

        #文字内容 （含副标题）
        if slide["content"]:
            y = draw_content_list(img,draw,slide,card_x,card_width,card_bg_color,font_color,section_colors,i,y,only_calc= True)

                
        # 卡片高度,保障一个最小值300的空间
        if y - y_pos < 150:
            y += 100

        #卡片高度
        card_height = y - y_pos 

        # 创建圆角卡片
        card = Image.new('RGBA', (int(card_width), int(card_height)), (0, 0, 0, 0))
        card_draw = ImageDraw.Draw(card)
        
        # 小圆角矩形填充
        card_draw.rounded_rectangle([(0, 0), (card_width, card_height)], 
                    radius=15,
                    fill=card_bg_color,
                    outline= section_colors[i])
                
        # 粘贴卡片到海报
        img.paste(card, (int(card_x), int(y_pos)), card)
        
        #真正绘制内容
        y = y_pos

        num_w, num_h = get_text_size(draw,slide["主标"], section_title_font)
        draw.rectangle([(card_x + 15, y+20+10), (card_x + 15+10, y+20+10+num_h)], 
                    fill= section_colors[i])
        draw.text((card_x + 30, y+20), 
                slide["主标"], fill=section_colors[i], font=section_title_font)

        y += num_h + 50

        #文字内容(含副标题)
        if "content" in slide:
            y = draw_content_list(img,draw,slide,card_x,card_width,card_bg_color,font_color,section_colors,i,y,only_calc= False)
        
        #下一个
        y = y_pos + card_height+60

    return y


#绘制内容列表
def draw_content_list(img,draw,slide,card_x,card_width,bg_color,font_color,section_colors,i,y,only_calc= True):
    ol=1
    for j,content in enumerate(slide["content"]):
        #文字
        if "text" in content:
            num_w = 40
            if len(slide["content"]) ==1:
                num_w = 0

            font = content_font
            if content["level"]==2:
                num_w = 0
                font = content_bold_font

            if  "bullet" in content:#二级标题
                num_w= 15
                if not only_calc:
                    
                    # draw.rectangle([(card_x +110, y+15), (card_x +110+20, y+15+20)], 
                    # fill=section_colors[i],
                    # #outline=font_color,
                    # #width=4,
                    # )
                    # 圆形  
                    # draw.ellipse([(card_x +110, y+15), (card_x +110+25, y+15+25)], 
                    # fill=font_color,
                    # outline=section_colors[i],
                    # width = 5,
                    # )
                    triangle_points = [
                        (card_x +90+15, y+10),   # 顶部顶点
                        (card_x +90, y+10+30),  # 左下顶点
                        (card_x +90+30, y+10+30)   # 右下顶点
                    ]
                    draw.polygon(triangle_points,
                    fill=section_colors[i],
                    #outline=,
                    #width = 5,
                    )
            if  "square" in content:
                num_w= 30
                if not only_calc:
                    # 方形填充
                    draw.rectangle([(card_x +110, y+15), (card_x +110+20, y+15+20)], 
                    fill=section_colors[i],
                    #outline=font_color,
                    #width=4,
                    )
            #顺序号
            if  "number" in content:
                num_w= 50
                if not only_calc:
                    # 圆点填充
                    draw.ellipse([(card_x +110, y+5), (card_x +110+40, y+5+40)], 
                    fill=section_colors[i],
                    #outline=font_color
                    )
                    #数字
                    draw.text((card_x +110+10, y-2), 
                        str(ol), fill=card_bg_color, font=content_font)
                    ol +=1


            if content["level"]==1:
                #副标题
                y = draw_multiline_text(
                draw, 
                content["text"],
                (card_x +90, y),
                card_width-120,
                section_title_font,
                section_colors[i],
                line_spacing=15,
                only_calc = only_calc
                )
            else:
                
                y = draw_multiline_text(
                    draw, 
                    content["text"],
                    (card_x +110+num_w, y),
                    card_width-120-num_w,
                    font,
                    font_color,
                    line_spacing=15,
                    only_calc = only_calc
                )
            y +=20
        elif "image" in content:
            image = content
            image_width= int(card_width)-100
            
            resized_img,target_height= draw_image(image["path"],image_width)
            draw.text((card_x + 100, y), 
                image["caption"], fill=font_color, font=footer_font)
            img.paste(resized_img, (card_x+50,y+50), resized_img.convert('RGBA'))
            y += target_height+65

        elif "table" in content:
            y = draw_table(draw,content["data"],
                           y,card_x+40,card_width-80,
                           keyword_font,content_font,
                           font_color,section_colors[i],
                           bg_color
            )
            y +=20

    return y
        


"""
无卡片布局
"""
def draw_content_3(img,draw,poster_data,width,y_start,section_colors,title_color,bg_color,font_color):
    # 2. 内容区域 -多个内容块,流式布局按各自的内容大小来排
    section_y_start = y_start

    #卡片宽度
    card_width = width * 0.9
    card_x = int((width - card_width) / 2)

    #内容
    y = section_y_start #内容的绝对值是
    for i,slide in enumerate(poster_data["内容列表"]):

        # 计算位置,卡片的位置
        y_pos = y

        #y从 主标
        y = y_pos + 80 + 30
 
        #内容    
        if slide["content"]:
            y = draw_content_list(img,draw,slide,card_x,card_width,bg_color,font_color,section_colors,i,y,only_calc= True)

        # 卡片高度,保障一个最小值300的空间
        if y - y_pos < 150:
            y += 100

        #卡片高度
        card_height = y - y_pos

        # 绘制主标,标题点缀
        draw.rectangle([(card_x, y_pos), (card_x+10, y_pos+70)], 
                         fill=section_colors[i])
        
        num_w, num_h = get_text_size(draw,slide["主标"], section_title_font)
        draw.text((card_x+20, y_pos+5), 
                slide["主标"], fill=title_color, font=section_title_font)
    
        #真正绘制内容
        y = y_pos + 80 + 30

        #文字内容    
        if slide["content"]:
            y = draw_content_list(img,draw,slide,card_x,card_width,bg_color,font_color,section_colors,i,y,only_calc= False)

        #下一个
        y = y_pos +80+30+card_height+20

    return y


"""
无卡片，网格布局
"""
def draw_content_4(img,draw,poster_data,width,y_start,section_colors,title_color,bg_color,font_color):
    # 2. 内容区域 -多个内容块,流式布局按各自的内容大小来排
    section_y_start = y_start

    #卡片宽度
    card_width = width * 0.9
    card_x = int((width - card_width) / 2)

    #内容
    y = section_y_start #内容的绝对值是
    for i,slide in enumerate(poster_data["内容列表"]):

        # 计算位置,卡片的位置
        y_pos = y

        #y从 主标
        y = y_pos + 80 + 30
 
        #文字内容    
        if slide["content"]:
            y = draw_content_list(img,draw,slide,card_x,card_width,bg_color,font_color,section_colors,i,y,only_calc= True)

        # 卡片高度,保障一个最小值300的空间
        if y - y_pos < 150:
            y += 100

        #卡片高度
        card_height = y - y_pos

        #主标题
        num_w, num_h = get_text_size(draw,slide["主标"], section_title_font)
        draw.text((card_x+20, y_pos+5), 
                slide["主标"], fill=section_colors[i], font=section_title_font)
        
        # 绘制主标,标题下方点缀
        draw.rectangle([(card_x+20, y_pos+30+num_h), (card_x+20+num_w, y_pos+30+num_h+10)], 
                         fill=section_colors[i])
    
        #真正绘制内容
        y = y_pos + 80 + 30

        #文字内容    
        if slide["content"]:
            y = draw_content_list(img,draw,slide,card_x,card_width,bg_color,font_color,section_colors,i,y,only_calc= False)

        #下一个
        y = y_pos +80+30+card_height+20

    return y

#总结的card
def draw_submit_card(img,draw,poster_data,width,y,title_color,card_bg_color,subtitle_color,style="round"):
    card_width = int(width*0.90)
    card_x = int(width*0.05)

    container_height = draw_multiline_text(
                draw, 
                poster_data["结语"],
                (card_x+40, y),
                card_width-40,
                end_font,
                title_color,
                line_spacing=15,
                only_calc=True
            )-y+20
    
    container = Image.new('RGBA', (card_width, container_height), (0, 0, 0, 0))
    container_draw = ImageDraw.Draw(container)
    if style=="round":
        container_draw.rounded_rectangle([(0, 0), (card_width, container_height)], 
                                        radius=20, fill=card_bg_color)
    elif style=="rect":
        container_draw.rectangle([(0, 0), (card_width, container_height)], 
                    fill=card_bg_color)
    
    # 粘贴容器
    img.paste(container, (card_x, y), container)

    y +=10
    y = draw_multiline_text(
        draw, 
        poster_data["结语"],
        (card_x+40, y),
        card_width-40,
        end_font,
        subtitle_color,
        line_spacing=15
    )

    return y


#尾部样式1： 渐变圆点
def draw_footer_1(img,draw,poster_data,width,y,title_color,subtitle_color):
    # 装饰元素 - 渐变圆点
    footer_dots_y = y

    #手机一整屏
    if footer_dots_y <1980:#内容少的直接到底部
        footer_dots_y = 1980
    
    #13个点，一个点大，一个点小
    for i in range(13):
        x = width * (0.1 + 0.066 * i)
        size = 10 + i % 4
        color = subtitle_color
        draw.ellipse([(x, footer_dots_y), (x+size, footer_dots_y+size)], 
                    fill=color)
    
    #装饰元素 -线
    footer_line_y = footer_dots_y+20
    draw.line([(width*0.1, footer_line_y), (width*0.9, footer_line_y)], 
             fill=title_color, width=2)
    
    #海报尾部文字
    y  = footer_line_y+30
    for i,footer in enumerate(poster_data["报尾"]):
        if len(footer)<30:
            #单行，居中对齐
            footer = footer.replace("."," · ")
            footer_w, footer_h = get_text_size(draw,footer, footer_font)
            draw.text(((width - footer_w) // 2, y), 
                    footer, fill=subtitle_color, font=footer_font)
            y += footer_h+10
        else:
            #多行，居左对齐
            y = draw_multiline_text(
                    draw, 
                    footer,
                    (40, y),
                    width-40,
                    footer_font,
                    subtitle_color,
                    line_spacing=15
                )

    
    #海报尾部图片
    image_width  =  width //2 #海报的一半
    y = y+30

    for i,image in enumerate(poster_data["报尾图片"],1):
        # 调整图像大小
        resized_img,target_height =draw_image(image["path"],image_width)

        #图片文字
        if image["caption"] and image["caption"][-3:] not in ["png","jpg","peg"]:
            draw.text(((width-image_width)//2+10, y+i*10), 
                        image["caption"], fill=subtitle_color, font=footer_font)
            y += i*10+60
            
        #图片居中
        img.paste(resized_img, ((width-image_width)//2,y), resized_img.convert('RGBA'))
        y += target_height+10
        

    return y+60

#手机适合的宣传图
def create_modern_mobile_poster(poster_data,poster_style={}):
    # 海报尺寸 (手机竖屏9:16比例)
    width, height = 1080, 20000

    accent_color = (100, 180, 180) # 青蓝色点缀

    # 主色调：深蓝背景 + 金色点缀
    bg_color = (15, 30, 64)       # 深蓝背景
    title_color = (255, 215, 0)   # 金色标题
    subtitle_color = (220, 220, 240)  #亚白
    card_bg_color = (30, 50, 80, 220) #浅蓝
    section_colors = [
        (255,77,90),    #粉红
        (70, 130, 180),   # 蓝色
        (100, 180, 160),  # 青色
        (180, 120, 70),     # 橙色
        (184, 66, 55),   # 砖红
    ]
    font_color = (240, 240, 240)  #接近白色

    if poster_style:
        try:
            bg_color = hex_to_rgb(poster_style["bg_color"])
            title_color = hex_to_rgb(poster_style["title_color"])
            subtitle_color = hex_to_rgb(poster_style["subtitle_color"])
            card_bg_color = hex_to_rgb(poster_style["card_bg_color"])
            section_colors = [ hex_to_rgb(color) for color in poster_style["section_colors"]]*5
            font_color = hex_to_rgb(poster_style["font_color"])
        except:
            pass 

    # 创建画布
    img = Image.new('RGBA', (width, height),bg_color)
    draw = ImageDraw.Draw(img)
    
    if poster_style["style"]==4:
        #网格背景
        size=50
        bg_color1 = get_similar_hsv_color(bg_color)
        #横线
        for i in range(0,height//size):
            y = size//2 + i * size
            draw.line(
                [(0, y), (width, y)], 
                #fill=(int(0.299*subtitle_color[0]),int(0.587*subtitle_color[1]),int(0.114*subtitle_color[2])), 
                fill = bg_color1,
                width=1
            )
        #竖线
        for i in range(0, width//size):
            x = size//2 + i * size
            draw.line(
                [(x, 0), (x, height)], 
                #fill=(subtitle_color[0],subtitle_color[1],subtitle_color[2],0), 
                fill = bg_color1,
                width=1
            )


    # 1. 绘制头部
    if poster_style["header_style"]==2:
        y = draw_header_2(img,draw,poster_data,width,title_color,subtitle_color)
    elif poster_style["header_style"]==3:
        y = draw_header_3(img,draw,poster_data,width,title_color,subtitle_color)
    else:
        y = draw_header_1(img,draw,poster_data,width,title_color,subtitle_color)



    # 2. 绘制中间内容
    if poster_style["style"] ==1: #多彩卡片
        # 2. 绘制内容
        y +=60
        y = draw_content_card_1(img,draw,poster_data,width,y,section_colors,card_bg_color,font_color)

        # 3.结语
        y += 50
        if poster_data["结语"]: 
            y = draw_submit_card(img,draw,poster_data,width,y,title_color,card_bg_color,subtitle_color)

    elif poster_style["style"] ==2: #标题卡片
         # 2.结语
        y += 40
        if poster_data["结语"]:
            y = draw_submit_card(img,draw,poster_data,width,y,title_color,card_bg_color,subtitle_color)

        # 3. 绘制内容
        y +=50
        y = draw_content_card_2(img,draw,poster_data,width,y,section_colors,card_bg_color,font_color)

    elif poster_style["style"] ==3: #无卡片
         # 2.结语
        if poster_data["结语"]:
            y += 40
            y = draw_submit_card(img,draw,poster_data,width,y,title_color,card_bg_color,subtitle_color,"rect")

        # 3. 绘制内容
        y +=50
        y = draw_content_3(img,draw,poster_data,width,y,section_colors,title_color,bg_color,font_color)

    elif poster_style["style"] ==4: # 网格背景
        # 2.结语
        if poster_data["结语"]:
            y += 40
            y = draw_submit_card(img,draw,poster_data,width,y,title_color,card_bg_color,subtitle_color,"rect")

        # 3. 绘制内容
        y +=50
        y = draw_content_4(img,draw,poster_data,width,y,section_colors,title_color,bg_color,font_color)
    
    elif poster_style["style"] ==5: #彩色标签卡片
         # 2.绘制内容
        y += 40
        y = draw_content_card_5(img,draw,poster_data,width,y,section_colors,card_bg_color,font_color)

        # 3. 结语
        y +=50
        if poster_data["结语"]:
            y = draw_submit_card(img,draw,poster_data,width,y,title_color,card_bg_color,subtitle_color)
    elif poster_style["style"] ==6: #小圆角卡片
        # 2. 结语
        if poster_data["结语"]:
            y += 40
            y = draw_submit_card(img,draw,poster_data,width,y,title_color,card_bg_color,subtitle_color)
        
        # 3. 绘制内容
        y +=50
        y = draw_content_card_6(img,draw,poster_data,width,y,section_colors,card_bg_color,font_color)



    # 4. 底部装饰、版权信息
    y +=60
    if poster_data["报尾"]:
        y = draw_footer_1(img,draw,poster_data,width,y,title_color,subtitle_color)

    #裁切图片
    if y < height:
        new_img = Image.new('RGB', (width, y), bg_color)
        new_img.paste(img, (0, 0))
        return new_img
    else:
        return img


#入口函数，创建海报
def create_poster(content,path):
    #百科内容转化为结构
    poster_data = parse_html_to_poster(content)

    from fun_calls import gen_poster_color
    #生成主题颜色
    
    try:
        poster_style = gen_poster_color(poster_data)
    except Exception as e:
        print("主题生成出错",e)
        poster_style = { "style": 6, "header_style": 3, "bg_color": "#F0F0F0", "title_color": "#003366", "subtitle_color": "#FFA500", "font_color": "#FFFFFF", "card_bg_color": "#D3D3D3", "section_colors": ["#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF"] }

    poster_style["style"] = 6
    poster_style["header_style"] = 3

#     #测试使用
#     poster_style={
#     "style": 6,
#     "header_style":3,
#     "bg_color": "#FFFFFF",
#     "title_color": "#333333",
#     "subtitle_color": "#003366",
#     "font_color": "#000000",
#     "card_bg_color": "#F0F8FF",
#     "section_colors": ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEEAD"],

# # "bg_color": "#000080",
# # "title_color": "#FFFFFF",
# # "subtitle_color": "#CCCCCC",
# # "font_color": "#333333",
# # "card_bg_color": "#ADD8E6",
# # "section_colors": ["#FFFFFF", "#ADD8E6", "#87CEEB", "#B0C4DE", "#D3D3D3"]
#     }


    # 生成并保存海报
    poster = create_modern_mobile_poster(poster_data,poster_style)
    poster.save(path)
    print('海报已生成: modern_poster.png')

#入口函数，创建海报
def create_poster_style(content,path,poster_style):
    #百科内容转化为结构
    poster_data = parse_html_to_poster(content)

    # 生成并保存海报
    poster = create_modern_mobile_poster(poster_data,poster_style)
    poster.save(path)
    print('海报已生成: modern_poster.png')