File size: 4,834 Bytes
8e2959f
 
 
 
b4297f5
8e2959f
 
b4297f5
 
 
 
900310e
b4297f5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
900310e
b4297f5
 
 
 
 
8e2959f
b4297f5
8e2959f
900310e
 
 
 
 
8e2959f
900310e
 
 
8e2959f
 
b4297f5
 
900310e
 
 
 
 
 
 
 
 
 
 
 
 
 
8e2959f
900310e
 
b4297f5
 
8e2959f
b4297f5
 
900310e
 
b4297f5
 
8e2959f
900310e
8e2959f
 
900310e
 
 
 
 
 
 
b4297f5
8e2959f
 
b4297f5
 
8e2959f
b4297f5
 
 
 
 
8e2959f
b4297f5
 
 
 
 
 
 
 
8e2959f
 
b4297f5
900310e
b4297f5
900310e
 
 
b4297f5
900310e
 
 
 
b4297f5
 
900310e
b4297f5
 
 
 
 
 
 
8e2959f
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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();