PosterRender 实现微信下程序 分享商品生成海报

news2025/3/18 23:09:13

PosterRender 是什么

PosterRender 是一种专注于生成高质量海报图像的技术或工具,常用于生成静态图片,特别是适合用于营销、宣传和展示的图形设计。它通常用于在服务端或客户端渲染复杂的图像,包括文字、图形、图标、背景等,生成可供下载或直接使用的最终图片格式(如 PNG 或 JPEG)。

PosterRender 用来做什么

  • 营销海报生成:
    用于快速生成电商平台的商品促销海报、活动宣传海报等。
  • 用户内容分享:
    在社交媒体上分享的内容卡片、个人成就海报(如运动记录、学习记录等)。
  • 模版化设计:
    通过可配置的模板,快速生成批量的海报,适合规模化需求。
  • 动态内容渲染:
    根据用户数据动态生成个性化的海报,如公众号文章分享页、个人二维码推广图等。

PosterRender 的优点

  • 高效性:
    能快速生成高质量的图像,特别适合批量任务。
  • 灵活性:
    支持高度定制化设计,可以通过模板调整文字、颜色、布局等细节。
  • 跨平台支持:
    可以在服务端或客户端完成渲染,适合多种技术栈(如 Node.js、Python、前端浏览器)。
  • 自动化:
    可结合动态数据生成个性化内容,减少人工设计成本。
  • 高质量输出:
    支持高清图片输出,满足打印与显示需求。

PosterRender 的缺点

  • 复杂性:
    对于初学者来说,模板配置与设计可能存在一定学习成本。
  • 性能依赖:
    如果在服务端渲染,生成大量高分辨率图片可能消耗较多的计算资源;如果在客户端渲染,可能受限于设备性能。
  • 开发成本:
    自定义模板和动态渲染的实现需要一定的开发工作量。
  • 实时性限制:
    对于需要实时生成大量图片的场景(如高并发访问),可能需要额外优化或使用缓存机制。

PosterRender实例

  • 实例是结合taro+react 实现微信小程序分享商品
  • 通过样式增加遮照,设置z-index 浮在页面上
  • PosterRender list进行x,y轴坐标布局
  // 父组件代码
  import type { QrcodeRenderRef } from '@/components/Qrcode/QrcodeRender';
  import QrcodeRender from '@/components/Qrcode/QrcodeRender';

  const ref = useRef<QrcodeRenderRef>(null);
  <QrcodeRender ref={ref} />
// 子组件代码
import type { ForwardRefRenderFunction } from 'react';
import { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react';
import type { PosterRenderRef } from '@poster-render/taro-react';
import { PosterRender } from '@poster-render/taro-react';
import { View } from '@tarojs/components';
import Taro, { pxTransform } from '@tarojs/taro';
import classNames from 'classnames';

import { getRoutineCode } from '@/services/promotion';

import styles from './styles.modules.less';
//设置海报的宽度和高度
const SIZE = {
  width: 315,
  height: 365
};

export interface QrcodeRenderRef {
  // 子组件暴露给父组件的方法
  open: () => Promise<void>;
}

const QrcodeRender: ForwardRefRenderFunction<QrcodeRenderRef> = (_, ref) => {
  const posterRender = useRef<PosterRenderRef>(null);
  // const [qrcode, setQrcode] = useState('');
  const [rendered, setRendered] = useState(false);
  const [visible, setVisible] = useState(false);
  const [data, setData] = useState<Promotion.CodeInfo>();

  // 请求接口 获取要渲染的数据
  const handleShow = useCallback(async () => {
    Taro.showToast({
      title: '正在生成',
      icon: 'loading',
      mask: true
    });
    const res = await getRoutineCode();
    if (res?.status !== 200) {
      Taro.showToast({
        title: '生成失败,请重试',
        icon: 'none'
      });
      return;
    }

    setData(res?.data);
    setVisible(true);
  }, []);

  useImperativeHandle(
    ref,
    () => ({
      open: async () => {
        handleShow().then().catch();
      }
    }),
    [handleShow]
  );

  const onRender = useCallback(async () => {
    Taro.hideLoading();
    setRendered(true);
  }, []);

  const handleHide = useCallback(async () => {
    setVisible(false);
    setRendered(false);
  }, []);

  const handleSave = useCallback(() => {
    posterRender.current?.savePosterToPhoto();
  }, []);

  return (
    <>
      <View
        catchMove
        className={classNames({
          [styles.qrcodeWrap]: true,
          [styles.qrcodeWrapShow]: rendered
        })}
      >
        <View className={styles.masker} onClick={handleHide} />
        <View className={styles.container}>
          <View className={styles.containerBox}>
            {visible && (
              <PosterRender
                disableRerender
                ref={posterRender}
                canvasId="taro-poster-render"
                renderType="image"
                canvasWidth={SIZE.width}
                canvasHeight={SIZE.height}
                debug={false}
                style={{
                  width: pxTransform(SIZE.width),
                  height: pxTransform(SIZE.height)
                }}
                showMenuByLongpress
                onRender={onRender}
                onLongTap={handleSave}
                onRenderFail={(err) => console.error('onRenderFail', err?.message)}
                onSave={(url) => {
                  console.warn('onSave', url);
                  Taro.showToast({
                    title: '保存成功',
                    icon: 'none',
                    duration: 2000
                  });
                }}
                onSaveFail={(err) => console.error('onSaveFail', err?.message)}
                list={[
                  {
                    type: 'rect',
                    x: 0,
                    y: 0,
                    width: SIZE.width,
                    height: SIZE.height,
                    backgroundColor: '#fff',
                    borderWidth: 7,
                    radius: 16,
                    borderColor: '#00C8C8'
                  },
                  {
                    type: 'image',
                    width: 240,
                    height: 240,
                    backgroundColor: '#333333',
                    src: `${data?.url}`,
                    x: 37,
                    y: 47,
                    radius: 120,
                    mode: 'cover'
                  },
                  {
                    type: 'text',
                    x: (tw) => (SIZE.width - tw) * 0.5,
                    y: 310,
                    text: '长按识别或扫描二维码识别',
                    fontSize: 14,
                    color: '#999999',
                    width: (tw) => tw,
                    height: 19,
                    lineHeight: 19
                  }
                ]}
              />
            )}
            <View className={styles.desc}>扫描该二维码与您绑定推广关系</View>
            <View onClick={handleSave} className={styles.close}>
              保存图片
            </View>
          </View>
        </View>
      </View>
    </>
  );
};

export default forwardRef(QrcodeRender);
// styles.modules.css 代码
}
.qrcodeWrap {
  position: fixed;
  top: -100%;
  left: -200%;
  z-index: -1;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
}

.qrcodeWrapShow {
  top: 0;
  left: 0;
  z-index: 9999999999;
}
.masker {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.6);
}
.container {
  width: 100vw;
  height: 100vh;
}

.containerBox {
  position: relative;
  top: 50%;
  width: 315px;
  //height: 503px;
  margin: 0 auto;
  transform: translateY(-50%);
}

.desc {
  margin-top: 35px;
  color: #fff;
  font-weight: 400;
  font-size: 14px;
  font-style: normal;
  line-height: normal;
  text-align: center;
}

.close {
  position: absolute;
  left: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 249px;
  height: 40px;
  margin-top: 30px;
  color: #fff;
  font-weight: 500;
  font-size: 18px;
  background-color: @primary-color;
  border-radius: 249px * 0.5;
  transform: translateX(-50%);
}


实例图片

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2317461.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何利用 Zeabur 实现 OceanBase 的一键部署

引言 Zeabur 是一个功能强大且即开即用的自动化部署平台&#xff0c;它不仅能迅速部署多种应用&#xff0c;还支持一键安装 MySQL、PostgreSQL 等数据库服务。 Zeabur 拥有众多国内外用户&#xff0c;如 AFFiNE、Bytebase 等企业客户&#xff0c;以及大量全栈和独立开发者。将…

(hash表+vector 数位和相等数对的最大和)leetcode 2342

一定要断点调试看看数据对不对的上&#xff01;&#xff01;&#xff01;不然很容易弄不清楚值和下标 这个题意思是在nums中找出相同数位和的值 如 数位和为7 nums中符合要求的有 43&#xff0c;7 在这些数中选两个相加取最大值&#xff0c;再与其他数位和取得的相加最大值比…

kmp报错→Cannot find skiko-windows-x64.dll.sha256

1、前言 学习kmp&#xff08;Kotlin MultiPlatform简称&#xff09;过程中报了错误&#xff0c;这个报错在直接运行desktop的main方法才会出现&#xff0c;用gradle运行却不会报错&#xff0c;新建的kmp项目也不会出现&#xff0c;我学习的写了一些代码的项目才会出现。   运…

Cocos Creator Shader入门实战(四):预处理宏定义和Chunk

引擎&#xff1a; 3.8.5 您好&#xff0c;我是鹤九日&#xff01; 回顾 学习Shader&#xff0c;前期是让人烦躁无味的&#xff0c;后期可能就是各种的逻辑让人抓耳挠腮。 一成不变的内容&#xff1a;遵循引擎设定的规则&#xff0c;理解引擎要求的规范。 这里&#xff0c;简单…

K8S快速部署

前置虚拟机环境正式部署BUG解决 前置虚拟机环境 每个虚拟机配置一次就好 #关闭防火墙 systemctl stop firewalld systemctl disable firewalld #关闭 selinux sed -i s/enforcing/disabled/ /etc/selinux/config # 永久 setenforce 0 # 临时 #关闭 swap swapoff -a # 临时 vi…

汽车PKE无钥匙进入系统一键启动系统定义与原理

汽车智能钥匙&#xff08;PKE无钥匙进入系统&#xff09;一键启动介绍 系统定义与原理 汽车无钥匙进入系统&#xff0c;简称PKE&#xff08;Passive Keyless Entry&#xff09;&#xff0c;该系统采用了RFID无线射频技术和车辆身份编码识别系统&#xff0c;率先应用小型化、小…

WPF程序使用AutoUpdate实现自动更新

AutoUpdate.NET使用 一、AutoUpdater.NET 简介 AutoUpdater.NET 是一个开源库&#xff0c;支持从各种源&#xff08;如GitHub、FTP、HTTP服务器等&#xff09;下载并安装更新。它提供了灵活的配置选项&#xff0c;允许开发者根据需求定制更新检查逻辑和用户体验。 二、安装 …

每日Attention学习28——Strip Pooling

模块出处 [CVPR 20] [link] Strip Pooling: Rethinking Spatial Pooling for Scene Parsing 模块名称 Strip Pooling (SP) 模块结构 模块特点 本质是空间注意力的一种使用横/纵两个方向的条形池化获得一维方向上的重要程度&#xff0c;结合后便可以扩展至二维方向 模块代码 …

ollama docker设置模型常驻显存

参考&#xff1a; https://github.com/ollama/ollama/issues/5272 https://deepseek.csdn.net/67cfd7c93b685529b708fdee.html 通过-e传入环境变量&#xff0c;ollama运行&#xff1a; docker run -d --gpusall -e OLLAMA_KEEP_ALIVE-1 -v ollama:/root/.ollama -p 11434:114…

无再暴露源站!群联AI云防护IP隐匿方案+防绕过实战

一、IP隐藏的核心原理 群联AI云防护通过三层架构实现源站IP深度隐藏&#xff1a; 流量入口层&#xff1a;用户访问域名解析至高防CNAME节点&#xff08;如ai-protect.example.com&#xff09;智能调度层&#xff1a;基于AI模型动态分配清洗节点&#xff0c;实时更新节点IP池回…

【深度学习|目标检测】YOLO系列anchor-based原理详解

YOLO之anchor-based 一、关于anchors的设置二、网络如何利用anchor来训练关于register_buffer训练阶段的anchor使用推理阶段的anchor使用 三、训练时的正负样本匹配静态策略&#xff1a;跨分支采样跨anchor采样跨grid采样 动态策略 总结起来其实就是&#xff1a;基于anchor-bas…

Linux 入门:权限的认识和学习

目录 一.shell命令以及运行原理 二.Linux权限的概念 1.Linux下两种用户 cannot open directory .: Permission denied 问题 2.Linux权限管理 1).是什么 2).为什么&#xff08;权限角色目标权限属性&#xff09; 3).文件访问者的分类&#xff08;角色&#xff09; 4).文…

搭建opensbi+kernel+rootfs及基本设备驱动开发流程

目录 一.编译qemu 运行opensbikernelrootfs 1.编译qemu-9.1.1 2.安装riscv64编译器 3. 编译opensbi 4.编译kernel 5.编译rootfs 设备驱动开发流程 1.安装 RISC-V 交叉编译工具链 2.驱动开发准备 3.编写简易中断控制器驱动&#xff08;PLIC&#xff09;​ 4.配置内核…

QT非UI设计器生成界面的国际化

目的 UI设计器生成界面的国际化&#xff0c;比较容易实现些&#xff0c;因为有现成的函数可以调用&#xff0c;基本过程如下&#xff1a; void MainWindow::on_actLang_CN_triggered() {//中文界面qApp->removeTranslator(trans);delete trans;transnew QTranslator;trans…

python | 输入日期,判断这一天是这一年的第几天

题目&#xff1a; 使用 python 编程&#xff0c;实现输入日期&#xff0c;判断这一天是这一年的第几天? 具体实现代码如下&#xff1a; import datetime year input(请输入年份&#xff1a;) month input(请输入月份&#xff1a;) day input(请输入天&#xff1a;) date…

单片机开发资源分析的实战——以STM32F103C8T6为例子的单片机资源分析

目录 第一点&#xff1a;为什么叫STM32F103C8T6 从资源手册拿到我们的对STM32F103C8T6的资源描述 第二件事情&#xff0c;关心我们的GPIO引脚输出 第三件事情&#xff1a;去找对应外设的说明部分 前言 本文章隶属于项目&#xff1a; Charliechen114514/BetterATK: This is…

Maven | 站在初学者的角度配置

目录 Maven 是什么 概述 常见错误 创建错误代码示例 正确代码示例 Maven 的下载 Maven 依赖源 Maven 环境 环境变量 CMD测试 Maven 文件配置 本地仓库 远程仓库 Maven 工程创建 IDEA配置Maven IDEA Maven插件 Maven 是什么 概述 Maven是一个项目管理和构建自…

【css酷炫效果】纯CSS实现3D翻转卡片动画

【css酷炫效果】纯CSS实现3D翻转卡片动画 缘创作背景html结构css样式完整代码效果图 想直接拿走的老板&#xff0c;链接放在这里&#xff1a;https://download.csdn.net/download/u011561335/90490472 缘 创作随缘&#xff0c;不定时更新。 创作背景 刚看到csdn出活动了&am…

并发编程面试题二

1、java线程常见的基本状态有哪些&#xff0c;这些状态分别是做什么的 &#xff08;1&#xff09;创建&#xff08;New&#xff09;&#xff1a;new Thread()&#xff0c;生成线程对象。 &#xff08;2&#xff09;就绪&#xff08;Runnable&#xff09;:当调用线程对象的sta…

Spring Cloud Stream - 构建高可靠消息驱动与事件溯源架构

一、引言 在分布式系统中&#xff0c;传统的 REST 调用模式往往导致耦合&#xff0c;难以满足高并发和异步解耦的需求。消息驱动架构&#xff08;EDA, Event-Driven Architecture&#xff09;通过异步通信、事件溯源等模式&#xff0c;提高了系统的扩展性与可观测性。 作为 S…