assets/shoot.mjs
2.3 KB| 1 | |
| 2 | // 把 hero.html 渲染成 PNG。横版画布比 lieflat-xhs-cover 的竖版脚本宽, |
| 3 | // 所以单独走一份 viewport 配置,避免元素截图被裁掉。 |
| 4 | import { resolve } from "node:path"; |
| 5 | import { pathToFileURL } from "node:url"; |
| 6 | |
| 7 | const arg = (n, d) => { |
| 8 | const i = process.argv.indexOf(`--${n}`); |
| 9 | return i === -1 ? d : process.argv[i + 1]; |
| 10 | }; |
| 11 | |
| 12 | const html = arg("html", "hero.html"); |
| 13 | const out = arg("out", "gongwen-dna-hero-zh.jpg"); |
| 14 | // 头图 1600px 宽,对 GitHub 约 850px 的正文栏已经是 2 倍图,scale 再翻倍 |
| 15 | // 只把体积从 155KB 推到 605KB,肉眼无差别,所以默认 1。 |
| 16 | const scale = Number(arg("scale", "1")); |
| 17 | const width = Number(arg("width", "1760")); |
| 18 | const height = Number(arg("height", "900")); |
| 19 | |
| 20 | const { chromium } = await import( |
| 21 | arg("playwright", "/opt/homebrew/lib/node_modules/playwright/index.mjs") |
| 22 | ); |
| 23 | |
| 24 | const browser = await chromium.launch({ headless: true, args: ["--disable-gpu"] }); |
| 25 | const page = await browser.newPage({ |
| 26 | viewport: { width, height }, |
| 27 | deviceScaleFactor: scale, |
| 28 | }); |
| 29 | await page.goto(pathToFileURL(resolve(html)).href, { waitUntil: "load" }); |
| 30 | await page.evaluate(() => document.fonts?.ready); |
| 31 | await page.waitForTimeout(600); // 让雨滴画几帧再截 |
| 32 | |
| 33 | const scene = page.locator(".scene").first(); |
| 34 | await scene.waitFor({ state: "visible", timeout: 5000 }); |
| 35 | // 纸纹是满版噪点,PNG 压不动(1.4MB);这版式本质是一张纸的照片, |
| 36 | // 走 JPEG q92 体积降到 ~170KB,且不像调色板量化那样吃掉 logo 的绿。 |
| 37 | const jpeg = /\.jpe?g$/i.test(out); |
| 38 | await scene.screenshot({ |
| 39 | path: resolve(out), |
| 40 | ...(jpeg ? { type: "jpeg", quality: 92 } : {}), |
| 41 | }); |
| 42 | |
| 43 | const m = await page.evaluate(() => { |
| 44 | const s = document.querySelector(".scene"); |
| 45 | const a = s.querySelector(".article"); |
| 46 | const r = s.getBoundingClientRect(); |
| 47 | return { |
| 48 | css: [Math.round(r.width), Math.round(r.height)], |
| 49 | scroll: a.scrollHeight, |
| 50 | client: a.clientHeight, |
| 51 | overflowX: a.scrollWidth > a.clientWidth ? a.scrollWidth - a.clientWidth : 0, |
| 52 | }; |
| 53 | }); |
| 54 | await browser.close(); |
| 55 | |
| 56 | const bad = m.scroll > m.client || m.overflowX > 0; |
| 57 | console.log( |
| 58 | `${out} ${m.css[0]}x${m.css[1]} css → ${m.css[0] * scale}x${m.css[1] * scale} px ` + |
| 59 | `scroll ${m.scroll}/${m.client} ${bad ? `OVERFLOW y+${m.scroll - m.client} x+${m.overflowX}` : "ok"}` |
| 60 | ); |
| 61 | process.exit(bad ? 1 : 0); |
文件内容是平台检查时读出的文本,只供查看。平台不会运行包里的任何脚本或程序。

