用代码绘制OG图:从SVG模板到Sharp渲染的博客封面实践
2026/8/26 8:32:10 网站建设 项目流程

在很多社交平台上,一篇文章被分享出去时,第一个被看到的不是标题,而是那张带链接的卡片缩略图。这张图在 HTML 里由og:image这个 meta 标签决定,也就是 Open Graph 图片,简称 OG 图。一个认真写博客的人,如果不想让自己的内容看起来像批量生产的 AI 文章,通常不会忽略这张图。这篇文章来自一个略带执念的实践系列:为了证明自己不是 AI,先从画好一张 OG 图开始。

这个标题看起来有点绕,但背后的需求很具体:当读者把链接发到聊天群、论坛或社交媒体时,平台会抓取网页并展示标题、摘要和一张缩略图。缩略图质量直接决定点击意愿,而缩略图的风格也会透露内容生产者的认真程度。这里要做的,不是用 AI 绘图工具生成一张花哨封面,而是用代码精确渲染一张 1200x630 的 OG 图,并把这套流程沉淀成可复用脚本。你可以直接用于自己的博客、GitHub 项目介绍页,或者公众号配图。下面会从 OG 图原理、SVG 模板设计、Sharp 渲染、博客接入和常见坑五个部分展开,最后给出一份发布前的检查清单。

1. 为什么一张 OG 图能影响内容的可信度

1.1 Open Graph 协议和 og:image 的工作机制

Open Graph 协议最初由 Facebook 提出,用于让网页在被分享到社交平台时,能提供比默认抓取更完整的标题、描述和图片。Web 开发者通过<meta property="og:title"><meta property="og:description"><meta property="og:image">这三组标签,告诉平台“这张页面应该如何被展示”。

当一条链接被分享时,抓取器会在几秒内访问页面,解析 head 中相关 meta,然后生成一张卡片。卡片的缩略图就是og:image指向的图片。如果这个标签缺失,平台通常会自动截取页面中的第一张图,或者完全不显示缩略图,这会造成两种结果:要么卡片样式不统一,要么因自动截取导致内容错位。

og:image的推荐尺寸一般是 1200x630,比例约 1.91:1。这个尺寸是当前大多数社交平台的标准卡片尺寸。图片格式上,PNG、JPEG 和 WebP 都能用,但要注意平台兼容性。为了通用性,本文使用 PNG 输出。

这些细节决定了一张 OG 图是否能在不同平台正确展示。仅凭这一点,就值得为博客页面专门生成一张图,而不是让框架自动塞一个随机缩略图。

1.2 AI 生成图片容易露出哪些马脚

标题里提到“证明自己不是 AI”,在 OG 图这个场景下,主要针对的是越来越常见的 AI 生图封面。很多 AI 绘图模型生成的图片,第一眼很漂亮,但放到技术博客的分享卡片里,会暴露出几个典型特征。

第一是文字渲染不稳定。AI 生成图像里的标题文字经常出现拼写错误、笔画畸形,或者字形风格和正文完全不一致。对技术博客来说,标题是卡片最重要的信息,文字一旦出错,整张图的可信度立刻下降。

第二是装饰元素缺乏语义。AI 生成图喜欢堆叠渐变光晕、玻璃拟态、飘带和抽象几何体,这些元素看起来很“炫”,但和文章内容没有关联,也看不出作者的取舍。读者看到后只会觉得这是批量生成的素材,不会被勾起点击欲望。

第三是风格过度统一。同一个模型反复出图,容易在配色、构图、光影上形成固定模式,多篇文章的封面摆在一起时,会给人一种“内容也是自动生成”的暗示。

用代码模板生成 OG 图,恰好能绕开这些问题。文字由前端模板完整控制,不会出现字形扭曲;版式由栅格和坐标决定,稳定可复用;每篇文章的标题、日期、编号和强调色不同,既统一又有变化。

1.3 这个系列的定位:保留“作者痕迹”

Going out of my way to prove I'm not an AI这个标题直译是“为了证明我不是 AI,我愿意多走弯路”。这是一个很有延续性的选题。第一集选择 OG 图片,是因为它是最容易被读者感知到“是否用心”的页面元素。

在实际项目里,“作者痕迹”可以来自很多方面:自绘的流程图、有个人习惯的代码注释、真实运行时的截图、对某个异常日志的手写标注。OG 图只是开始。通过用 SVG 精确控制每一个像素和字号,能够传递出和 AI 生成图完全不同的信息:这里有人在做决定,有人在检查细节,有人在为读者观看卡片时的体验负责。

这种“多走弯路”的做法,本质上是一种工程化实践:把设计意图变成可执行的模板和脚本,让每个新页面在生成时都保持同样标准。这也是本系列后续几集会持续使用的思路。

2. 准备环境与项目结构

2.1 Node.js 环境和依赖选择

实现 OG 图生成脚本,只需要一个可以运行 Node.js 的本地环境。推荐使用 Node.js 18 或更高版本,因为脚本里可能会用到replaceAll等新的字符串方法,也方便使用更现代的语法。

先确认本地版本:

node -v npm -v

然后创建项目目录并初始化:

mkdir og-poster cd og-poster npm init -y npm install sharp

sharp是当前 Node.js 生态里使用最广的图像处理库,底层基于 libvips。它支持读取 SVG 并输出 PNG、JPEG、WebP,也能进行缩放、裁剪、旋转和压缩。对生成 OG 图来说,sharp 足够用,而且安装简单、跨平台稳定。

这里要注意一个容易被忽略的点:sharp 渲染 SVG 时,依赖系统里的字体渲染能力。如果在服务器或 CI 环境生成图片,必须在环境里安装中文字体,否则中文标题会变成方块。关于字体问题,后面第 6 节会详细讲。

2.2 项目目录结构

为了让生成流程具备可维护性,建议一开始就按模板、脚本、数据、字体和输出目录来组织项目:

og-poster/ ├── templates/ │ └── og-post.svg ├── scripts/ │ └── generate.js ├── fonts/ │ └── SourceHanSansCN-Regular.otf ├── data/ │ └── posts.json ├── output/ │ └── post-001.png └── package.json

每个目录的职责如下:

  • templates:存放 SVG 模板。模板负责版式、配色和文字占位符。
  • scripts:存放生成脚本。脚本读取文章数据,填充模板,调用 sharp 输出 PNG。
  • fonts:存放字体文件。推荐把开源的思源黑体或 Noto Sans CJK 字体文件放在项目内,避免依赖系统字体。
  • data:存放文章元数据,比如标题、日期、文章编号、强调色。
  • output:存放生成的图片。建议输出目录加入.gitignore,避免二进制文件频繁提交。

把字体文件放到项目里,还有一个实际好处:生成结果不随运行环境变化。本地有某种字体、服务器没有,导致图片风格不一致,这种问题很常见。把字体固定进项目后,只要脚本相同,输出就一致。

2.3 准备文章数据 JSON

生成图片之前,先把文章信息整理成结构化数据。这里以本系列第一篇文章为例:

{ "posts": [ { "slug": "prove-not-ai-ep1-og-images", "title": "Going out of my way to prove I'm not an AI – Ep. #1 – OG images", "date": "2025-04-10", "episode": 1, "accentColor": "#d97706", "siteName": "Code Notes" } ] }

各字段含义:

  • slug:文章链接的最后一段,用作输出文件名。
  • title:要显示在 OG 图上的文章标题,可能需要按行拆分。
  • date:文章发布日期。
  • episode:系列第几集,用于生成EP 01标签。
  • accentColor:强调色,控制卡片上的标题下划线、标签底色等视觉元素。
  • siteName:博客名称,显示在卡片左上角或底部。

使用 JSON 而不是直接在脚本里写字符串,是为了后续能循环生成多张图。写一篇文章时,只需要新增一条数据,脚本不用改。

这里需要补充说明,实际数据可按自己博客的 front matter 或 CMS 导出格式调整。如果文章标题有特殊符号,比如#,在 JSON 里是合法字符,但放进 URL 或文件名前需要处理。本示例中.replaceAll不会处理 HTML 转义,如果标题包含<>&,在 SVG 中要转义。这一点会在第 4 节代码里体现。

3. 设计一张“不像 AI 生成”的 SVG 模板

3.1 版式原则:克制、对齐、清晰的信息层级

生成 OG 图之前,先想清楚版式。1200x630 的卡片不算大,在聊天列表或信息流里缩略显示时,细节几乎看不清。因此设计要遵循三个原则:背景简洁、标题突出、信息分层明确。

背景不需要复杂渐变。纯白、浅灰或带一点纸张质感的底色,搭配一种强调色,反而更有“人工排版”的感觉。标题是卡片的绝对主角,要占据上半部分或左半部分,字体端正,留出足够呼吸空间。置底可以放发布日期、文章编号和博客名,字号比标题小一个量级。

不要同时叠加阴影、描边、渐变和多种装饰形状。每多加一个视觉元素,就要在读者脑海里增加一次认知负担。代码生成图片的真正优势,是可以用规格保证每张图都在同一套克制体系里,避免手忙脚乱地临时加元素。

3.2 手写一张基础 SVG 模板

先创建templates/og-post.svg。下面是一个适合程序填充的模板,使用{{siteName}}{{titleLines}}{{date}}{{episode}}{{accentColor}}作为占位符:

<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630"> <rect width="1200" height="630" fill="#faf9f5"/> <rect x="80" y="80" width="80" height="10" fill="{{accentColor

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询