""" HTML 渲染器模块 将元素对象渲染为 HTML 代码,用于浏览器预览。 """ from pathlib import Path from core.elements import TextElement, ImageElement, ShapeElement, TableElement # 固定 DPI 用于单位转换 DPI = 96 class HtmlRenderer: """HTML 渲染器,将元素渲染为 HTML""" def render_slide(self, slide_data, index, base_path): """ 渲染单个幻灯片为 HTML Args: slide_data: 包含 background 和 elements 的字典 index: 幻灯片索引 base_path: 基础路径 Returns: str: 幻灯片的 HTML 代码 """ elements_html = "" bg_style = "" if slide_data.get('background'): bg = slide_data['background'] if 'color' in bg: bg_style = f"background: {bg['color']};" for elem in slide_data.get('elements', []): try: if isinstance(elem, TextElement): elements_html += self.render_text(elem) elif isinstance(elem, ShapeElement): elements_html += self.render_shape(elem) elif isinstance(elem, TableElement): elements_html += self.render_table(elem) elif isinstance(elem, ImageElement): elements_html += self.render_image(elem, base_path) except Exception as e: elements_html += f'
渲染错误: {str(e)}
' return f'''
幻灯片 {index + 1}
{elements_html}
''' def render_text(self, elem: TextElement): """ 将文本元素转换为 HTML Args: elem: TextElement 对象 Returns: str: HTML 代码 """ style = f""" left: {elem.box[0] * DPI}px; top: {elem.box[1] * DPI}px; width: {elem.box[2] * DPI}px; height: {elem.box[3] * DPI}px; font-size: {elem.font.get('size', 16)}pt; color: {elem.font.get('color', '#000000')}; text-align: {elem.font.get('align', 'left')}; {'font-weight: bold;' if elem.font.get('bold') else ''} {'font-style: italic;' if elem.font.get('italic') else ''} display: flex; align-items: center; white-space: normal; overflow-wrap: break-word; """ content = elem.content.replace('<', '<').replace('>', '>') return f'
{content}
' def render_shape(self, elem: ShapeElement): """ 将形状元素转换为 HTML Args: elem: ShapeElement 对象 Returns: str: HTML 代码 """ border_radius = { 'rectangle': '0', 'ellipse': '50%', 'rounded_rectangle': '8px' }.get(elem.shape, '0') style = f""" left: {elem.box[0] * DPI}px; top: {elem.box[1] * DPI}px; width: {elem.box[2] * DPI}px; height: {elem.box[3] * DPI}px; background: {elem.fill if elem.fill else 'transparent'}; border-radius: {border_radius}; """ if elem.line: style += f""" border: {elem.line.get('width', 1)}pt solid {elem.line.get('color', '#000000')}; """ return f'
' def render_table(self, elem: TableElement): """ 将表格元素转换为 HTML Args: elem: TableElement 对象 Returns: str: HTML 代码 """ table_style = f""" left: {elem.position[0] * DPI}px; top: {elem.position[1] * DPI}px; """ rows_html = "" for i, row in enumerate(elem.data): cells_html = "" for cell in row: cell_style = f"font-size: {elem.style.get('font_size', 14)}pt;" if i == 0: if 'header_bg' in elem.style: cell_style += f"background: {elem.style['header_bg']};" if 'header_color' in elem.style: cell_style += f"color: {elem.style['header_color']};" cell_content = str(cell).replace('<', '<').replace('>', '>') cells_html += f'{cell_content}' rows_html += f'{cells_html}' return f'{rows_html}
' def render_image(self, elem: ImageElement, base_path): """ 将图片元素转换为 HTML Args: elem: ImageElement 对象 base_path: 基础路径 Returns: str: HTML 代码 """ img_path = Path(base_path) / elem.src if base_path else Path(elem.src) style = f""" left: {elem.box[0] * DPI}px; top: {elem.box[1] * DPI}px; width: {elem.box[2] * DPI}px; height: {elem.box[3] * DPI}px; """ return f''