小程序 canvas合成图片 保存到相册

文章目录

调用

const draw = await eyeCopyFun({
	cvs:this.cvs,
	bg:'#FFFFFF',
	canvasId:'poster',
	title:{
		title:'20元代金券',
		validity:'2021-04-05'
	},
	content:[
		{
			img:{
				width: 150,
				url:'https://weixin.hotapp.cn/src/home/img/qrcode_example.png',  // 只能
				type:'url' // base64/url(不能为本地图片)
			}, 
			code:'47387554894'
		},
		{
			img:{
				width: 150,
				base64:data.data.QRCode,
				type:'base64' 
			}, 
			code:'47387554894'
		},
		
		{
			img:{
				width: 150,
				base64:data.data.QRCode,
				type:'base64' 
			}, 
			code:'47387554894'
		}
	],
	footer:{
		title:'可用商家',
		name:'一屋子薯片韩式大头贴(上虞区店)'
	}
})
const path = await draw.getImg();
// 保存合成图片到相册
const save = await saveImgPhotosAlbum(path)		

// saveImgPhotosAlbum ===> https://blog.csdn.net/weixin_42448623/article/details/112365076

效果

在这里插入图片描述

eyeCopy.js

/**
 * eyeCopy.js
 * 通过合成图片
 */

import {removeSavedFile,downloadFile, writeFileBase64} from '@/common/saveImgAlbum.js'

class eyeCopy {
    constructor(data = {}) {
        this.data = data
		this.width = this.data.cvs.w
		this.height = this.data.cvs.h
        this.bg = this.data.bg
		this.ctx = uni.createCanvasContext(this.data.canvasId) 
        this.totalH = 0
		
		// this.draw()
		
		// 绘制图片 网络图片
		// const url = 'https://weixin.hotapp.cn/src/home/img/qrcode_example.png'
		// this.ctx.drawImage(url, (this.width - 150) / 2, 60, 150, 150) // yes
		// const base64 = content[0].img.base64
		// let fileName = new Date().valueOf();
		// const filePath = tt.env.USER_DATA_PATH + '/'+ fileName +'.png'
		// writeFileBase64(filePath,base64).then(async res=>{
		// 	console.log('写入成功')
		// 	const path = await downloadFile(filePath)
		// 	console.log('path',path)
		// 	this.ctx.drawImage(path, (this.width - 150) / 2, 60, 150, 150)
		// 	this.ctx.draw()
		// 	removeSavedFile(filePath)
		// })
    }

    async init(cabllack=()=>{}){
        await this.draw() // 第一遍绘制 获取高度
		console.log('绘制--1')
		this.setHeight()
		this.totalH = 0
		await this.draw()
		console.log('绘制--2')
    }
	
	delay(fun=()=>{}, delay=0){
		return new Promise((resolve, reject)=>{
			setTimeout(async ()=>{
				await fun()
				resolve()
			},delay)
		})
	}
	
    getImg(){
		return new Promise(async (resolve, reject) => {
			await this.delay(undefined, 500)
			const obj = {
				canvasId: this.data.canvasId,
				x:0,y:0,
				width: this.width,
				height: this.height,
				destWidth: this.width,
				destHeight: this.height	,
			}
			tt.canvasToTempFilePath({
				...obj,
				success(res) {
					console.log('res',res.tempFilePath)
					resolve(res.tempFilePath)
				},
				fail(err) {
					console.log('fail',err)
					reject(e)
				}
			})
		})
    }

    async reflesh(){
        this.setHeight()
        this.totalH = 0
        await this.draw()
    }

    async draw() {
		return new Promise(async (resolve, reject)=>{
			this.ctx.clearRect(0,0,this.width, this.height)
			this.ctx.beginPath()
			this.setBg()
			console.log('开始绘制--内容')
			const { title, content, footer } = this.data
			this.drawTitle(title)
			console.log('开始绘制--内容-content')
			await this.drawContent(content)
			console.log('开始绘制--内容-footer')
			this.drawFoot(footer)
			this.ctx.draw(false, function(){
				console.log('--绘制完成--')
				resolve()
			})
		})
    }

    drawTitle(data) {
        this.drawText({ text: data.title, mtop: 30, font: ['20', 'Arial'] })
        this.drawText({ text: '有效期至' + data.validity, mtop: 5 })
    }
	drawText(params) {
	    const {
	        font = ['13', 'Arial'],
	        align = 'center',
	        // color = 'black',
	        mtop,
	        text
	    } = params
		this.ctx.setFontSize(font[0])
		this.ctx.setTextAlign(align)
		this.ctx.fillText(text, this.width / 2, this.totalH + mtop)
		const h = parseInt(font[0])
		this.totalH += h + mtop
	}
    async drawContent(data) {
        for (let i = 0; i < data.length; i++) {
            const {img:{url,base64,width,height,type}, code} = data[i]
			let imgURL = url, filePath;
			if(type === 'base64'){
				console.log('base64Hadle')
				let h = await this.base64Hadle(base64)
				console.log('base64Hadle',h)
				imgURL = h.path
				filePath = h.filePath
			}
            await this.drawBlock({
                code,
                height, width,
                src: imgURL
            })
			if(type === 'base64'){
				// 清除临时图片
				removeSavedFile(filePath)
			}
        }
    }
    drawFoot(data) {
        this.drawText({ text: data.title, mtop: 25 })
        this.drawText({ text: data.name, mtop: 10 })
    }
	async base64Hadle(base64){
		let fileName = new Date().valueOf();
		const filePath = tt.env.USER_DATA_PATH + '/'+ fileName +'.png'
		await writeFileBase64(filePath,base64)
		console.log('临时文件存入',filePath)
		const path = await downloadFile(filePath)
		console.log('临时文件路径',path)
		
		// bug ttfile://user/1612418287735.png 不在配置的域名白名单中
		// 这里把base64上传到白名单的服务器 然后返回路径 
		// upTempImg 上传图片到服务器
		// 合成部分越多 请求次数越多  可以考虑后端合成
		const path = await upTempImg({base64})
		return {path,filePath}
	}
    async drawBlock(params) {
        const {
            width,
            height,
            src,
            code,
        } = params
        await this.drawImg({ src, width, height, mtop: 0 })
        this.drawText({ text: '券码:' + code, mtop: 15 })
    }

    setHeight(){
		this.height = this.totalH + 20
		this.data.cvs.h = this.totalH + 20
    }

    drawImg(params) {
        return new Promise(async (resolve, reject) => {
           try{
			   const {
			       mtop,
			       width,
			       height = width,
			       src
			   } = params
			   this.ctx.drawImage(src, (this.width - width) / 2, this.totalH + mtop, width, height)
			   this.totalH += mtop + height
			   resolve()
		   }catch(e){
			   reject(e)
		   }
        })
    }

    setBg(){
       this.ctx.save()
       this.ctx.setFillStyle(this.bg)
       this.ctx.fillRect(0,0, this.width, this.height)
       this.ctx.restore()
    }
}

export async function eyeCopyFun(params){
	const draw = new eyeCopy(params)
	await draw.init()
	
	return draw
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值