Dynamic Poster Generation in WeChat Mini Programs Using Painter
Creating dynamic posters in WeChat Mini Programs often involves complex Canvas API operations. Painter simplifies this by utilizing a JSON-based configuration approach, similar to CSS, to render elements onto a <canvas> and export an image directly.
- Repository: https://github.com/manycore-maas/Painter
- Documentation: https://painterjs.github.io/docs.html
Entegration
- Clone or download the repository from GitHub.
- Copy the
components/painterdirectory into your project'scomponentsfolder (e.g.,your-miniprogram/components/painter).
Core Concepts
Unlike tradisional web Canvas libraries that manipulate the drawing context direct, Painter generates an image file based on a provided JSON schema. This resulting image is then displayed using the standard <image> component.
Component Registration
Include the component in your page's JSON configuration file.
// pages/poster/poster. { "usingComponents": { "painter": "/components/painter/painter" } }
Layout and Data Binding
The WXML template requires both the <painter> component (which remains invisible) and an <image> component to display the output.
<view>
<painter
palette="{{posterSchema}}"
bind:imgOK="onImageReady"
/>
<image src="{{outputImageUrl}}" />
</view>
palette: Accepts the JSON data structure defining the poster layout.bind:imgOK: Triggered when the image is successfully generated, returning the file path.src: Binds to the generated image's local path.
Page Logic
Construct the JSON schema in the JavaScript file and handle the image generation callback.
// pages/poster/poster.js
Page({
data: {
posterSchema: {},
outputImageUrl: '',
canvasWidth: 600,
canvasHeight: 800
},
onImageReady(e) {
const { path } = e.detail;
this.setData({ outputImageUrl: path });
},
buildSchema() {
return {
width: `${this.data.canvasWidth}px`,
height: `${this.data.canvasHeight}px`,
background: '#e0e0e0',
views: [
{
type: 'text',
text: 'Hello World',
css: {
fontSize: '80px',
color: '#333333'
}
}
]
};
},
onLoad() {
this.setData({ posterSchema: this.buildSchema() });
}
});
The palette object requires three primary fields:
width: Canvas width (e.g.,'600px').height: Canvas height (e.g., `'800px'').views: An array of elements to render.
Fixing Aspect Ratio
The native <image> component defaults to 320px by 240px, which may distort the generated poster. To maintain the correct proportions, bind the canvas dimensions directly to the image element's style.
<image
src="{{outputImageUrl}}"
style="width: {{canvasWidth}}rpx; height: {{canvasHeight}}rpx"
/>
Supported Elements
The views array supports various element types, defined by the type and css properties.
Text
Set type to "text" and provide the string via the text property.
views: [
{
type: 'text',
text: 'Main Title',
css: {
top: '150px',
left: '80px',
fontSize: '60px',
color: 'blue',
rotate: '15'
}
},
{
type: 'text',
text: 'Subtitle',
css: {
top: '250px',
left: '80px',
fontSize: '40px',
color: 'gray'
}
}
]
Image
Set type to "image" and provide the source via url. Network URLs require the domain to be whitelisted in the Mini Program backend.
views: [
{
type: 'image',
url: '/assets/images/banner.png',
css: {
top: '50px',
right: '30px',
width: '200px' // Height scales automatically
}
}
]
Rectangle
Set type to "rect". Both width and height are mandatory. Use color to fill the shape (not backgroundColor). Circular shapes can be achieved using borderRadius.
views: [
{
type: 'rect',
css: {
width: '400px',
height: '200px',
color: 'green',
borderRadius: '100px'
}
}
]
QR Code
Set type to "qrcode". The content property holds the encoded data. Dimensions are required.
views: [
{
type: 'qrcode',
content: 'https://example.com/invite',
css: {
width: '250px',
height: '250px',
color: 'darkblue'
}
}
]