123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- import puppeteer, { Browser, PuppeteerLaunchOptions } from 'puppeteer';
- import art from 'art-template';
- import * as fs from 'fs';
- import botlogger from './logger.js';
- export class HtmlImg {
- private browser: Browser | null = null;
- async init() {
- if (!this.browser) {
- const options: PuppeteerLaunchOptions = {
- headless: true, // 无头模式,可根据需要设置为false,
- args: [
- '--no-sandbox',
- '--disable-setuid-sandbox',
- '--allow-file-access-from-files' // 新增参数
- ]
- };
- this.browser = await puppeteer.launch(options);
- }
- }
- async render(options: {
- url?: string;
- template: string;
- templateIsPath?: boolean;
- data: any;
- width?: number;
- height?: number;
- type?: string;
- quality?: number;
- fullPage?: boolean;
- background?: boolean;
- }) {
- try {
- await this.init();
- const {
- url,
- template,
- templateIsPath = true,
- data,
- width = -1,
- height = -1,
- type = 'png',
- quality = 100,
- fullPage = false,
- background = true
- } = options;
- // 读取模板
- const templateContent = templateIsPath ? fs.readFileSync(template, 'utf-8') : template;
- // 渲染HTML
- let html = '';
- if (templateContent) {
- html = art.render(templateContent, data);
- }
- // 计算高度
- // 创建页面
- const page = await this.browser!.newPage();
- await page.setViewport({ width, height });
- // 设置页面内容
- if (url) {
- await page.goto(url);
- await page.emulate({
- viewport: { width: 375, height: 667 },
- userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1'
- });
- await page.waitForNetworkIdle();
- if(data.selector){
- const element = await page.$(data.selector);
- if (element) {
- const image = await element.screenshot({ type: type as 'png' | 'jpeg', quality: type === 'jpeg'? quality : undefined });
- return image;
- }
- }
- //加载额外的js
- page.evaluate(data.urlJs)
- }else{
- await page.setContent(html, { waitUntil: 'networkidle0' });
- }
- // 获取document.body.scrollHeight
-
-
- const bodyheight = await page.evaluate(() => document.body.scrollHeight) as number;
- const bodywidth = await page.evaluate(() => document.body.scrollWidth) as number;
- botlogger.info(`获取body高度${bodyheight}和宽度${bodywidth}`)
- if(-1 != height && -1 != width){
- await page.setViewport({ width: bodywidth, height: bodyheight });
- await page.waitForNetworkIdle();
- }
- // 截图
- const image = await page.screenshot({
- type: type as 'png' | 'jpeg',
- quality: type === 'jpeg' ? quality : undefined,
- fullPage,
- omitBackground: !background
- });
- await page.close();
- return image;
- } catch (error) {
- botlogger.error('渲染图片失败:', error);
- throw error;
- }
- }
- async close() {
- if (this.browser) {
- await this.browser.close();
- this.browser = null;
- }
- }
- }
|