# ========================================== # 3. PPT 通用工具 (PPT Utilities) # ========================================== import os from utils.font_utils import is_font_available def replace_text_in_slide(prs, slide_index, placeholder, text): """在指定幻灯片中替换指定占位符的文本,并保持原有格式""" slide = prs.slides[slide_index] for shape in slide.shapes: if shape.name == placeholder: if not shape.has_text_frame: continue # 1. 保存原有格式 original_paragraph_formats = [] for paragraph in shape.text_frame.paragraphs: paragraph_format = { 'alignment': paragraph.alignment, 'space_before': getattr(paragraph, 'space_before', None), 'space_after': getattr(paragraph, 'space_after', None), 'line_spacing': getattr(paragraph, 'line_spacing', None), 'left_indent': getattr(paragraph, 'left_indent', None), 'right_indent': getattr(paragraph, 'right_indent', None), 'first_line_indent': getattr(paragraph, 'first_line_indent', None), 'font_info': [] } for run in paragraph.runs: run_format = { 'font_name': run.font.name, 'font_size': run.font.size, 'bold': run.font.bold, 'italic': run.font.italic, 'underline': run.font.underline, 'color': run.font.color, 'character_space': getattr(run.font, 'space', None), 'all_caps': getattr(run.font, 'all_caps', None), 'small_caps': getattr(run.font, 'small_caps', None) } paragraph_format['font_info'].append(run_format) original_paragraph_formats.append(paragraph_format) # 2. 设置新文本 shape.text = str(text) # 确保是字符串 # 3. 恢复格式 for i, paragraph in enumerate(shape.text_frame.paragraphs): orig_idx = i if i < len(original_paragraph_formats) else -1 if not original_paragraph_formats: break original_para = original_paragraph_formats[orig_idx] # 恢复段落属性 for attr in ['alignment', 'space_before', 'space_after', 'line_spacing', 'left_indent', 'right_indent', 'first_line_indent']: if original_para[attr] is not None: setattr(paragraph, attr, original_para[attr]) # 恢复字体属性 for j, run in enumerate(paragraph.runs): font_idx = j if j < len(original_para['font_info']) else 0 if not original_para['font_info']: break original_font = original_para['font_info'][font_idx] # 字体名称检查与回退 if original_font['font_name']: if is_font_available(original_font['font_name']): run.font.name = original_font['font_name'] else: run.font.name = "微软雅黑" # 恢复其他字体属性 if original_font['font_size']: run.font.size = original_font['font_size'] if original_font['bold']: run.font.bold = original_font['bold'] if original_font['italic']: run.font.italic = original_font['italic'] if original_font['underline']: run.font.underline = original_font['underline'] if original_font['all_caps']: run.font.all_caps = original_font['all_caps'] if original_font['character_space']: try: run.font.space = original_font['character_space'] except: pass if original_font['color']: try: if hasattr(original_font['color'], 'rgb'): run.font.color.rgb = original_font['color'].rgb except: pass def replace_picture(prs, slide_index, placeholder, img_path): """在指定幻灯片中替换指定占位符的图片""" if not os.path.exists(img_path): print(f"警告: 图片路径不存在 {img_path}") return slide = prs.slides[slide_index] sp_tree = slide.shapes._spTree for i, shape in enumerate(slide.shapes): if shape.name == placeholder: left, top, width, height = shape.left, shape.top, shape.width, shape.height sp_tree.remove(shape._element) new_shape = slide.shapes.add_picture(img_path, left, top, width, height) sp_tree.insert(i, new_shape._element) break