89 lines
2.7 KiB
JavaScript
Raw Normal View History

/**
*
* 铸渊图片工作室 · Puppeteer 渲染引擎
*
*/
import puppeteer from 'puppeteer'
import { existsSync, mkdirSync } from 'fs'
import { join, dirname } from 'path'
import { fileURLToPath } from 'url'
const __dirname = dirname(fileURLToPath(import.meta.url))
const OUTPUT_DIR = join(__dirname, 'output')
/**
* 渲染 HTML 为图片
* @param {string} html - 完整 HTML 字符串
* @param {object} opts
* @param {number} opts.width - 图片宽度
* @param {number} opts.height - 图片高度
* @param {string} opts.name - 输出文件名不含扩展名
* @param {string} opts.format - 输出格式 png/webp/jpeg
* @param {number} opts.quality- 图片质量 webp/jpeg
* @returns {Promise<string>} 输出文件路径
*/
export async function renderToImage(html, opts = {}) {
const {
width = 1080,
height = 1440,
name = `card_${Date.now()}`,
format = 'png',
quality = 90,
} = opts
if (!existsSync(OUTPUT_DIR)) mkdirSync(OUTPUT_DIR, { recursive: true })
const browser = await puppeteer.launch({
headless: true,
executablePath: '/usr/bin/google-chrome',
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-features=TranslateUI', '--font-render-hinting=none'],
})
try {
const page = await browser.newPage()
await page.setViewport({ width, height })
// 注入完整的 HTML
await page.setContent(html, { waitUntil: 'networkidle0' })
// 等待字体加载
await page.evaluate(() => document.fonts.ready)
// 额外等一会儿让渲染稳定
await new Promise(r => setTimeout(r, 500))
const outputPath = join(OUTPUT_DIR, `${name}.${format}`)
await page.screenshot({
path: outputPath,
type: format,
clip: { x: 0, y: 0, width, height },
quality: format !== 'png' ? quality : undefined,
})
return outputPath
} finally {
await browser.close()
}
}
/**
* 批量生成多页轮播图
* @param {string[]} pages - 每页的 HTML
* @param {object} opts
* @returns {Promise<string[]>} 输出文件路径数组
*/
export async function renderCarousel(pages, opts = {}) {
const results = []
for (let i = 0; i < pages.length; i++) {
const name = opts.baseName
? `${opts.baseName}_p${i + 1}`
: `carousel_${Date.now()}_p${i + 1}`
const path = await renderToImage(pages[i], { ...opts, name })
results.push(path)
}
return results
}