// 前后端共享的PPT导出工具
// 可以在浏览器和Node.js环境中运行
export const generateSlideHTML = (pptData, slideIndex, options = {}) => {
const {
width = 1000,
height = 562,
includeInteractive = false,
format = 'view' // 'view' | 'export' | 'screenshot'
} = options;
const slide = pptData.slides[slideIndex];
if (!slide) {
throw new Error(`Slide ${slideIndex} not found`);
}
const theme = pptData.theme || {};
// 计算实际尺寸
const actualWidth = pptData.viewportSize || width;
const actualHeight = Math.ceil(actualWidth * (pptData.viewportRatio || 0.5625));
// 渲染元素
const renderElements = (elements) => {
if (!elements || elements.length === 0) return '';
return elements.map(element => {
const baseStyle = `
position: absolute;
left: ${element.left || 0}px;
top: ${element.top || 0}px;
width: ${element.width || 0}px;
height: ${element.height || 0}px;
z-index: ${element.zIndex || 1};
transform: rotate(${element.rotate || 0}deg);
`;
let content = '';
let specificStyles = '';
switch (element.type) {
case 'text':
const fontFamily = element.fontName || 'Microsoft YaHei';
const fontFallback = `${fontFamily}, 'Noto Sans SC', 'PingFang SC', 'Hiragino Sans GB', 'SimHei', 'SimSun', Arial, Helvetica, sans-serif`;
specificStyles = `
font-family: ${fontFallback};
font-size: ${element.fontSize || 14}px;
color: ${element.defaultColor || element.color || '#000'};
font-weight: ${element.bold ? 'bold' : 'normal'};
font-style: ${element.italic ? 'italic' : 'normal'};
text-decoration: ${element.underline ? 'underline' : 'none'};
text-align: ${element.align || 'left'};
line-height: ${element.lineHeight || 1.2};
padding: 10px;
word-wrap: break-word;
overflow: hidden;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
`;
content = element.content || '';
break;
case 'image':
specificStyles = `
background-image: url('${element.src}');
background-size: ${element.objectFit || 'cover'};
background-position: center;
background-repeat: no-repeat;
`;
break;
case 'shape':
specificStyles = `
background-color: ${element.fill || 'transparent'};
border: ${element.outline?.width || 0}px ${element.outline?.style || 'solid'} ${element.outline?.color || 'transparent'};
border-radius: ${element.shape === 'ellipse' ? '50%' : '0px'};
`;
break;
}
return `
(.*?)<\/div>/s)?.[1] || '';
return `
PPT Export - ${pptData.title}
🚀 PPT Export
${pptData.title} - Slide ${slideIndex + 1}
${slideContent}
Ready to generate screenshot
`;
};
// 新增:前端导出功能的服务器端实现
export const exportPPTToJSON = (pptData) => {
return {
title: pptData.title,
width: pptData.viewportSize || 1000,
height: Math.ceil((pptData.viewportSize || 1000) * (pptData.viewportRatio || 0.5625)),
theme: pptData.theme,
slides: pptData.slides,
exportedAt: new Date().toISOString(),
format: 'json',
version: '1.0'
};
};
// 新增:生成完整的HTML演示文稿
export const generateHTMLPresentation = (pptData, options = {}) => {
const {
includeInteractivity = true,
standalone = true,
includeCSS = true
} = options;
const viewportSize = pptData.viewportSize || 1000;
const viewportRatio = pptData.viewportRatio || 0.5625;
const slideHeight = Math.round(viewportSize * viewportRatio);
const theme = pptData.theme || {};
// CSS样式
const css = includeCSS ? `
` : '';
// JavaScript交互功能
const javascript = includeInteractivity ? `
` : '';
// 格式化幻灯片背景
const formatSlideBackground = (background) => {
if (!background) return 'background: #ffffff;';
if (background.type === 'solid') {
return `background: ${background.color || '#ffffff'};`;
}
if (background.type === 'gradient') {
const { gradientType, colors } = background;
if (gradientType === 'linear') {
return `background: linear-gradient(${background.gradientRotate || 0}deg, ${colors.map(c => c.color).join(', ')});`;
}
return `background: radial-gradient(${colors.map(c => c.color).join(', ')});`;
}
if (background.type === 'image' && background.image) {
return `background-image: url(${background.image.src}); background-size: cover; background-position: center;`;
}
return 'background: #ffffff;';
};
// 格式化元素
const formatElement = (element) => {
const baseStyle = `
left: ${element.left || 0}px;
top: ${element.top || 0}px;
width: ${element.width || 100}px;
height: ${element.height || 100}px;
transform: rotate(${element.rotate || 0}deg);
`;
if (element.type === 'text') {
const fontFamily = element.fontName || 'Microsoft YaHei';
const fontFallback = `${fontFamily}, 'Noto Sans SC', 'PingFang SC', 'Hiragino Sans GB', 'SimHei', 'SimSun', Arial, Helvetica, sans-serif`;
const textStyle = `
font-size: ${element.fontSize || 16}px;
font-family: ${fontFallback};
color: ${element.defaultColor || element.color || '#000000'};
font-weight: ${element.bold ? 'bold' : 'normal'};
font-style: ${element.italic ? 'italic' : 'normal'};
text-decoration: ${element.underline ? 'underline' : 'none'};
text-align: ${element.align || 'left'};
line-height: ${element.lineHeight || 1.5};
padding: 10px;
word-wrap: break-word;
overflow: hidden;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
`;
return `
${element.content || ''}
`;
}
if (element.type === 'image' && element.src) {
return `
`;
}
if (element.type === 'shape') {
const shapeStyle = `
background: ${element.fill || '#ffffff'};
border: ${element.outline?.width || 0}px solid ${element.outline?.color || '#000000'};
border-radius: ${element.borderRadius || 0}px;
`;
return `
`;
}
// 其他元素类型的基本处理
return `
`;
};
// 生成幻灯片HTML
const slidesHTML = pptData.slides.map((slide, index) => {
const slideBackground = formatSlideBackground(slide.background);
const elementsHTML = slide.elements.map(element => formatElement(element)).join('');
return `
${elementsHTML}
`;
}).join('');
// 导航控件HTML
const navigationHTML = includeInteractivity ? `
1 / ${pptData.slides.length}
` : '';
// 组装完整HTML
return `
${pptData.title}
${css}
${navigationHTML}
${javascript}
`;
};