更新记录

1.0.0(2026-10-09)

首版发布。

新增

  • generate(options) — 生成海报,异步返回输出路径
  • 4 种元素类型
    • text — 文字,支持折行、行高、左/中/右对齐、字号、颜色、粗体
    • image — 图片,支持圆角与不透明度
    • rect — 矩形 / 圆角矩形
    • line — 线条
  • 5 种尺寸预设:wechat-share / wechat-moments / wechat-poster / square / story
  • size: 'custom' + customWidth / customHeight 自定义尺寸
  • 输出格式 png / jpg / webp,quality 可调
  • 背景色支持 #RRGGBB 与 #AARRGGBB
  • listSizes() / hasNative() / platform() 能力查询
  • 三端原生合成(Android Bitmap + Canvas,iOS CIImage,鸿蒙 PixelMap)

平台限制

  • Web / 小程序不支持。generate 依赖原生位图合成(多层叠加 + 圆角遮罩 + alpha 混合),canvas 2D 无法等价实现,调用返回 50001。
  • iOS 文字图层需经 JS canvas 渲染成位图后再合成(类型库未暴露 NSString.drawAtPoint / sizeWithAttributes),矢量文字元素在 App 端会多一次 canvas 往返。

实现说明

  • 折行与文本尺寸估算(CJK 1em / ASCII 0.55em)在 JS 层完成,保证三端排版一致。
  • 颜色只接受 #RRGGBB / #AARRGGBB,透明度统一走元素 opacity 字段,便于原生层解析。
  • 原生层三端各只导出 generate 一个方法,职责收敛到「铺背景 → 逐层合成 → 编码落盘」。

平台兼容性

uni-app(3.99)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
√ √ × × √ √ √ √ √
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × × × × × - √ ×

其他

多语言 暗黑模式 宽屏模式 蒸汽模式
√ √ √ ×

czg-poster 海报生成

把多张图片与文字合成为营销海报。支持图层叠放、圆角矩形、线条、透明背景图,输出 PNG / JPEG。

平台能力

能力 Android iOS 鸿蒙 Web / 小程序
多图层合成 ✅ ✅ ✅ ❌ 需 App 端
背景纯色 ✅ ✅ ✅ ❌
图片图层 ✅ ✅ ✅ ❌
文字图层 ✅ ✅ ✅ ❌
圆角矩形 ✅ ✅ ✅ ❌
线条 ✅ ✅ ✅ ❌
图层圆角 ✅ ✅ ✅ ❌
图层不透明度 ✅ ✅ ✅ ❌
输出 PNG / JPEG / WebP ✅ ✅ ✅ ❌

为什么 Web / 小程序不支持:generate 依赖原生位图合成(多张位图叠加 + 圆角遮罩),canvas 2D 做不到同等的图层圆角与 alpha 合成质量。需要海报请在 App 端调用,或自行用 canvas 分层绘制。

安装

import { generate, listSizes, hasNative, platform } from '@/uni_modules/czg-poster/index.js'

App 端(自定义基座)会自动注入原生实现,Web / 小程序端调用会返回 50001 并提示。

快速开始

const poster = await generate({
  size: 'wechat-moments',
  background: '#101010',
  elements: [
    { type: 'image', src: '/static/bg.jpg', x: 0, y: 0, width: 900, height: 500 },
    { type: 'rect',   x: 40, y: 60, width: 400, height: 60, fill: '#FF5722', radius: 30 },
    { type: 'text',   text: '活动进行中', x: 60, y: 70, fontSize: 32, color: '#FFFFFF', fontWeight: 'bold' },
    { type: 'line',   x: 40, y: 460, width: 820, stroke: '#333333', lineWidth: 2 },
    { type: 'image',  src: '/static/logo.png', x: 760, y: 380, width: 100, height: 100, opacity: 0.6 }
  ]
})

console.log(poster.path)      // 输出文件路径
uni.previewImage({ urls: [poster.path] })

尺寸预设

listSizes()
// [ { key: 'wechat-share', name: '微信分享缩略图', width: 500, height: 400, ratio: 1.25 }, ... ]
key 名称 尺寸
wechat-share 微信分享缩略图 500×400
wechat-moments 微信朋友圈封面 900×500
wechat-poster 微信小程序海报 750×1334
square 方形 1080×1080
story 竖版故事 1080×1920

自定义尺寸:

await generate({
  size: 'custom',
  customWidth: 1200,
  customHeight: 600,
  elements: [ /* ... */ ]
})

generate(options): Promise<Object>

参数 类型 默认 说明
size string 'wechat-moments' 预设 key,或 'custom'
customWidth number — size='custom' 时必填
customHeight number — size='custom' 时必填
background string '#FFFFFF' 背景色,#RRGGBB 或 #AARRGGBB
elements Array 必填 图层数组,先入的在下、后入的在上
format string 'png' png / jpg / webp
quality number 90 1~100,jpeg/webp 有效
outPath string 自动 输出路径,默认 USER_DATA_PATH/poster_宽x高_时间戳.png

返回:

{
  path: '/.../poster_900x500_1699999999999.png',
  size: { width: 900, height: 500 },
  format: 'png',
  layers: 5          // 实际合成的图层数
}

元素类型

text — 文字

{
  type: 'text',
  text: '双十一狂欢盛典',
  x: 50, y: 120,
  width: 650,              // 给了就按此宽度折行
  fontSize: 48,
  color: '#FFFFFF',
  fontWeight: 'bold',      // 'bold' | 'normal'
  lineHeight: 1.5,         // 行高倍数
  align: 'left'            // 'left' | 'center' | 'right'
}

width 不给则按文本长度自动算宽(中文按 1em、ASCII 按 0.55em 估算)。给了 width 且 align 非 left 时按 width 做对齐基准。

折行按 \n 与宽度估算自动切分,中英文混排均可用。

image — 图片

{
  type: 'image',
  src: '/static/photo.jpg',
  x: 0, y: 0,
  width: 750, height: 500,
  radius: 16,              // 圆角(像素)
  opacity: 0.8
}

width / height 不给时由原生按图片原始尺寸处理。

rect — 矩形 / 圆角矩形

{ type: 'rect', x: 40, y: 60, width: 400, height: 60, fill: '#FF5722', radius: 30, opacity: 0.9 }

radius > 0 时走 canvas 的 beginPath + arcTo 画圆角,否则 fillRect。

line — 线条

{ type: 'line', x: 40, y: 460, width: 820, stroke: '#333333', lineWidth: 2 }

width 是线的长度(从 x 延伸到 x + width),垂直居中在 y 上。

颜色格式

只接受 #RRGGBB 与 #AARRGGBB,不支持 rgba() / 命名色 / 三位简写。透明度请用元素的 opacity 字段。

[40002] fill 必须用 #RRGGBB 格式,收到:rgba(255,0,0,0.5)
[40002] color 含非十六进制字符:#GGGGGG

完整示例:营销长图

import { generate } from '@/uni_modules/czg-poster/index.js'

export async function makeBanner() {
  return await generate({
    size: 'custom',
    customWidth: 750,
    customHeight: 1334,
    background: '#0B1020',
    format: 'jpg',
    quality: 88,
    elements: [
      // 背景图
      { type: 'image', src: '/static/hero.jpg', x: 0, y: 0, width: 750, height: 600, opacity: 0.85 },

      // 半透明色块做信息分区
      { type: 'rect', x: 0, y: 600, width: 750, height: 734, fill: '#0B1020', opacity: 0.7 },

      // 主标题(两行,自动折行)
      { type: 'text', text: '双十一狂欢盛典\n全场五折起', x: 50, y: 660,
        width: 650, fontSize: 56, color: '#FFFFFF', fontWeight: 'bold',
        lineHeight: 1.3, align: 'left' },

      // 副标题
      { type: 'text', text: '跨店满减 每满300减50', x: 50, y: 830,
        width: 650, fontSize: 28, color: '#FFB020' },

      // 价格标签
      { type: 'rect', x: 50, y: 900, width: 320, height: 110, fill: '#FF4D4F', radius: 55 },
      { type: 'text', text: '¥99', x: 100, y: 925, fontSize: 56,
        color: '#FFFFFF', fontWeight: 'bold' },

      // 分隔线
      { type: 'line', x: 50, y: 1060, width: 650, stroke: '#2A3358', lineWidth: 2 },

      // 底部 logo(带圆角)
      { type: 'image', src: '/static/logo.png', x: 50, y: 1100, width: 200, height: 68, radius: 12 },

      // 说明文字
      { type: 'text', text: '活动时间 11.01 - 11.11', x: 50, y: 1210,
        width: 650, fontSize: 24, color: '#8899BB', align: 'right' }
    ]
  })
}

错误码

码 含义
40001 EMPTY_PATH image 元素未提供 src
40002 BAD_OPTION 尺寸预设不存在、颜色格式错、quality 越界、size='custom' 未给宽高
40009 BAD_ELEMENT 元素不是对象 / type 不支持 / 坐标为负 / opacity 越界 / 数字字段传了非数字 / text 未提供 text
40010 NO_ELEMENTS elements 为空
50001 UNSUPPORTED 非 App 端(无原生合成实现)
50004 CANVAS_FAIL 当前环境无 createCanvasContext,或 canvas 导出返回空路径
50006 POSTER_FAIL 原生合成失败(画布过大或图层位图不可读)

能力查询

hasNative()          // 是否注入原生实现(App 端为 true)
platform()           // 'android' | 'ios' | 'harmony' | 'none'

实现说明

为什么文字要绕道 canvas:iOS 侧类型库未暴露 NSString.drawAtPoint / sizeWithAttributes,只有 CoreText C 风格的 showTextAtPoint(需 UnsafePointer<CChar>),UTS 无法安全构造 C 字符串指针。所以 text / rect / line 三类元素统一在 JS 层渲染成透明底位图,原生只做「位图 + 位图 → 画布」的合成。

好处:三端排版完全一致(折行、行高、对齐只有一处实现);代价是每个矢量元素多一次 canvas 往返。image 元素不绕道,直接由原生读原图。

原生层职责极简——三端各只有一个 generate(background, w, h, layers, format, quality, outPath) 方法,就是「铺背景 → 逐层画位图(含圆角与 alpha)→ 编码落盘」。

价格

授权类型 价格
普通授权(regular) ¥19.90
源码授权(sourcecode) ¥99.00

普通授权版由 DCloud 对 uts 源码加密保护,运行时经云端解密编译;源码授权版提供完整 uts 源码,可自行修改与扩展,同样享受后续版本升级。

隐私说明

本插件全部图片处理在本机完成,不联网、不采集、不上传任何图片或数据。插件不主动读取相册与存储目录,输入完全由调用方通过参数传入。隐私声明详见 package.json 的 dcloudext.declaration。

更新日志

见 changelog.md

开源协议

MIT

隐私、权限声明

1. 本插件需要申请的系统权限列表:

无。输入为调用方主动传入的图片路径或 base64 字符串,插件不主动读取相册或存储。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

全部转换在本机完成,不联网、不采集、不上传任何图片或数据。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

暂无用户评论。