uni生成海报并保存

需求:通过不访问服务器,生成海报,解决服务访问压力和带宽问题,在本地生成海报图片

<template><!--页面属性配置节点,设置页面跟字体大小  --><!--  <page-meta :root-font-size="fontSize + 'px'"></page-meta>--><view class="posPoster"><view class="percard"><canvascanvas-id="myCanvas":style="{width: state.canvasWidth,height: state.canvasHeight,transform: 'scale(' + scale + ') translate(-' + translate + '%, -' + translate + '%)'}"></canvas></view><!-- 底部按钮占位,防止底部按钮挡住海报 --><view class="bottomPosHeight"></view></view><uv-modalref="modalRef"title="长按保存到本地":showCancelButton="false":showConfirmButton="false":textStyle="{ color: '#c22632' }"><uv-image width="650rpx" mode="widthFix" v-if="isShow" :src="state.imgs"></uv-image></uv-modal><view class="sureEvaluate" @click="saveImg()">下载到本地</view>
</template><script setup>import { onLoad, onReady } from '@dcloudio/uni-app'import html2canvas from 'html2canvas'const scale = ref(0.5)const picWidth = reactive(750)const picHeight = reactive(1080)const translate = computed(() => {console.log(state.screenWidth, state.ratio)return ((picWidth - state.screenWidth) / (state.screenWidth * 2)) * 100})const isShow = ref(false)const modalRef = ref()const state = reactive({fontSize: '',isShowBtn: false,myObj: {number: '',bgImg: '', //背景图name: ''},canvasWidth: picWidth, //画布宽度canvasHeight: picHeight, //画布高度ratio: window.devicePixelRatio || 1, //计算UI设计稿和你手机的屏幕宽度比例(例如UI设计稿是750宽度 你手机是350宽度 比例就是2  那么你画布画图时候 所有的尺寸大小、宽高、位置、定位左右上下都需要除以 / 比例2 )widths: '',heights: '',imgs: ''})const saveImg = () => {isShow.value = trueconsole.log(modalRef)modalRef.value.open()alert('长按保存到本地')}/*** 计算海报尺寸,适配各种手机,因为我的项目没有使用rpx用的rem所以需要换算,后来为了提出单独组件,在scss里用了rpx。*/onLoad((option) => {const pop = getCurrentPages().pop()const eventChannel = pop.$vm.getOpenerEventChannel()eventChannel.on('acceptDataFromOpenerPage', function (data) {console.log(1111, data)state.myObj.name = data.name})uni.getSystemInfo({success: (res) => {console.log(res.screenWidth)console.log(state.ratio)state.screenWidth = res.screenWidthscale.value = res.screenWidth / picWidthstate.screenHeight = res.screenHeightstate.canvasWidth = picWidth + 'px'state.canvasHeight = picHeight + 'px'state.ratio = 750 / res.screenWidthstate.widths = (res.screenWidth / 750) * 750state.heights = (res.screenWidth / 750) * 1080state.fontSize = res.screenWidth / 750downImgUrl()}})uni.showLoading({title: '生成中...'})})const downImgUrl = () => {uni.getImageInfo({src: state.myObj.bgImg,success: function (res) {console.log(1234, res)state.myObj.bgImg = res.pathdrawPageImg()state.isShowBtn = true}})}//画一个带圆角矩形const ctxCircular = (ctx, img, x, y, width, height, r, shadow) => {ctx.beginPath() //开始绘制ctx.save() //保存(canvas)状态ctx.moveTo(x + r, y)ctx.lineTo(x + width - r, y)ctx.arc(x + width - r, y + r, r, Math.PI * 1.5, Math.PI * 2)ctx.lineTo(x + width, y + height - r)ctx.arc(x + width - r, y + height - r, r, 0, Math.PI * 0.5)ctx.lineTo(x + r, y + height)ctx.arc(x + r, y + height - r, r, Math.PI * 0.5, Math.PI)ctx.lineTo(x, y + r)ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)if (shadow == 1) {ctx.shadowBlur = 20 // 模糊效果程度的ctx.shadowColor = 'red' // 阴影颜色}ctx.fill() //对当前路径中的内容进行填充ctx.clip() //从原始画布中剪切任意形状和尺寸ctx.closePath() //关闭一个路径ctx.drawImage(img, x, y, width, height)ctx.restore() //恢复(canvas)状态ctx.globalCompositeOperation = 'source-over'}//画一个矩形也就是整个海报的背景const ctxRectangle = (ctx, x, y, width, height, r, gnt) => {ctx.beginPath()ctx.save() //保存状态ctx.moveTo(x + r, y)ctx.lineTo(x + width - r, y)ctx.arc(x + width - r, y + r, r, Math.PI * 1.5, Math.PI * 2)ctx.lineTo(x + width, y + height - r)ctx.arc(x + width - r, y + height - r, r, 0, Math.PI * 0.5)ctx.lineTo(x + r, y + height)ctx.arc(x + r, y + height - r, r, Math.PI * 0.5, Math.PI)ctx.lineTo(x, y + r)ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)ctx.fillStyle = gntctx.fill() //对当前路径中的内容进行填充ctx.closePath() //关闭一个路径}// 文字const ctxText = (ctx, textFont, textAlign, textFillStyle, textName, x, y, w) => {ctx.beginPath()ctx.save() //保存状态//字体;(ctx.font = textFont),//字体样式(ctx.textAlign = textAlign)//字体颜色ctx.fillStyle = textFillStyle//填充字体var temp = ''var row = []let gxqm = ''if (textName) {gxqm = textName} else {gxqm = '失败'}let gexingqianming = gxqm.split('')for (var a = 0; a < gexingqianming.length; a++) {if (ctx.measureText(temp).width < w) {} else {row.push(temp)temp = ''}temp += gexingqianming[a]}row.push(temp)for (var b = 0; b < row.length; b++) {ctx.fillText(row[b] || '', x, y + (b + 1) * 20)}// ctx.fillText(textName || '', x, y)ctx.globalCompositeOperation = 'source-over'}// 文字const ctxTextWrap = (ctx, text, x, y, w, size) => {//自动换行介绍var temp = ''var row = []let gxqm = ''if (text) {gxqm = text} else {gxqm = ''}let gexingqianming = gxqm.split('')for (var a = 0; a < gexingqianming.length; a++) {if (ctx.measureText(temp).width < w) {} else {row.push(temp)temp = ''}temp += gexingqianming[a]}row.push(temp)ctx.font = `${size}px arail`ctx.textAlign = 'left'ctx.fillStyle = '#333'ctx.globalCompositeOperation = 'source-over'for (var b = 0; b < row.length; b++) {ctx.fillText(row[b] || '', x, y + (b + 1) * 20)}}// 文字const ctxTextWrapA = (ctx, text, x, y, w, size, color) => {//自动换行介绍var temp = ''var row = []let gxqm = ''if (text) {gxqm = text} else {gxqm = ''}let gexingqianming = gxqm.split('')for (var a = 0; a < gexingqianming.length; a++) {if (ctx.measureText(temp).width < w) {} else {row.push(temp)temp = ''}temp += gexingqianming[a]}row.push(temp)ctx.font = `${size}px arail`ctx.textAlign = 'left'ctx.fillStyle = `#${color}`ctx.globalCompositeOperation = 'source-over'for (var b = 0; b < row.length; b++) {ctx.fillText(row[b] || '', x, y + (b + 1) * 20)}}// 文字const ctxTextWrapB = (ctx, text, x, y, w, size, color) => {//自动换行介绍var temp = ''var row = []let gxqm = ''if (text) {gxqm = text} else {gxqm = ''}let gexingqianming = gxqm.split('')for (var a = 0; a < gexingqianming.length; a++) {if (ctx.measureText(temp).width < w) {} else {row.push(temp)temp = ''}temp += gexingqianming[a]}row.push(temp)// ctx.font = `arail normal bold ${size}px sans-serif`// ctx.textAlign = 'left'// ctx.fillStyle = `#${color}`// ctx.globalCompositeOperation = 'source-over'for (var b = 0; b < row.length; b++) {ctx.fillText(row[b] || '', x, y + (b + 1) * 20)}}// 使用画布绘制页面const drawPageImg = () => {// 生成画布const ctx = uni.createCanvasContext('myCanvas')// 绘制背景ctx.drawImage(state.myObj.bgImg, //图像资源0 / state.ratio, //图像的左上角在目标canvas上 X 轴的位置0 / state.ratio, //图像的左上角在目标canvas上 Y 轴的位置picWidth, //在目标画布上绘制图像的宽度picHeight //在目标画布上绘制图像的高度)let fontBase = Math.round(picWidth * 0.02580645)let fontBase2 = Math.round(fontBase * 0.84375)let fontBase3 = Math.round(fontBase * 0.875)let fontSizeStyle = fontBase + 'px 思源宋体'const date = state.myObj.arrivalDate.split('-')//编号ctxText(ctx,fontSizeStyle,'right','',state.myObj.number,picWidth * 0.871,picHeight * 0.361,picWidth * 0.242)//姓名ctxText(ctx,fontSizeStyle,'right','',state.myObj.name.length == 2 ? state.myObj.name.split('').join('  ') : state.myObj.name,picWidth * 0.2218,picHeight * 0.411,600 / state.ratio)ctx.draw(false, () => {// alert('draw')setTimeout(() => {// 将canvas 变成图片方便发送给好友或者保存uni.canvasToTempFilePath({canvasId: 'myCanvas',fileType: 'jpg',success: (res) => {// alert(JSON.stringify(res))isShow.value = trueuni.hideLoading()// alert(res.tempFilePath)state.imgs = res.tempFilePath},fail: function (error) {// alert(JSON.stringify(error))uni.hideLoading()uni.showToast({icon: 'none',position: 'bottom',title: '绘制图片失败'})}})}, 100)})}
</script><style scoped>.posPoster {width: 750rpx;height: 1338rpx;position: relative;}.percard {width: 750rpx;height: 1080rpx;overflow: hidden;position: absolute;left: 50%;transform: translate(-50%, 0);}.sureEvaluate {width: 690rpx;height: 88rpx;line-height: 88rpx;border-radius: 53rpx;background: #e6e8ff;position: fixed;bottom: 50rpx;left: 30rpx;border: none;outline: none;box-shadow: none;z-index: 999;text-align: center;}.bottomPosHeight {width: 750rpx;height: 138rpx;}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构-数组(稀疏矩阵转置)和广义表

目录 1、数组定义 1&#xff09;数组存储地址计算示例①行优先②列优先 2&#xff09;稀疏矩阵的转置三元组顺序表结构定义 ①普通矩阵转置②三元组顺序表转置稀疏矩阵③稀疏矩阵的快速转置 3&#xff09;十字链表结构定义 2、广义表定义 1&#xff09;基本操作①GetHead②GetT…

云集电商:如何通过 OceanBase 实现降本 87.5%|OceanBase案例

云集电商&#xff0c;一家聚焦于社交电商的电商公司&#xff0c;专注于‘精选’理念&#xff0c;致力于为会员提供超高性价比的全品类精选商品&#xff0c;以“批发价”让亿万消费者买到质量可靠的商品。面对近年来外部环境的变化&#xff0c;公司对成本控制提出了更高要求&…

【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案

作者&#xff1a;CSDN-PleaSure乐事 欢迎大家阅读我的博客 希望大家喜欢 使用环境&#xff1a;WebStorm 目录 问题概述 原因 解决方案 解决方法 潜在问题修改 最终效果呈现 额外内容 管理员界面路由配置 WebStorm背景更换 法一&#xff1a; 法二&#xff1a; 问题概…

一文透彻了解电容

文章目录 一、电容的作用二、电容的选择三、电容的分类四、多层陶瓷电容五、钽电容替代电解电容的误区六、旁路电容的应用问题七、电容的等效串联电阻 ESR八、电解电容的电参数九、电容器参数的基本公式十、电源输入端的 X,Y 安全电容 一、电容的作用 作为无源元件之一的电容&…

Python OpenCV 傅里叶变换

傅里叶变换 傅里叶变换比较难和不容易理解&#xff0c;有错的地方请见谅 傅里叶原理表明&#xff1a;任何连续测量的时序或信号&#xff0c;都可以表示为不同频率的正弦波信号的无限叠加。也就是说&#xff0c;傅里叶变换是一种特殊的积分变换&#xff0c;它能将满足一定条件的…

如何调整pdf的页面尺寸

用福昕阅读器打开pdf&#xff0c;进入打印页面&#xff0c;选择“属性”&#xff0c;在弹出的页面选择“高级” 选择你想调成的纸张尺寸&#xff0c;然后打印&#xff0c;打印出来的pdf就是调整尺寸后的pdf

WPF中如何简单的使用CommunityToolkit.Mvvm创建一个项目并进行 增删改查

目录 开始前准备的数据库dbblog如下&#xff1a; 第一步&#xff1a;创建项目后下载四个NuGet程序包 第二步&#xff1a;删除原本的MainWindow.XAML文件 并创建如下的目录结构 然后在View文件夹下面创建Login.XAML和Main.XAML 并且在App.XAML中将启动项改为Login.X…

基于python多准则决策分析的汽车推荐算法设计与实现

摘要 随着汽车市场的快速发展和消费者需求的多样化&#xff0c;汽车选择变得愈加复杂。为了帮助消费者在众多汽车选项中做出明智的决策&#xff0c;基于多准则决策分析&#xff08;MCDA&#xff09;的汽车推荐算法应运而生。本研究旨在设计和实现一种基于 Python 的汽车推荐系…

xftp连接中不成功 + sudo vim 修改sshd_config不成功的解决方法

我们使用sudo vim不成功&#xff0c;但是我们使用sudo su就可以 了&#xff01; root用户权利更大&#xff01; 喵的&#xff0c;终于成功了&#xff0c;一个xftp连接半天不成功。&#xff08;添加上面的内容就可以连接成功了↑&#xff09;

vue:Transition

1. Transition 1. 基本用法 <Transition> 是Vue 提供的 “内置组件动画组件”&#xff0c;与一般的CSS过渡动画不同的是&#xff0c;它通过在特点时刻给元素或组件增加、移除类名来实现——在一个元素或组件进入和离开 DOM 时应用过渡动画。 下面是一个基本用法&#…

Python 中的字符串匹配算法

在 Python 中&#xff0c;字符串匹配算法用于在一个字符串中寻找一个子串的出现位置&#xff0c;这是许多文本处理任务的核心。下面我将介绍几种常用的字符串匹配算法以及它们在 Python 中的实现方式。 1、问题背景 在 Python 中&#xff0c;字符串匹配是一个非常重要的操作&a…

配置本地策略路由示例

组网需求 RouterA与RouterB间有两条链路相连。 用户希望实现本机下发的不同长度的报文通过不同的下一跳地址进行转发&#xff0c;其中&#xff1a; 长度为64&#xff5e;1400字节的报文设置192.168.1.2作为下一跳地址。长度为1401&#xff5e;1500字节的报文设置192.168.2.2…

【大数据学习 | kafka高级部分】文件清除原理

2. 两种文件清除策略 kafka数据并不是为了做大量存储使用的&#xff0c;主要的功能是在流式计算中进行数据的流转&#xff0c;所以kafka中的数据并不做长期存储&#xff0c;默认存储时间为7天 那么问题来了&#xff0c;kafka中的数据是如何进行删除的呢&#xff1f; 在Kafka…

推荐一款基于Flash的交互式园林设计工具:Garden Planner

Garden Planner是一款由Artifact Interactive开发的基于Flash的交互式园林设计工具。它允许用户以拖放的方式安排植物、树木、建筑物和各种对象&#xff0c;使园林规划变得简单直观。此外&#xff0c;Garden Planner提供工具来快速创建铺路、路径和围栏&#xff0c;帮助用户设计…

微信小程序开发,诗词鉴赏app,诗词推荐实现(二)

微信小程序开发&#xff0c;诗词鉴赏app&#xff08;一&#xff09;&#xff1a; https://blog.csdn.net/jky_yihuangxing/article/details/143501681微信小程序开发&#xff0c;诗词鉴赏app&#xff0c;诗词推荐实现&#xff08;二&#xff09;:https://blog.csdn.net/jky_yih…

关于诊断中的各种时间参数

前言&#xff1a; 因为不会转载&#xff0c;故在这里贴出原文连接&#xff0c;写的非常好&#xff01;条理清晰&#xff0c;一遍看懂king110108 原文链接&#xff1a;UDS之时间参数总结篇_uds时间参数-CSDN博客 以下内容是我自己对这篇文章的一些备注和理解&#xff0c;以及从测…

技术干货|HyperMesh CFD功能详解:虚拟风洞 Part 2

在上期 Part 1文章中&#xff0c;我们介绍了从 v2023 版本开始&#xff0c;虚拟风洞VWT&#xff08;Virtual Wind Tunnel&#xff09;模块合并到HyperMesh CFD中。用户在VWT模块中完成LBM求解器ultraFluidX的前处理设置&#xff0c;导出参数文件XML和模型文件STL&#xff0c;并…

H7-TOOL的CAN/CANFD助手增加帧发送成功标识支持, 继续加强完善功能细节

2.27版本固件正式携带此功能&#xff0c;包括之前做的负载率检测和错误信息展示也将集成到这个版本固件中。 对于接收&#xff0c;我们可以直接看到效果&#xff0c;而发送不行&#xff0c;所以打算在发送的地方展示下发送成功标识。CAN发送不像串口&#xff0c;需要等待应答后…

mysql5安装

1.下载安装包 https://downloads.mysql.com/archives/community/ mysql-5.7.44-1.el7.x86_64.rpm-bundle.tar tar -xvf mysql-5.7.44-1.el7.x86_64.rpm-bundle.tar2.安装依赖 yum -y install perl yum -y install net-tools yum install numactl libaio libaio-devel -y也可…

大模型应用编排工具Dify二开之工具和模型页面改造

1.前言 简要介绍下 dify&#xff1a; ​ 一款可以对接市面上主流大模型的任务编排工具&#xff0c;可以通过拖拽形式进行编排形成解决某些业务场景的大模型应用。 背景信息&#xff1a; ​ 环境&#xff1a;dify-0.8.3、docker-21 ​ 最近笔者在做 dify的私有化部署和二次…