小程序图片加水印实现代码,带效果图

    技术2022-07-10  132

    效果图:

    本文有核心代码和完整代码,完整代码是上传用户的个人信息到云数据库,包括表单,图片上传,多图上传到云数据库。

    实现核心代码

    <view class="mg_bo"> <view class="text mg_bot">身份证正面照片: </view> <view class="text_">上传自动加水印</view> <view class="img_ img_2" mode="widthFix" bindtap="zhengmian_img" wx:if="{{zhengmian}}"> <image class="img" src="{{zhengmian}}"></image> </view> <image wx:else class="img_ img_2" mode="widthFix" bindtap="zhengmian_img" src="/img/zhengmian.jpg"></image> </view> <canvas style="width: {{imageWidth}}px; height: {{imageHeight}}px;visibility:hidden;" canvas-id="myCanvas"></canvas> zhengmian_img() { let that = this var ctx = wx.createCanvasContext('myCanvas') wx.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success(res) { //获取图片基本信息 wx.getImageInfo({ src: res.tempFilePaths[0], success: function (res) { var width = res.width var height = res.height //获取屏幕宽度 let screenWidth = wx.getSystemInfoSync().windowWidth //处理一下图片的宽高的比例 if (width >= height) { if (width > screenWidth) { width = screenWidth } height = height / res.width * width } else { if (width > screenWidth) { width = screenWidth } if (height > 400) { height = 400 width = res.width / res.height * height } else { height = height / res.width * width } } that.setData({ imageWidth: width, imageHeight: height, }) ctx.drawImage(res.path, 0, 0, width, height) ctx.rotate(20 * Math.PI / 180) for (let j = 1; j < 12; j++) { ctx.beginPath() ctx.setFontSize(14) ctx.setFillStyle('white') ctx.fillText('身份证水印', 0, 50 * j) for (let i = 1; i < 12; i++) { ctx.beginPath() ctx.setFontSize(14) ctx.setFillStyle('white') ctx.fillText("身份证水印", (15 + (14 - 1) * "身份证水印".length) * i, 50 * j) } } ctx.draw(false, () => { //生成图片 wx.canvasToTempFilePath({ canvasId: 'myCanvas', success: function (res) { console.log("canvas可以生成图片") console.log(res.tempFilePath, 'canvas图片地址'); // tempFilePath可以作为img标签的src属性显示图片 console.log('选择图片', res) const tempFilePaths = res.tempFilePath wx.cloud.uploadFile({ cloudPath: Date.parse(new Date()) + "", filePath: tempFilePaths, success: res => { console.log('上传成功', res) let imgUrl = res.fileID that.setData({ zhengmian: imgUrl }) }, fail: err => { console.log('上传失败', err) } }) } }) }) } }) } }) },

    实现完整页面代码:

    <form bindsubmit='formsubmit'> <view> <image class="top" mode="widthFix" src="/img/IMG1.png"></image> <view class="info"> <view> <view class="title">{{page_type?'信息填写':'编辑信息'}}</view> <block wx:for="{{list}}" wx:key="idx"> <view class="mg_bo"> <view class="text">{{item.text}}: <text style="color:red">*</text> </view> <view class="text_">{{item.text_}}</view> <input name="{{item.name}}" value="{{item.value}}" data-title="{{item.text}}" data-type='0'></input> </view> </block> </view> <view> <view class="title">以下信息对外公开,填写时注意保护身份证号码、住址等隐私信息</view> <view class="mg_bo"> <view class="text mg_bot">昵称: <text style="color:red">*</text> </view> <input name="nicheng" value="{{nicheng}}"></input> </view> <view class="mg_bo"> <view class="text mg_bot">单选: <text style="color:red">*</text> </view> <view class=""> <radio-group bindchange="radioChange" class="flexRow "> <view wx:for="{{sex_list}}" wx:key="idx" style="margin-right: 40rpx;" class="weui-cell__hd"> <radio value="{{item.name}}" checked="true" />{{item.name}} </view> </radio-group> </view> </view> <view class="mg_bo"> <view class="text mg_bot">封面头像: </view> <view class="text_">支持 jpg, png, gif, bmp, psd, tiff 等图片格式</view> <view class="img_" bindtap="hande_img" wx:if="{{hande}}"> <image class="img" src="{{hande}}"></image> </view> <view class="img_" bindtap="hande_img" wx:else>+ </view> </view> <view class="mg_bo"> <view class="text mg_bot">生活照片: </view> <view class="text_">支持 jpg, png, gif, bmp, psd, tiff 等图片格式(建议上传多张,不要过度美颜哦)</view> <view class="img_" bindtap="live_phone" wx:if="{{live_phone.length==0}}">+ </view> <block wx:else> <view class="img_" bindtap="live_phone" wx:for="{{live_phone}}"> <image class="img" src="{{item}}"></image> </view> </block> </view> <view class="mg_bo"> <view class="text mg_bot">身份证正面照片: </view> <view class="text_">上传自动加水印</view> <view class="img_ img_2" mode="widthFix" bindtap="zhengmian_img" wx:if="{{zhengmian}}"> <image class="img" src="{{zhengmian}}"></image> </view> <image wx:else class="img_ img_2" mode="widthFix" bindtap="zhengmian_img" src="/img/zhengmian.jpg"></image> </view> <view class="mg_bo"> <view class="text mg_bot">身份证反面照片: </view> <view class="text_">上传自动加水印</view> <view class="img_ img_2" bindtap="fanmian_img" wx:if="{{fanmian}}"> <image class="img" mode="widthFix" src="{{fanmian}}"></image> </view> <image wx:else class="img_ img_2" mode="widthFix" bindtap="fanmian_img" src="/img/fanmian.jpg"></image> </view> <view class="mg_bo"> <view class="text mg_bot">籍贯: </view> <picker mode="region" bindchange="bindRegionChange1" value="{{region1}}"> <view class="picker"> 当前选择:{{region1[0]}},{{region1[1]}},{{region1[2]}} </view> </picker> </view> <view class="mg_bo"> <view class="text mg_bot">所在地区: <view class="text_">同区域的小伙伴配对成功的概率大哦</view> </view> <picker mode="region" bindchange="bindRegionChange2" value="{{region2}}"> <view class="picker"> 当前选择:{{region2[0]}},{{region2[1]}},{{region2[2]}} </view> </picker> </view> <view class="itemaaaa"> <view class="mg_bo flexRow"> <view class="text">身高</view> <input name="shengao" value="{{shengao}}" class="bt_input"></input> <text>cm</text> </view> <view class="mg_bo flexRow"> <view class="text">体重</view> <input name="tizhong" value="{{tizhong}}" class="bt_input"></input> <text>kg</text> </view> <view class="mg_bo flexRow"> <view class="text">年龄</view> <input name="age" value="{{age}}" class="bt_input"></input> <text>岁</text> </view> <view class="mg_bo flexRow"> <view class="text">年薪</view> <input name="nianxing1" value="{{nianxing1}}" class="bt_input"></input> <text class="ganggang">-</text> <input name="nianxing2" value="{{nianxing2}}" class="bt_input"></input> <text>元</text> </view> <view class="mg_bo flexRow"> <view class="text">家庭成员</view> <input name="jtcy" value="{{jtcy}}" class="bt_input bt_input2"></input> </view> <view class="mg_bo " bindtap="xuli"> <view class="text">学历</view> <view class="da {{ xuli?'':'col'}}">{{xuli?xuli:'请选择'}}</view> </view> <view class="mg_bo " bindtap="ziyie"> <view class="text">职业</view> <view class="da {{ ziyie?'':'col'}}">{{ziyie?ziyie:'请选择'}}</view> </view> <view class="mg_bo " bindtap="car"> <view class="text">车子</view> <view class="da {{ car?'':'col'}}">{{car?car:'请选择'}}</view> </view> <view class="mg_bo " bindtap="house"> <view class="text">房子</view> <view class="da {{ house?'':'col'}}">{{house?house:'请选择'}}</view> </view> <view class="mg_bo " bindtap="love"> <view class="text">恋爱状态</view> <view class="da {{ love?'':'col'}}">{{love?love:'请选择'}}</view> </view> <view class="mg_bo"> <view> <view class="text mg_bot">你是怎么样的人 <text style="color:red">*</text> </view> <view class="text_">让对方对你有个简单的认识</view> <view class="text_">日常生活简介、会不会做饭?是不是颜值控?</view> <view class="text_">家庭情况、工作简介等等</view> <view class="text_">请输入200个字以上</view> <textarea name="nssmr" value="{{nssmr}}"></textarea> </view> </view> <view class="mg_bo"> <view> <view class="text mg_bot">平时的兴趣爱好 <text style="color:red">*</text> </view> <view class="text_">让对方对你有个简单的认识</view> <view class="text_">为匹配兴趣相近的小伙伴,请准确填写。可以填写上班时间喜欢做什么,下班时间喜欢做什么,节假日喜欢做什么.....等等</view> <view class="text_">请输入200个字以上</view> <textarea name="psdah" value="{{psdah}}"></textarea> </view> </view> <view class="mg_bo"> <view> <view class="text mg_bot">交友宣言 </view> <input name="jyxy" value="{{jyxy}}"></input> </view> </view> <view class="mg_bo"> <view> <view class="text mg_bot">你希望的TA是什么样子的? <text style="color:red">*</text> </view> <textarea name="nxwdt" value="{{nxwdt}}"></textarea> </view> </view> </view> </view> <button formType="submit">{{page_type?'提交':'下一步'}}</button> </view> </view> </form> <canvas style="width: {{imageWidth}}px; height: {{imageHeight}}px;visibility:hidden;" canvas-id="myCanvas"></canvas>

    js  

    //index.js var userInfo; const DB = wx.cloud.database() var util = require('../../utils/util.js') let that // var data{ // phoneNumber: '手机号码', // name: '姓名', // userNumber: '身份证号码', // wxNumber: '微信帐号', // shengao: '身高', // tizhong: '体重', // nssmr: '你是怎么样的人', // psdah: '平时的兴趣爱好', // jyxy: '交友宣言', // nxwdt: '你希望的TA是什么样子的?', // nicheng 昵称 // sex: '性别', // region1: '籍贯', // region2: '所在地区', // xuli: '学历', // ziyie: '职业', // car: '车子', // house: '房子', // love: '恋爱状态', // jtcy 家庭成员 // nianxing1 年薪 // nianxing2 年薪 // zhengmian 身份证正面 // fanmian_img 身份证反面 // } Page({ data: { page_type: wx.getStorageSync('userInfoDetail') ? false : true, list: [{ text: '手机号码', text_: '仅用于登记,不公开', name: 'phoneNumber', value: "" }, { text: '姓名', text_: '仅用于登记,不公开', name: 'name', value: "" }, { text: '身份证号码', text_: '仅作核实身份之用,不公开', name: 'userNumber', value: "" }, { text: '微信帐号', text_: '', name: 'wxNumber', value: "" }], region1: ['请选择', '请选择', '请选择'], region2: ['请选择', '请选择', '请选择'], sex: "男", customItem: '请选择', sex_list: [{ name: '男', checked: 'true', }, { name: '女', }, ], hande: "cloud://gezi-ofhmx.6765-gezi-ofhmx-1255880295/1593571997000", arr_list: [], live_phone: [], }, onLoad: function (option) { that = this console.log('--------') if (option.nav_type == "login") { this.setData({ nav_type: option.nav_type }) } try { if (wx.getStorageSync('userInfo')) { var list = this.data.list; var user = wx.getStorageSync('userInfo').userInfoDetail; console.log(list[0].value, user.phoneNumber) if (user.phoneNumber) { list[0].value = user.phoneNumber } if (user.name) list[1].value = user.name if (user.userNumber) list[2].value = user.userNumber if (user.wxNumber) list[3].value = user.wxNumber var sex_list = this.data.sex_list; var sex = "男"; if (user.age == 1) { sex_list[0].checked = true; sex_list[1].checked = false; sex = "男" } else { sex = "女" sex_list[0].checked = false; sex_list[1].checked = true; } console.log('-----------------', user) this.setData({ list, sex_list, sex, user, ...user }) } else { console.log('===========') } } catch (error) { console.log('====', error) } }, hande_img() { let that = this wx.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success(res) { // tempFilePath可以作为img标签的src属性显示图片 console.log('选择图片', res) const tempFilePaths = res.tempFilePaths[0] // 将图片上传至云存储空间 wx.cloud.uploadFile({ // 指定上传到的云路径 cloudPath: Date.parse(new Date()) + tempFilePaths[0], // 指定要上传的文件的小程序临时文件路径 filePath: tempFilePaths, // 成功回调 success: res => { console.log('上传成功', res) // 成功之后的图片地址 let imgUrl = res.fileID that.setData({ hande: imgUrl }) } }) } }) }, zhengmian_img() { let that = this var ctx = wx.createCanvasContext('myCanvas') wx.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success(res) { //获取图片基本信息 wx.getImageInfo({ src: res.tempFilePaths[0], success: function (res) { var width = res.width var height = res.height //获取屏幕宽度 let screenWidth = wx.getSystemInfoSync().windowWidth //处理一下图片的宽高的比例 if (width >= height) { if (width > screenWidth) { width = screenWidth } height = height / res.width * width } else { if (width > screenWidth) { width = screenWidth } if (height > 400) { height = 400 width = res.width / res.height * height } else { height = height / res.width * width } } that.setData({ imageWidth: width, imageHeight: height, }) ctx.drawImage(res.path, 0, 0, width, height) ctx.rotate(20 * Math.PI / 180) for (let j = 1; j < 12; j++) { ctx.beginPath() ctx.setFontSize(14) ctx.setFillStyle('white') ctx.fillText('身份证水印', 0, 50 * j) for (let i = 1; i < 12; i++) { ctx.beginPath() ctx.setFontSize(14) ctx.setFillStyle('white') ctx.fillText("身份证水印", (15 + (14 - 1) * "身份证水印".length) * i, 50 * j) } } ctx.draw(false, () => { //生成图片 wx.canvasToTempFilePath({ canvasId: 'myCanvas', success: function (res) { console.log("canvas可以生成图片") console.log(res.tempFilePath, 'canvas图片地址'); // tempFilePath可以作为img标签的src属性显示图片 console.log('选择图片', res) const tempFilePaths = res.tempFilePath wx.cloud.uploadFile({ cloudPath: Date.parse(new Date()) + "", filePath: tempFilePaths, success: res => { console.log('上传成功', res) let imgUrl = res.fileID that.setData({ zhengmian: imgUrl }) }, fail: err => { console.log('上传失败', err) } }) } }) }) } }) } }) }, fanmian_img() { let that = this var ctx = wx.createCanvasContext('myCanvas') wx.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success(res) { //获取图片基本信息 wx.getImageInfo({ src: res.tempFilePaths[0], success: function (res) { var width = res.width var height = res.height //获取屏幕宽度 let screenWidth = wx.getSystemInfoSync().windowWidth //处理一下图片的宽高的比例 if (width >= height) { if (width > screenWidth) { width = screenWidth } height = height / res.width * width } else { if (width > screenWidth) { width = screenWidth } if (height > 400) { height = 400 width = res.width / res.height * height } else { height = height / res.width * width } } that.setData({ imageWidth: width, imageHeight: height, }) ctx.drawImage(res.path, 0, 0, width, height) ctx.rotate(20 * Math.PI / 180) for (let j = 1; j < 12; j++) { ctx.beginPath() ctx.setFontSize(14) ctx.setFillStyle('white') ctx.fillText('身份证水印', 0, 50 * j) for (let i = 1; i < 12; i++) { ctx.beginPath() ctx.setFontSize(14) ctx.setFillStyle('white') ctx.fillText("身份证水印", (15 + (14 - 1) * "身份证水印".length) * i, 50 * j) } } ctx.draw(false, () => { //生成图片 wx.canvasToTempFilePath({ canvasId: 'myCanvas', success: function (res) { console.log("canvas可以生成图片") console.log(res.tempFilePath, 'canvas图片地址'); // tempFilePath可以作为img标签的src属性显示图片 console.log('选择图片', res) const tempFilePaths = res.tempFilePath wx.cloud.uploadFile({ cloudPath: Date.parse(new Date()) + "", filePath: tempFilePaths, success: res => { console.log('上传成功', res) let imgUrl = res.fileID that.setData({ fanmian: imgUrl }) }, fail: err => { console.log('上传失败', err) } }) } }) }) } }) } }) }, live_phone() { let that = this wx.chooseImage({ count: 9, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success(res) { // tempFilePath可以作为img标签的src属性显示图片 // console.log('选择图片', res) const tempFilePaths = res.tempFilePaths that.setData({ live_phone: [] }) let i = 0 for (i; i < tempFilePaths.length; i++) { // console.log(i, ':', tempFilePaths[i]) let url = tempFilePaths[i] // 将图片上传至云存储空间 wx.cloud.uploadFile({ // 指定上传到的云路径 cloudPath: Date.parse(new Date()) + i + '.png', // 指定要上传的文件的小程序临时文件路径 filePath: url, // 成功回调 success: res => { console.log('上传成功', res) // 成功之后的图片地址 let imgUrl = res.fileID let arr = [ imgUrl ] that.setData({ live_phone: that.data.live_phone.concat(arr) }) } }) } } }) }, formsubmit: function (e) { var that = this; var formData = e.detail.value; console.log('formData1', formData) if (this.data.hande) formData.hande = this.data.hande; if (this.data.live_phone) formData.live_phone = this.data.live_phone; if (this.data.sex) formData.sex = this.data.sex; if (this.data.region1) formData.region1 = this.data.region1[0] == "请选择" ? null : this.data.region1; if (this.data.region2) formData.region2 = this.data.region2[0] == "请选择" ? null : this.data.region2; if (this.data.xuli) formData.xuli = this.data.xuli; if (this.data.ziyie) formData.ziyie = this.data.ziyie; if (this.data.car) formData.car = this.data.car; if (this.data.house) formData.house = this.data.house; if (this.data.love) formData.love = this.data.love; console.log('formData2', formData) this.userAdd(formData) }, userAdd(formData) { if (this.data.user && this.data.user.hande) { formData.hande = this.data.user.hande } console.log(formData.name, formData.hande, formData.sex, formData.phoneNumber, formData.wxNumber, formData.userNumber) if (!formData.name || !formData.hande || !formData.sex || !formData.phoneNumber) { wx.showToast({ title: '请确认必填信息填写完整', icon: 'none' }) return } if (!util.IdentityCodeValid(formData.userNumber)) { wx.showToast({ title: '身份证信息错误', icon: 'none' }) return } if (!util.regPhone(formData.phoneNumber)) { wx.showToast({ title: '手机号错误', icon: 'none' }) return } wx.setStorageSync('userInfoDetail', formData); DB.collection('user').doc(wx.getStorageSync('userInfo')._id).update({ data: { userInfoDetail: formData } }) if (this.data.nav_type == "login") { console.log('11111111111111111111111111') wx.navigateTo({ url: '/pages/character_list/index', }) } else { console.log('2222222222222222222222222') wx.switchTab({ url: '/pages/find/index', }) } }, //省市区选择器: bindRegionChange1: function (e) { console.log('picker发送选择改变,携带值为', e.detail.value) this.setData({ region1: e.detail.value }) }, //省市区选择器: bindRegionChange2: function (e) { console.log('picker发送选择改变,携带值为', e.detail.value) this.setData({ region2: e.detail.value }) }, next() { wx.navigateTo({ url: '../character_list/index', success: function (res) {}, fail: function (res) {}, complete: function (res) {}, }) }, input(e) { console.log(e) let tite = e.currentTarget.dataset.title let type = e.currentTarget.dataset.type let text = e.detail.value let arr = { tite: tite, type: type, text: text } this.setData({ arr_list: this.data.arr_list.push(arr) }) }, radioChange(e) { this.setData({ sex: e.detail.value }) }, // 学历 xuli() { let list = ['研究生及以上', '本科', '专科及以下'] wx.showActionSheet({ itemList: list, itemColor: '', success: function (res) { console.log(res) that.setData({ xuli: list[res.tapIndex] }) }, fail: function (res) {}, complete: function (res) {}, }) }, // 职业 ziyie() { let list = ['企业员工', '公务员', '自由职业', '其他'] wx.showActionSheet({ itemList: list, itemColor: '', success: function (res) { that.setData({ ziyie: list[res.tapIndex] }) }, fail: function (res) {}, complete: function (res) {}, }) }, //车 car() { let list = ['自己名下有车全款', '自己名下有车贷款', '没车', '家里有车'] wx.showActionSheet({ itemList: list, itemColor: '', success: function (res) { that.setData({ car: list[res.tapIndex] }) }, fail: function (res) {}, complete: function (res) {}, }) }, // 房 house() { let list = ['自己名下有房全款', '自己名下有房贷款', '没房', '家里有房'] wx.showActionSheet({ itemList: list, itemColor: '', success: function (res) { that.setData({ house: list[res.tapIndex] }) }, fail: function (res) {}, complete: function (res) {}, }) }, // 恋爱状态 love() { let list = ['未恋爱过', '恋爱分手一年内', '恋爱分手多年', '离异自己带子女', '离异无子女', '离异对方带子女'] wx.showActionSheet({ itemList: list, itemColor: '', success: function (res) { that.setData({ love: list[res.tapIndex] }) }, fail: function (res) {}, complete: function (res) {}, }) } })

    css

    .title { width: 100%; text-align: center; font-size: 36rpx; font-weight: 800; } radio{ } .top{ width: 100%; min-height: 200rpx; } .info{ padding: 30rpx; } .itemaaaa .text{ margin-top: 10rpx; } .itemaaaa input{ position: relative; top: -20rpx; } .itemaaaa .mg_bo{ display: flex; flex-direction: row; } .mg_bo{ margin: 20rpx; /* border-bottom: 1rpx solid #ccc; */ padding-bottom: 40rpx } .text { font-size: 32rpx; color: #233144; } .text_ { font-size: 22rpx; color: rgba(111, 111, 112, 0.89); } input{ width: 90%; border-bottom: 1rpx solid #ccc; margin-left: 5%; margin-top: 10rpx; padding: 10rpx } .flexRow{ display: flex; flex-direction: row } .mg_bot{ margin-bottom: 20rpx; } label{ flex: 1; text-align: center } .img_{ width: 300rpx; height: 300rpx; text-align: center; line-height: 300rpx; border: 1rpx solid #ccc; background: rgb(228, 228, 228); font-size: 100rpx; color: #fff; /* margin-left: 200rpx; */ margin-top: 20rpx } .img_2{ width: 500rpx; } .img_ .img{ width: 100%; height: 100%; } .map_bo{ width: 100% } .map_bo view{ flex: 1; text-align: center } .bt_input{ width: 100rpx } .bt_input2{ width: 300rpx; } .ganggang{ width: 100rpx; text-align: center; margin-right: -5%; } .da{ margin-left: 100rpx; padding-top: 10rpx; } .col{ color: #757575 } textarea{ width: 600rpx; border: 1rpx solid #ccc; margin-top: 10rpx; padding: 20rpx } .next{ margin: 100rpx; background: #0778fa; color: #fff; line-height: 80rpx; text-align: center;border-radius: 16rpx }

     

    Processed: 0.011, SQL: 9