为冰朔定制专属配图生成系统,支持三种卡片类型:
- 小红书竖版卡片 (1080×1440, 3:4)
- 即刻方卡 (1080×1080, 1:1)
- 海报 (1080×1920, 9:16)
特性:多套配色方案、多种布局风格、
Puppeteer + HTML/CSS 渲染引擎、
可部署 Web 服务 + 预览页面
使用方式:冰朔在对话里告诉铸渊内容和类型,
铸渊运行脚本生成,冰朔直接下载使用。
89 lines
2.6 KiB
JavaScript
89 lines
2.6 KiB
JavaScript
/**
|
||
* ═══════════════════════════════════════════════════
|
||
* 铸渊图片工作室 · 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'],
|
||
})
|
||
|
||
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
|
||
}
|