web_ppt / backend /src /services /screenshotService.js
CatPtain's picture
Upload screenshotService.js
900310e verified
raw
history blame
4.83 kB
import puppeteer from 'puppeteer';
class ScreenshotService {
async generateScreenshot(htmlContent, options = {}) {
let browser = null;
try {
console.log('Starting Puppeteer browser...');
// 更适合容器环境的Puppeteer配置
browser = await puppeteer.launch({
headless: 'new',
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--no-first-run',
'--no-zygote',
'--disable-gpu',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
'--disable-web-security',
'--disable-features=TranslateUI',
'--disable-extensions',
'--disable-component-extensions-with-background-pages',
'--disable-default-apps',
'--mute-audio',
'--no-default-browser-check',
'--autoplay-policy=user-gesture-required',
'--disable-background-mode',
'--disable-plugins',
'--disable-translate',
'--disable-ipc-flooding-protection',
'--memory-pressure-off',
'--max_old_space_size=4096'
],
timeout: 30000,
protocolTimeout: 30000
});
console.log('Browser launched successfully');
const page = await browser.newPage();
console.log('New page created');
// PPT标准尺寸 (4:3 比例)
const pptWidth = 1000;
const pptHeight = 750;
// 设置页面视窗大小,添加足够的边距以避免裁切问题
await page.setViewport({
width: pptWidth + 100, // 添加边距
height: pptHeight + 100, // 添加边距
deviceScaleFactor: 2 // 高分辨率
});
console.log('Viewport set');
// 修改HTML内容,确保PPT容器居中且尺寸精确
const modifiedHtmlContent = htmlContent.replace(
'<div class="slide-container"',
`<div class="slide-container" style="width: ${pptWidth}px; height: ${pptHeight}px; position: absolute; left: 50px; top: 50px; margin: 0; transform: none; box-shadow: 0 2px 10px rgba(0,0,0,0.1);"`
).replace(
'.viewport-container {',
`.viewport-container {
position: relative;
width: ${pptWidth + 100}px;
height: ${pptHeight + 100}px;
background-color: transparent;
display: block;`
);
// 设置HTML内容
await page.setContent(modifiedHtmlContent, {
waitUntil: 'domcontentloaded',
timeout: 10000
});
console.log('HTML content set');
// 等待渲染完成
await page.waitForTimeout(1000);
console.log('Taking screenshot...');
// 精确截取PPT区域
const screenshot = await page.screenshot({
type: 'jpeg',
quality: 90, // 提高质量
clip: {
x: 50,
y: 50,
width: pptWidth,
height: pptHeight
},
timeout: 10000
});
console.log('Screenshot taken successfully, size:', screenshot.length);
return screenshot;
} catch (error) {
console.error('Screenshot generation error:', error);
// 返回一个错误图片而不是抛出异常
return this.generateErrorImage(error.message);
} finally {
if (browser) {
try {
await browser.close();
console.log('Browser closed');
} catch (closeError) {
console.error('Error closing browser:', closeError);
}
}
}
}
// 生成错误提示图片 - 也使用精确的PPT尺寸
generateErrorImage(errorMessage = '截图生成失败') {
const pptWidth = 1000;
const pptHeight = 750;
const canvas = `
<svg width="${pptWidth}" height="${pptHeight}" xmlns="http://www.w3.org/2000/svg">
<rect width="${pptWidth}" height="${pptHeight}" fill="#f8f9fa"/>
<rect x="50" y="50" width="${pptWidth - 100}" height="${pptHeight - 100}" fill="white" stroke="#dee2e6" stroke-width="2"/>
<text x="${pptWidth / 2}" y="${pptHeight / 2 - 20}" text-anchor="middle" font-family="Arial" font-size="24" fill="#6c757d">
截图生成失败
</text>
<text x="${pptWidth / 2}" y="${pptHeight / 2 + 20}" text-anchor="middle" font-family="Arial" font-size="16" fill="#868e96">
${errorMessage}
</text>
</svg>
`;
return Buffer.from(canvas);
}
}
export default new ScreenshotService();