🎉 未来新方向!轻松生成分享海报的神器,零HTML生成海报

380 阅读3分钟

🎉 未来新方向!轻松生成分享海报的神器 —— 零HTML!

在日常开发中,生成分享海报几乎是所有 B 端 / C 端项目的刚需。
不论是商品推广、活动宣传,还是问诊报告、小程序分享,海报生成总是绕不过的一道坎。

手写 canvas?布局复杂 + 尺寸计算让人头疼;
用 html2canvas?不支持跨域图片 + 不同端兼容性差;
用 node-canvas 服务端生成?部署难、成本高、不易调试。

于是,我们造了个轮子——
🌟 gen-poster-f:一套极易扩展的前端海报生成框架,基于 canvas 实现,你只关注布局,canvas让它来。拥有强大的布局能力与灵活的组件机制!


💡 为什么我们需要 gen-poster-f?

开发中,我们遇到这些真实问题:

  • ❌ 使用 canvas 手写布局,非常麻烦,代码难维护;
  • ❌ 图片多、文字多,绘制逻辑很快变成「屎山」;
  • ❌ 想动态生成活动海报,还要处理异步加载、字体兼容、分辨率适配……
  • ❌ 一旦需求变化,整张海报都要改,复用性低;
  • ❌ 小程序 / H5 想复用海报逻辑?做不到!

于是我们参考 Flutter 的布局思想,设计了一套基于 Widget 渲染的 canvas 框架。写 canvas,就像在写 Flutter 一样!


🧩 特性一览

声明式组件化布局
通过 Widget 树的方式描述海报内容,完全告别手写 ctx.fillRect() 的混乱逻辑。

Container({
    width: 300,
    height: 300,
    color: Colors.grey200,
    alignment: Alignment.center,
    child: Container({
        width: 100,
        height: 100,
        color: Colors.blue
    })
});

强大的布局系统

  • 支持容器嵌套(Row / Column / Stack / Positioned 等)
  • 支持图片、文字、二维码、圆角、边框、背景、阴影等样式
  • 自动布局、对齐、缩放适配,多分辨率下效果一致

轻松导出高清海报
原生 toDataURL()toCanvas() 等导出方式,满足各种平台分享需求。


开箱即用的组件库
已内置常用组件:
TextImageSizedBoxContainerRowColumnPositioned ……
也可自定义组件,自由组合,打造专属海报模板!


灵活扩展 & 二次封装

  • 支持纯 html 网页引入
  • 支持写成 Vue / React 组件
  • 纯 Js/ Ts 编码,零 HTML
  • 支持在小程序中使用(抖音 / 微信 / uniapp 等平台)
  • 支持服务端渲染 NodeCanvas(计划中)

🚀 快速开始

  • 1安装

npm install gen-poster-f

  • 2初始化
    const canvas = document.querySelector("canvas");
    const dpr = canvasConfigData.dpr;
    const scale = canvasConfigData.scale || 1;
    const width =canvasConfigData.width;
    const height = canvasConfigData.height;
    const ctx = canvas.getContext("2d");
    canvas.width = width * dpr * scale;
    canvas.height = height * dpr * scale;
    ctx.scale(1 / dpr, 1 / dpr)
    GenPlatformConfig.InitInstance({
            screenWidth: canvas.width,
            screenHeight: canvas.height,
            devicePixelRatio: dpr,
            strategies: new DefaultNativeStrategies(),
            canvas,
            renderContext: ctx,
    });
  • 3运行
runApp(
  Container({
      width: canvas.width,
      height: canvas.height,
      color:Colors.black,
      child:  Stack({
        children: generateTrigramWidgets({ radius: 100 }),
      }),
    })
);

function generateTrigramWidgets({ radius }: { radius: number }): Widget[] {
  const trigrams = [
    [1, 1, 1], // 乾
    [1, 1, 0], // 兑
    [1, 0, 1], // 离
    [1, 0, 0], // 震
    [0, 1, 1], // 巽
    [0, 1, 0], // 坎
    [0, 0, 1], // 艮
    [0, 0, 0], // 坤
  ];

  return trigrams.map((lines, i) => {
    const angle = (i / 8) * 2 * Math.PI;
    const x = Math.cos(angle) * radius + 140;
    const y = Math.sin(angle) * radius + 140;

    return  Positioned({
      left: x,
      top: y,
      child: Transform.rotate({
        alignment: Alignment.center,
        angle: (Math.PI / 180) * (360 / 8) * i + (Math.PI / 180) * 90,
        child: new Container({
          child: Trigram({ lines }),
        }),
      }),
    });
  });
}

function Trigram({ lines }: { lines: number[] }): Widget {
  return  Column({
    spacing: 4,
    crossAxisAlignment: CrossAxisAlignment.center,
    children: lines.map((line) => {
      if (line === 0)
        return  Row({
          spacing: 4,
          children: [
             Container({
              width: 10,
              height: 4,
              decoration: new BoxDecoration({ backgroundColor: Colors.white }),
            }),
             Container({
              width: 10,
              height: 4,
              decoration: new BoxDecoration({ backgroundColor: Colors.white }),
            }),
          ],
        });
      return  Container({
        width: line === 1 ? 24 : 10,
        height: 4,
        decoration: new BoxDecoration({ backgroundColor: Colors.white }),
      });
    }),
  });
}
  • 4:运行效果

企业微信截图_17484890672617.png

使用方式:查看Demo

海报例子

一个完整的GenPoster海报

企业微信截图_17484862434378.png

最终生成效果图

cgi-bin_mmwebwx-bin_webwxgetmsgimg_&MsgID=8493963912230007225&skey=@crypt_cbbd980b_53b76d3dbdf01cb13005dd0903572bde&mmweb_appid=wx_webfilehelper.png


🧪 对比传统写法

展示与原生 canvas 的差异

原生CanvasGenPoster Widget
ctx.fillText 布局无约束,不能换行Text 支持父组件约束并换行
ctx.fillRect 布局无约束,布局困难Container 支持设置尺寸并嵌套,轻松布局
ctx.clip 裁剪难使用RectClip、RRectClip 轻松裁剪
更多...更多的新组件...

查看完整文档和组件示例 👉 gen-poster-doc


🎯 适用场景

  • 活动 / 商品分享图
  • 问诊报告 / AI 推理可视化图
  • 前端项目生成图片上传后台
  • 多语言海报自动布局适配
  • 静态复杂UI

💬 最后

一切都是Widget。写 canvas 不再痛苦,我们用未来的新方式优雅生成海报!