|
import puppeteer from 'puppeteer';
|
|
|
|
class ScreenshotService {
|
|
async generateScreenshot(htmlContent, options = {}) {
|
|
let browser = null;
|
|
|
|
try {
|
|
console.log('Starting Puppeteer browser...');
|
|
|
|
|
|
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');
|
|
|
|
|
|
const pptWidth = 1000;
|
|
const pptHeight = 750;
|
|
|
|
|
|
await page.setViewport({
|
|
width: pptWidth + 100,
|
|
height: pptHeight + 100,
|
|
deviceScaleFactor: 2
|
|
});
|
|
|
|
console.log('Viewport set');
|
|
|
|
|
|
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;`
|
|
);
|
|
|
|
|
|
await page.setContent(modifiedHtmlContent, {
|
|
waitUntil: 'domcontentloaded',
|
|
timeout: 10000
|
|
});
|
|
|
|
console.log('HTML content set');
|
|
|
|
|
|
await page.waitForTimeout(1000);
|
|
|
|
console.log('Taking screenshot...');
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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(); |