??页面有三部分的图片。logo。二维码和背景图。其中背景图是本地的。
logo和二维码是接口给的。
像这样的海报合成的例子我写过一篇,是在vue的项目中的vue把几张图片logo。二维码。背景合成一个海报并下载,使用canvas
但是小程序里面不支持使用var img=new Image();??? 他会有这个文章里面的报错。
?//把网络图片改成本地图片 ?????????? getNetworkImage(url) { ??????????????? return new Promise((resolve, reject) => { ??????????????????? uni.downloadFile({ ??????????????????????? url, ??????????????????????? success: (e) => { ??????????????????????????? const p = e.tempFilePath ??????????????????????????? if (p.indexOf('json') > -1) { ??????????????????????????????? reject(p) ??????????????????????????????? return false ??????????????????????????? } ??????????????????????????? resolve(p) ??????????????????????? }, ??????????????????????? fail: (r) => { ??????????????????????????? reject(r) ??????????????????????? } ??????????????????? }) ??????????????? }) ??????????? }, ?? ??? ??? ?//把base64图片转为本地图片 ?? ??? ??? ?base64ToSave(base64data, FILE_BASE_NAME = 'tmp_base64src') { ?? ??? ??? ??? ?const fsm = uni.getFileSystemManager(); ?? ??? ??? ??? ?return new Promise((resolve, reject) => { ?? ??? ??? ??? ??? ?//format这个跟base64数据的开头对应 ?? ??? ??? ??? ??? ?const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || []; ?? ??? ??? ??? ??? ?if (!format) { ?? ??? ??? ??? ??? ??? ?reject(new Error('ERROR_BASE64SRC_PARSE')); ?? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ?const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`; ?? ??? ??? ??? ??? ?const buffer = wx.base64ToArrayBuffer(bodyData); ?? ??? ??? ??? ??? ?fsm.writeFile({ ?? ??? ??? ??? ??? ??? ?filePath, ?? ??? ??? ??? ??? ??? ?data: buffer, ?? ??? ??? ??? ??? ??? ?encoding: 'binary', ?? ??? ??? ??? ??? ??? ?success() { ?? ??? ??? ??? ??? ??? ??? ?resolve(filePath); ?? ??? ??? ??? ??? ??? ?}, ?? ??? ??? ??? ??? ??? ?fail() { ?? ??? ??? ??? ??? ??? ??? ?reject(new Error('ERROR_BASE64SRC_WRITE')); ?? ??? ??? ??? ??? ??? ?}, ?? ??? ??? ??? ??? ?}); ?? ??? ??? ??? ?}); ?? ??? ??? ?},
?我的二维码和logo都是接口传的数据。这里都转为本地的。
?genQrFile1() { ?? ??? ??? ??? ?var urlQR = this.base64ToSave(this.qrBase64);//二维码。base64转为本地图片 ?? ??? ??? ??? ?var logo=this.getNetworkImage(this.userinfo.logo1);//机构logo网络图片转为本地图片 ?? ??? ??? ??? ?let that = this; ?? ??? ??? ??? ?Promise.all([ ?? ??? ??? ??? ??? ?urlQR,logo ?? ??? ??? ??? ?]).then(res => {?? ??? ??? ??? ??? ? ?? ??? ??? ??? ??? ?that.qrUrl=res[0]?? ??? ??? ??? ??? ? ?? ??? ??? ??? ??? ?let ctx = uni.createCanvasContext('firstCanvas', this); ?? ??? ??? ??? ??? ?ctx.drawImage("/pages_student/static/images/posterbg1.png", 0, 0, 375, 812); ?? ??? ??? ??? ??? ?ctx.drawImage(res[1],? 36, 25,80, 60); ?? ??? ??? ??? ??? ?ctx.drawImage(res[0], 201.5 / 2.0, 1098.67 / 2, ?? ??? ??? ??? ??? ??? ?347.0 / 2.0, 347.0 / 2.0); ?? ??? ??? ??? ??? ??? ? ?? ??? ??? ??? ??? ?ctx.draw(false, () => { ?? ??? ??? ??? ??? ??? ?uni.canvasToTempFilePath({ ?? ??? ??? ??? ??? ??? ??? ?x: 0, ?? ??? ??? ??? ??? ??? ??? ?y: 0, ?? ??? ??? ??? ??? ??? ??? ?width: 375, ?? ??? ??? ??? ??? ??? ??? ?height: 812, ?? ??? ??? ??? ??? ??? ??? ?destWidth: 375 * 2, ?? ??? ??? ??? ??? ??? ??? ?destHeight: 812 * 2, ?? ??? ??? ??? ??? ??? ??? ?canvasId: 'firstCanvas', ?? ??? ??? ??? ??? ??? ??? ?success: function(res) { ?? ??? ??? ??? ??? ??? ??? ??? ?uni.getFileSystemManager().readFile({ ?? ??? ??? ??? ??? ??? ??? ??? ??? ?filePath: res.tempFilePath, ?? ??? ??? ??? ??? ??? ??? ??? ??? ?encoding: 'base64', ?? ??? ??? ??? ??? ??? ??? ??? ??? ?success: r => { ?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?that.wholeBase64 = "data:image/jpg;base64," + r.data;?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ? ?? ??? ??? ??? ??? ??? ??? ??? ??? ?}?? ??? ? ?? ??? ??? ??? ??? ??? ??? ??? ?}) ?? ??? ??? ??? ??? ??? ??? ??? ? ?? ??? ??? ??? ??? ??? ??? ??? ?that.imgurl = res.tempFilePath ?? ??? ??? ??? ??? ??? ??? ?}, ?? ??? ??? ??? ??? ??? ??? ?fail(e) { ?? ??? ??? ? ?? ??? ??? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ??? ?}); ?? ??? ??? ??? ??? ?}); ?? ??? ??? ??? ?}) ?? ??? ??? ?},
主要代码是上面的部分。下面贴一下全部的代码:保存合成海报保存到相册
<template>
<view class="container">
<scroll-view scroll-y="true" class="scroll-view" v-if=!isShowShare>
<image @click="cancel()" class="back-btn" src="../static/images/back_btn.png" mode="aspectFit"></image>
<!-- //多机构 -->
<template v-if="notDw">
<image class="bg-set" src="https://ossvvwx.heebu.cn/public/growplan/mini/common/poster_bg1.png" ></image>
<image class="logo" :src="userinfo.logo1" mode="widthFix"></image>
</template>
<!-- 多维 -->
<template v-else>
<image class="bg-set" src="https://ossvvwx.heebu.cn/public/growplan/mini/common/poster_bg.png"></image>
</template>
<view class="bottom-qr">
<image class="image" src="/pages_student/static/images/poster_qr.png"></image>
<view class="center">
<text class="test-qr">测评二维码 </text>
</view>
<view class="center">
<image show-menu-by-longpress="true" class="qr-image" :src=qrUrl></image>
</view>
<view class="center">
<text class="share-mid-tips">扫一扫二维码,了解自己的学习潜力 </text>
</view>
<view class="center">
<view class="share-class" @click="share">去分享</view>
</view>
<view class="center">
<view class="cancel-class" @click="cancel">取消</view>
</view>
</view>
</scroll-view>
<view class="wrapper" style="position: fixed;left: 1000rpx;"><canvas style="height: 1624rpx ;width:750rpx; backgroundColor: #FFFFFF;z-index: -100;"
canvas-id="firstCanvas">
</canvas>
</view>
<view v-if=isShowShare style=" ">
<view class="share-whole">
<view class="top-image center">
<image mode='widthFix' show-menu-by-longpress="true" class="share-class"
:src=imgurl></image>
</view>
<view class="top-image" style="background-color: #EBF7FF;height: 200rpx;">
</view>
<view class="share-bottom">
<view class="share-top">
<view class="item" @click="showShareQr">
<image class="item-image" src="/pages_student/static/images/wechat.png"></image>
<text class="title">微信 </text>
<!-- <button open-type="share" plain=true class="share" style=""></button> -->
</view>
<view class="item" @click="saveToAlbum">
<image class="item-image" src="/pages_student/static/images/save.png"></image>
<text class="title">保存到相册 </text>
</view>
</view>
<view class="line">
</view>
<view class="share-cancel" @click="cancelClick">
<text style="">取消
</text>
</view>
</view>
</view>
</view>
<luPopupWrapper ref="luPopupWrapper" :type="type" :transition="transition" :backgroundColor="backgroundColor" :active="active"
:height="height" :width="width" :popupId="popupId" :maskShow="maskShow" :maskClick="maskClick" :closeCallback="closeCallback">
<view class="long-press">
<view class="center">
<view class="center top">
<image class="top-image" show-menu-by-longpress="true" :src='imgurl' mode='scaleToFill' style="width: 395rpx;height: 833rpx;"></image>
</view>
</view>
<view class="center">
<image class="tips" src="/pages_student/static/images/student_long_press.png"></image>
</view>
<view class="center" @click="dismissPopup">
<image class="close" src="/pages_student/static/images/student_close.png"></image>
</view>
</view>
</luPopupWrapper>
</view>
</template>
<script>
import luPopupWrapper from "../components/lu-popup-wrapper/lu-popup-wrapper.vue";
import useLocalStorage from '@/utils/useLocalStorage';
const storage = useLocalStorage()
import {
mapMutations,
mapState,
} from 'vuex'
export default {
components: {
luPopupWrapper
},
computed: {
...mapState({
zoneinfo: s => s.zoneinfo,
userinfo: s => s.userinfo,
isDW: s => s.isDW
}),
},
data() {
return {
type: "bottom", // left right top bottom center
transition: "slider", //none slider fade
backgroundColor: '#FFF0',
active: true,
height: "100%",
width: "100%",
popupId: 1,
maskShow: true,
maskClick: true,
qrUrl: '',
qrBase64: "data:image/jpg;base64,",
imgurl: '',
isShowShare: false,
wholeBase64: "",
notDw:false,//不是多维
}
},
onLoad() {
this.getQrData();
this.notDw=this.isDW=="false"?true:false;
},
methods: {
//多维生成海报
genQrFile() {
var urlQR = this.base64ToSave(this.qrBase64)
let that = this;
Promise.all([
urlQR
]).then(res => {
that.qrUrl=res[0]
let ctx = uni.createCanvasContext('firstCanvas', this);
ctx.drawImage("/pages_student/static/images/posterbg.png", 0, 0, 375, 812);
ctx.drawImage(res[0], 201.5 / 2.0, 1098.67 / 2,
347.0 / 2.0, 347.0 / 2.0);
ctx.draw(false, () => {
uni.canvasToTempFilePath({
x: 0,
y: 0,
width: 375,
height: 812,
destWidth: 375 * 2,
destHeight: 812 * 2,
canvasId: 'firstCanvas',
success: function(res) {
uni.getFileSystemManager().readFile({
filePath: res.tempFilePath,
encoding: 'base64',
success: r => {
that.wholeBase64 = "data:image/jpg;base64," + r.data
}
})
that.imgurl = res.tempFilePath
},
fail(e) {
}
});
});
})
},
//多机构生成海报
genQrFile1() {
var urlQR = this.base64ToSave(this.qrBase64);//二维码。base64转为本地图片
var logo=this.getNetworkImage(this.userinfo.logo1);//机构logo网络图片转为本地图片
let that = this;
Promise.all([
urlQR,logo
]).then(res => {
that.qrUrl=res[0]
let ctx = uni.createCanvasContext('firstCanvas', this);
ctx.drawImage("/pages_student/static/images/posterbg1.png", 0, 0, 375, 812);
ctx.drawImage(res[1], 36, 25,80, 60);
ctx.drawImage(res[0], 201.5 / 2.0, 1098.67 / 2,
347.0 / 2.0, 347.0 / 2.0);
ctx.draw(false, () => {
uni.canvasToTempFilePath({
x: 0,
y: 0,
width: 375,
height: 812,
destWidth: 375 * 2,
destHeight: 812 * 2,
canvasId: 'firstCanvas',
success: function(res) {
uni.getFileSystemManager().readFile({
filePath: res.tempFilePath,
encoding: 'base64',
success: r => {
that.wholeBase64 = "data:image/jpg;base64," + r.data;
}
})
that.imgurl = res.tempFilePath
},
fail(e) {
}
});
});
})
},
//返回上一页
cancel() {
uni.navigateBack({});
},
genAndShare(type) {
if (this.imgurl) {
if (type === "save") {
uni.saveImageToPhotosAlbum({
filePath: this.imgurl,
success: function() {
uni.showToast({
title: '保存成功',
icon: 'none'
});
}
});
}
}
},
saveToAlbum() {
this.genAndShare("save")
},
//把网络图片改成本地图片
getNetworkImage(url) {
return new Promise((resolve, reject) => {
uni.downloadFile({
url,
success: (e) => {
const p = e.tempFilePath
if (p.indexOf('json') > -1) {
reject(p)
return false
}
resolve(p)
},
fail: (r) => {
reject(r)
}
})
})
},
//把base64图片转为本地图片
base64ToSave(base64data, FILE_BASE_NAME = 'tmp_base64src') {
const fsm = uni.getFileSystemManager();
return new Promise((resolve, reject) => {
//format这个跟base64数据的开头对应
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || [];
if (!format) {
reject(new Error('ERROR_BASE64SRC_PARSE'));
}
const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`;
const buffer = wx.base64ToArrayBuffer(bodyData);
fsm.writeFile({
filePath,
data: buffer,
encoding: 'binary',
success() {
resolve(filePath);
},
fail() {
reject(new Error('ERROR_BASE64SRC_WRITE'));
},
});
});
},
// 获取二维码
async getQrData() {
this.$loading.show()
let para = {
"teacherid": storage.getItem('token'),
"zoneid": this.userinfo.zoneid,
"size": "240",
'type': this.isDW == 'true' ? 1 : 2
};
const {
data
} = await this.$http.fromteacherqrcode(para);
this.$loading.hide()
if (data.code == 1) {
this.qrBase64 += data.data
if(this.notDw){//是否是多维。获取canvas海报图片
this.genQrFile1();
}else{
this.genQrFile();
}
}
},
share() {
this.isShowShare = true;
},
showShareQr() {
this.$refs.luPopupWrapper.show();
},
cancelClick() {
this.isShowShare = false;
},
dismissPopup() {
this.$refs.luPopupWrapper.close()
}
}
}
</script>
<style lang="scss" scoped>
.container {
.back-btn {
position: fixed;
top: 80rpx;
left: 20rpx;
width: 78rpx;
height: 60rpx;
z-index: 999;
}
.scroll-view{
position:relative;
}
.logo{
position:absolute;
width: 160rpx;
top: 80rpx;
left:60rpx;
display:block;
}
.long-press {
width: 750rpx;
height: 1757rpx;
.center {
display: flex;
justify-content: center;
}
.top {
background-color: #21A3FE;
border-radius: 20rpx;
bottom: 206rpx;
position: fixed;
}
.top-image {
width: 500rpx !important;
height: 1083rpx !important;
border-radius: 20rpx;
top: 60rpx;
}
.close {
width: 55rpx;
height: 55rpx;
bottom: 60rpx;
position: fixed;
}
.tips {
width: 518rpx;
height: 81rpx;
bottom: 139rpx;
position: fixed;
}
}
.bg-set {
width: 750rpx;
height: 1757rpx;
top: 0;
left: 0;
z-index: -1;
}
.bottom-qr {
.image {
width: 674rpx;
height: 804rpx;
}
left:36.7rpx;
position: absolute;
bottom: 0rpx;
.share-mid-tips {
text-align: center;
font-size: 27rpx;
font-family: PingFang SC;
font-weight: bold;
color: #757575;
line-height: 27rpx;
margin-top: -256rpx;
position: absolute;
}
.qr-image {
width: 366rpx;
height: 366rpx;
margin-top: -633.6rpx;
}
.test-qr {
width: 276rpx;
height: 56rpx;
background: #1BA0FE;
border-radius: 18rpx;
margin-top: -716rpx;
position: absolute;
text-align: center;
font-size: 29rpx;
font-family: Source Han Sans CN;
font-weight: bold;
color: #FFFFFF;
line-height: 56rpx;
}
.center {
display: flex;
justify-content: center;
}
.share-class {
width: 426.6rpx;
height: 60rpx;
line-height: 60rpx;
border: 4rpx solid #1BA0FE;
border-radius: 45rpx;
margin-top: -189rpx;
position: absolute;
text-align: center;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: bold;
color: #1BA0FE;
}
.cancel-class {
width: 426.6rpx;
height: 60rpx;
line-height: 60rpx;
border: 4rpx solid #BAC2C8;
border-radius: 45rpx;
margin-top: -106rpx;
position: absolute;
text-align: center;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: bold;
color: #BAC2C8;
}
}
.share-whole {
text-align: center;
width: 100%;
height: 100%;
background-color: #EBF7FF;
.top-image {
width: 100%;
display: flex;
justify-content: center;
}
.share-class{
width: 500rpx;height: 1082.67rpx;margin-top: 117rpx;
}
.share-cancel {
width: 100%;
font-size: 28rpx;
font-family: PingFang SC;
font-weight: bold;
color: #91979C;
// position: absolute;
// bottom: 0;
height: 127.34rpx;
line-height: 127.34rpx;
}
.line {
width: 100%;
border-bottom: 1px solid #F2F2F2;
margin-top: 28rpx;
// margin-bottom: 40px;
}
.share-bottom {
height: 375rpx;
background-color: #FfFFFF;
position: fixed;
bottom: 0rpx;
width: 100%;
border-radius: 20rpx 20rpx 0rpx 0rpx;
}
.share-top {
// margin-bottom: 50rpx;
width: 100%;
display: flex;
justify-content: space-around;
flex-direction: row;
align-items: center;
height: 213rpx;
border-radius: 20rpx 20rpx 0rpx 0rpx;
.item {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: transparent;
border: 0rpx;
border-radius: 0rpx;
margin-top: 50rpx;
.share {
position: absolute;
width: 30%;
height: 40%;
border: 0rpx;
}
.title {
margin-top: 26.6rpx;
font-size: 24rpx;
font-family: PingFang SC;
font-weight: bold;
color: #989898;
}
.item-image {
width: 86.67rpx;
height: 86.67rpx;
}
}
}
}
}
</style>
?
|