uni-app实现canvas绘制图片、海报等

这篇具有很好参考价值的文章主要介绍了uni-app实现canvas绘制图片、海报等。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前段时间有个项目,需要绘制海报,我一听这不是可以用canvas来实现吗,所以我在五一假期就记录下实现方式

我把canvas绘制图片封装成一个组件,直接引入使用就好了。

这里虽然是uni-app写的,但实现方式其实都是一样的,之后其他原生小程序用到也是大差不大的,真的很简单😆

遇到的坑:uni-app在转app的时候 - ios 的canvas画布过大可能导致绘制空白 

创建canvas绘制图片的组件 - 代码如下

<template>
	<view>
		<canvas canvas-id="canvas" :style="{'width': width + 'px', 'height': height + 'px'}" style="position: fixed; left: -9999px; top: -9999px;"></canvas>
	</view>
</template>

<script>
	export default {
		name: "drawImage",
		props: {
			// 绘制图片的尺寸
			imageSize: {
				type: Object,
				default: () => {},
			},
			// canvas绘制的数据
			canvasData: {
				type: Array,
				default: () => [],
			},
			// 是否开始绘制
			isDraw: {
				type: Boolean,
				default: false,
			},
		},
		data() {
			return {
				// 屏幕宽度
				screenWidth: 0,
				// canvas画布的宽度
				width: 0,
				// canvas画布的高度
				height: 0,
				// 当前图片放大倍数 - 清晰度
				count: 2,
			};
		},
		mounted() {
            // 这段代码主要是为了防止uni-app在app端IOS的问题,因为在IOS 画布过大可能会导致绘制空白 - 可以自行调整
			// #ifdef APP-PLUS
			if(uni.getSystemInfoSync().platform === 'ios') {
				this.count = 1.8;
			}
			// #endif
		},
		watch: {
			// 监听是否开始绘制
			isDraw: async function(newVal) {
				if(newVal) {
					this.getSystemInfo();
					this.getImageByCanvasData(this.canvasData);
				}
			}
		},
		methods: {
			/** 获取系统信息 */
			getSystemInfo() {
				const { screenWidth } = uni.getSystemInfoSync();

				this.width = this.imageSize.width * this.count;
				this.height = this.imageSize.height * this.count;

				this.screenWidth = screenWidth;
			},
			
			/**
			 * 通过数据绘制图片
			 * @param {array} data		canvas绘制的数组
			 * 格式:每一项的数据
			 * { type: 'rect',  attr: { color: '', x, y, width, height, radian_1, radian_2, radian_3, radian_4 } }
			 * { type: 'image', attr: { image: '', x, y, width, height, radian_1, radian_2, radian_3, radian_4 } }
			 * { type: 'text',  attr: { text: '', x, y, color, size, weight, writingMode } }
			 * */
			async getImageByCanvasData(data) {
				// 获取canvas上下文对象
				const context = uni.createCanvasContext("canvas", this);
				// 清空画布
				context.clearRect(0, 0, this.width * this.count, this.height * this.count);

				for(const item of data) {
					// 判断类型
					if(item.type === 'rect') {
						// 绘制圆边矩形
						this.drawRoundRectangular(
							context, 
							item.attr.color, 
							item.attr.x * this.count, 
							item.attr.y * this.count, 
							item.attr.width * this.count, 
							item.attr.height * this.count, 
							item.attr.radian_1 ? item.attr.radian_1 * this.count : 0, 
							item.attr.radian_2 ? item.attr.radian_2 * this.count : -1, 
							item.attr.radian_3 ? item.attr.radian_3 * this.count : -1, 
							item.attr.radian_4 ? item.attr.radian_4 * this.count : -1
						);
					}
					else if(item.type === 'image' && item.attr.image) {
						// 绘制圆边图片
						await this.drawRoundImageToCanvas(
							context, 
							item.attr.image, 
							item.attr.x * this.count, 
							item.attr.y * this.count, 
							item.attr.width * this.count, 
							item.attr.height * this.count, 
							item.attr.radian_1 ? item.attr.radian_1 * this.count : 0, 
							item.attr.radian_2 ? item.attr.radian_2 * this.count : -1, 
							item.attr.radian_3 ? item.attr.radian_3 * this.count : -1, 
							item.attr.radian_4 ? item.attr.radian_4 * this.count : -1
						);
					}
					else if(item.type === 'text' && item.attr.text) {
						// 绘制文本
						this.drawTextToCanvas(
							context, 
							item.attr.text, 
							item.attr.x * this.count, 
							item.attr.y * this.count, 
							item.attr.color, 
							parseInt(item.attr.size ? item.attr.size * this.count : 16 * this.count), 
							item.attr.weight,
							item.attr.writingMode ? item.attr.writingMode : 'initial'
						);
					}
				}
				
				// 绘制图片 
				context.draw(false, () => {
					uni.canvasToTempFilePath({
						canvasId: 'canvas',
						x: 0,
						y: 0,
						width: this.width,
						height: this.height,
						destWidth: this.width,
						height: this.height,
						success: res => {
							this.$emit("generateImageSuccessful", res.tempFilePath);
						},
					}, this);
				});
			},
			
			/**
			 * 绘制文本
			 * @param {string} context		Canvase的实例
			 * @param {string} text			文本内容
			 * @param {number} x			矩形的x坐标
			 * @param {number} y			矩形的y坐标
			 * @param {number} color		文本颜色
			 * @param {number} size			字体的大小
			 * @param {string} weight		字体的粗细
			 * @param {string} writingMode	字体的排列方式 - initial 水平  tb 垂直
			 * */
			drawTextToCanvas(context, text, x, y, color = '#000', size = 16, weight = '400', writingMode = 'initial') {
				context.fillStyle = color;
				context.font = `normal ${weight} ${size}px sans-serif`;
				if(writingMode === 'tb') {
					const temp = text.split("");
					for(let i = 0; i < temp.length; i++) {
						context.fillText(temp[i], x, i * size + y);
					}
				}
				else {
					// 判断是否有换行符
					const temp = text.split("\n");
					for(let i = 0; i < temp.length; i++) {
						context.fillText(temp[i], x, i * size + y + i * size * 0.2);  // i * size * 0.2 增加换行的间距
					}
				}
			},
			
			/**
			 * 绘制圆边矩形
			 * @param {string} context	Canvase的实例
			 * @param {string} color	填充的颜色
			 * @param {number} x		矩形的x坐标
			 * @param {number} y		矩形的y坐标
			 * @param {number} width	矩形的宽度
			 * @param {number} height	矩形的高度
			 * @param {number} height	图片的高度
			 * @param {number} radian_1	弧度大小 - radian_1 右上 的弧度, 1个参数代表全部
			 * @param {number} radian_2	弧度大小 - radian_2 右下 的弧度
			 * @param {number} radian_3	弧度大小 - radian_3 左下 的弧度
			 * @param {number} radian_4	弧度大小 - radian_4 左上 的弧度
			 * */
			drawRoundRectangular(context, color, x, y, width, height, radian_1 = 0, radian_2 = -1, radian_3 = -1, radian_4 = -1) {
				context.save();
				this.drawRoundPath(context, x, y, width, height, radian_1, radian_2, radian_3, radian_4);
				context.setFillStyle(color);
				context.fill();
				context.restore();
			},
			
			/**
			 * 绘制圆角图片
			 * @param {string} context	Canvase的实例
			 * @param {string} image	图片地址
			 * @param {number} x		图片的x坐标
			 * @param {number} y		图片的y坐标
			 * @param {number} width	图片的宽度
			 * @param {number} height	图片的高度
			 * @param {number} radian_1	弧度大小 - radian_1 右上 的弧度, 1个参数代表全部
			 * @param {number} radian_2	弧度大小 - radian_2 右下 的弧度
			 * @param {number} radian_3	弧度大小 - radian_3 左下 的弧度
			 * @param {number} radian_4	弧度大小 - radian_4 左上 的弧度
			 * */
			async drawRoundImageToCanvas(context, image, x, y, width, height, radian_1 = 0, radian_2 = -1, radian_3 = -1, radian_4 = -1) {
				context.save();
				this.drawRoundPath(context, x, y, width, height, radian_1, radian_2, radian_3, radian_4);
				context.drawImage(await this.handleNetworkImgaeTransferTempImage(image), x, y, width, height);
				context.restore();
			},
			
			/**
			 * 绘制圆边路径
			 * @param {string} context	Canvase的实例
			 * @param {number} x		图片的x坐标
			 * @param {number} y		图片的y坐标
			 * @param {number} width	图片的宽度
			 * @param {number} height	图片的高度
			 * @param {number} radian_1	弧度大小 - radian_1 右上 的弧度, 1个参数代表全部
			 * @param {number} radian_2	弧度大小 - radian_2 右下 的弧度
			 * @param {number} radian_3	弧度大小 - radian_3 左下 的弧度
			 * @param {number} radian_4	弧度大小 - radian_4 左上 的弧度
			 * */
			drawRoundPath(context, x, y, width, height, radian_1 = 0, radian_2 = -1, radian_3 = -1, radian_4 = -1) {
				// 设置弧度
				radian_2 = radian_2 === -1 ? radian_1 : radian_2;
				radian_3 = radian_3 === -1 ? radian_1 : radian_3;
				radian_4 = radian_4 === -1 ? radian_1 : radian_4;
				
				// 创建路径 - 绘制带圆边的矩形
				context.beginPath();											
				context.moveTo(x + width / 2, y);
				context.arcTo(x + width, y, x + width, y + height, radian_1);
				context.arcTo(x + width, y + height, x, y + height, radian_2);
				context.arcTo(x, y + height, x, y, radian_3);
				context.arcTo(x, y, x + width, y, radian_4);
				// 关闭路径 - 结束绘制
				context.closePath();
				context.strokeStyle = "transparent";
				context.stroke();
				context.clip();
			},
			
			/** 将网络图片变成临时图片 */
			handleNetworkImgaeTransferTempImage(url) {
				return new Promise(resolve => {
					if(url.indexOf('http') === 0) {
						uni.downloadFile({
							url,
							success: res => {
								resolve(res.tempFilePath);
							}
						});
					}
					else {
						resolve(url);
					}
				});
			},
		}
	}
</script>

<style scoped lang="scss">

</style>

在页面中的使用 

<template>
	<view>
		<!-- 显示一下绘制完成后的路径 -->
		<image :src="tempImage" style="width: 375px; height: 667px;"></image>
		
		<!-- 引入绘制图片的组件 -->
		<drawImage :isDraw="isDraw" :canvasData="canvasData" :imageSize="{width: 375, height: 667}" @generateImageSuccessful="generateImageSuccessful" />
	</view>
</template>

<script>
export default {
	data() {
		return {
			// 是否开始绘制
			isDraw: false,
			/**
			 * 需要绘制的图片数据 - 具体参数需要看组件内的
			 * { type: 'rect',  attr: { color: '', x, y, width, height, radian_1, radian_2, radian_3, radian_4 } }
			 * { type: 'image', attr: { image: '', x, y, width, height, radian_1, radian_2, radian_3, radian_4 } }
			 * { type: 'text',  attr: { text: '', x, y, color, size, weight, writingMode } }
			 * */
			canvasData: [],
			// 临时路径
			tempImage: "",
		}
	},
	onLoad() {
		this.canvasData = [
			{ type: 'rect', attr: { color: '#00a127', x: 0, y: 0, width: 375, height: 667 } },
			{ type: 'text',  attr: { text: '略略大魔王', x: 100, y: 100, color: '#fff', size: 20, weight: '500', writingMode: 'tb' } }
		];
		
		this.isDraw = true;
	},
	methods: {
		/** 绘制成功后的回调 - 返回一个临时路径 */
		generateImageSuccessful(image) {
			this.tempImage = image;
		}
	}
};
</script>

<style scoped lang="scss">
	
</style>

这里只是简单的演示下(效果图):

createcanvascontext,前端,javascript,前端,html,小程序,vue文章来源地址https://www.toymoban.com/news/detail-699102.html

到了这里,关于uni-app实现canvas绘制图片、海报等的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 小程序-uni-app:将页面(html+css)生成图片/海报/名片,进行下载 保存到手机

    一、需要描述 本文实现,uniapp微信小程序,把页面内容保存为图片,并且下载到手机上。 说实话网上找了很多资料,但是效果不理想,直到看了一个开源项目,我知道可以实现了。 本文以开源项目uniapp-wxml-to-canvas 为蓝本 记录集成的步骤,以供参考。 详细内容可以下载并启

    2024年02月07日
    浏览(35)
  • uni-app+vue2 微信小程序 使用canvas绘制折线图/波形图

      接口返回一个数组,每一项均是一个数字,代表着y坐标,x坐标需自己处理。 我的数据是1024个浮点数,在-10到10之间 波形图需要xy轴缩放功能,用c3的 transform: scale()是不行的,至少会失真。 然后背景的格子,我这里是每个格子要求100个点,初始缩放下是11个格子,10条线(

    2024年04月26日
    浏览(47)
  • uni-app微信小程序-利用canvas给图片添加水印

    选择图片 → 将图片绘制到 canvas 中并绘制水印 →将添加水印的图片绘制到 canvas 中 → 将 canvas 画布转换为图片地址 → 上传/展示操作 注意:微信小程序在选择照片或者唤起相机之前需要获取相应的 权限 利用 uni.getSetting 查看用户是否调用相机的权限(有就选择图片,没有就

    2024年02月06日
    浏览(34)
  • uni-app 微信小程序 图文生成图片 wxml-to-canvas

    在做的小程序要增加一个将文字与图片生成图片不可修改的功能,第一次做,在网上找了不少资料。参考了wxml-to-canvas | 微信开放文档  ,又看了一些相关事例,尝试写了一下。   需要准备的文件及配置项: 1、先把代码片段下载到本地 2、创建wxcomponents目录,把代码片段中的

    2024年02月09日
    浏览(32)
  • 微信小程序canvas实现简易手写签名版(uni-app)

    微信小程序可以通过canvas实现手写签名的效果,本文中使用的是微信小程序Canvas 2D接口 本示例中绘制的是横屏签名的效果,效果图如下: 这里我们需要调整canvas的物理宽高,默认物理宽高为300*150px,物理宽高调整通过css样式即可,本文中需要根据屏幕高度进行动态调整,使

    2024年02月12日
    浏览(40)
  • uni-app 微信小程序中如何通过 canvas 画布实现电子签名?

    一、实际应用场景 电子签名软件应用场景:电子签名在金融、银行、贷款行业中可以用于对内日常办公流转的文档的盖章签字,对外涉及业务合作协议,采购合同,贷款申请、信用评估、贷款合同、贷款文件表、说明函等等。 可以说,只要是涉及纸质文档签字盖章的场景,

    2024年02月10日
    浏览(34)
  • 前端vue uni-app自定义精美海报生成组件

    在当前技术飞速发展的时代,软件开发的复杂度也在不断提高。传统的开发方式往往将一个系统做成整块应用,一个小的改动或者一个小功能的增加都可能引起整体逻辑的修改,从而造成牵一发而动全身的情况。为了解决这个问题,组件化开发逐渐成为了一种趋势。通过组件

    2024年02月14日
    浏览(41)
  • uni-app实现图片上传功能

    效果 代码  

    2024年02月13日
    浏览(37)
  • uni-app - 电子签字板组件(签名专用写字画板,支持调整写字板 “横纵“ 方向,可调整线条粗细颜色等,Canvas 绘制非常丝滑流畅)完美兼容 H5 APP 小程序,最好用的画板签字教程插件源码

    网上的教程代码非常乱且都有 BUG 存在,非常难移植到自己的项目中,本文代码干净整洁注释详细。 本文实现了 全端兼容,签名专用的写字板组件,真机流畅丝滑且无 BUG, 您直接复制组件源码,按照详细示例+超详细的注释轻松几分钟完成, 如下图 真机测试 ,您还可以通过

    2024年02月10日
    浏览(41)
  • uni-app 实现图片上传添加水印操作

    改进原因: 1、Canvas 2D(新接口)需要显式设置画布宽高,默认:300 150,最大:1365 1365 ios 无法上传较大图片的尺寸,固对超过此尺寸的图片进行了等比缩放的处理; 2、在页面中设置canvas宽高,导致页面有滚动条;现在采用离屏的canvas,但是离屏的canvas,canvasToTempFilePath方法

    2024年02月07日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包