怎么在小程序中实现保存图片组件功能
這篇文章主要講解了“怎么在小程序中實現保存圖片組件功能”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么在小程序中實現保存圖片組件功能”吧!
思路
首先聲明下組件采用的是uniapp,具體實現了可以繪制圖片、繪制文字以及保存海報至相冊的基本功能,在開發中這些也完全夠用了。
通過canvas繪制海報。通過uni.canvasToTempFilePath 將繪制好的 canvas轉為圖片。通過uni.saveImageToPhotosAlbum 將本地臨時路徑的圖片保存至手機相冊中。而我的想法是將所有采用的方法全部封裝到組件中,只通過父組件去調用需要使用的方法和調整相關的參數即可。 具體使用可以查看示例代碼
通過canvas繪制海報內容的順序先后問題
通過使用promise對象決定繪制海報內容的順序先后。promise.all()方法進行canvas最后一步的繪畫操作 context.draw()
注意uni.getImageInfo()
-
在繪制圖片 和 頭像時,組件通過
uni.getImageInfo()去獲取圖片的相關信息,調用該方法成功的前提是需要在微信小程序后臺配置download域名和request域名當然最好把uploadFile域名也一起配置,防止出差錯。但是官方給出的提示是配置download域名白名單即可,但是獲取不到圖片信息,這算是一個大坑了。 -
如果沒有進行相關配置,在調試時 或者 體驗版 正式版等 打開了vconsole調試工具。uni.getImageInfo() 是可以獲取到圖片信息的,一旦關閉了vconsole uni.getImageInfo() 將會fail, 也是個坑。
本組件方法,變量介紹
props
-
canvasInfo Object (必需)
-
canvasWidth 畫布寬度
-
canvasHeight 畫布高度
-
canvasId 畫布標識
-
isFullScreen Boolean
-
為ture時表示畫布為手機屏幕全屏,canvasInfo設置的寬高將失效。
-
默認為 false
methods
-
canvasInit(callback) canvas初始化,所有有關畫布canvas操作需在其回調函數操作。
-
drawCanvasImage(context, src, _imageWidth, _imageHeight, dx, dy) 在canvas繪制一張圖片
-
drawCircularAvatar(context, url, _circularX, _circularY, _circularR) 在canvas繪制一張圓形圖片
-
drawText(options) 在canvas繪制單行、多行文本
-
startDrawToImage(context, promiseArr, callback) 將canvas操作draw()進行繪制
-
posterToPhotosAlbum(filePath) 保存至手機相冊
示例代碼
<template>
<view>
<viewclass="savePosterItem">
<imagev-show="tempFilePath":src="tempFilePath"></image>
<save-poster-comv-show="!tempFilePath"ref="savePoster":canvasInfo="canvasInfo"></save-poster-com>
</view>
<buttonclass="savePosterBtn"type="primary"@click="saveBtnFun">保存海報</button>
</view>
</template>
<script>
importSavePosterComfrom'@/components/SavePosterCom/SavePosterCom.vue'
exportdefault{
components:{
SavePosterCom
},
data(){
return{
canvasInfo:{
canvasWidth:620,
canvasHeight:950,
canvasId:'save-poster'
},
tempFilePath:'',
canvasBgUrl:'https://images.pexels.com/photos/4065617/pexels-photo-4065617.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500',
avatarUrl:'https://p9-passport.byteacctimg.com/img/user-avatar/4dbf31fa6dec9c65b78a70d28d843c04~300x300.image'
}
},
onLoad(){
let{
drawCanvasImage,
drawCircularAvatar,
drawText
}=this.$refs.savePoster.$options.methods
this.$refs.savePoster.canvasInit(({
context,
comThis
})=>{
//獲取畫布寬高
letcanvasWH=comThis.canvasWH
//繪制海報背景圖
letpromise_1=drawCanvasImage(context,this.canvasBgUrl,canvasWH.canvasWidth,canvasWH.canvasHeight)
//必須先繪制玩海報背景圖再去操作其他繪制內容
promise_1.then(res=>{
letpromise_2=drawCircularAvatar(context,this.avatarUrl,canvasWH.canvasWidth/2,canvasWH.canvasHeight/
7,70)
letpromise_3=drawText({
context:context,
text:'皮皮蝦仁',
dx:(canvasWH.canvasWidth/2)+60,
dy:canvasWH.canvasHeight/4,
fontSize:30,
fontColor:'#5D4037'
})
letpromise_4=drawCanvasImage(context,this.avatarUrl,150,150,(canvasWH.canvasWidth/2)+85,(canvasWH.canvasHeight-
165))
this.$refs.savePoster.startDrawToImage(context,[promise_1,promise_2,promise_4],(tempFilePath)=>{
this.tempFilePath=tempFilePath
})
})
})
},
methods:{
saveBtnFun(){
uni.showModal({
title:'保存海報',
content:'海報將被保存至相冊中',
confirmText:'保存',
success:(res)=>{
if(res.confirm){
this.$refs.savePoster.posterToPhotosAlbum(this.tempFilePath)
}
}
})
}
}
}
</script>
<style>
.savePosterItem{
text-align:center;
}
.savePosterItem>image{
width:620rpx;
height:950rpx;
}
.savePosterBtn{
margin-top:40rpx;
width:80%;
}
</style>
組件源碼
<template>
<view>
<canvas:canvas-id="canvasInfo.canvasId":style="{width:canvasWH.canvasWidth+'px',height:canvasWH.canvasHeight+'px'}"></canvas>
</view>
</template>
<script>
exportdefault{
name:'savePosterCom',
data(){
return{
userPhoneWHInfo:{},
canvasWH:{
canvasWidth:0,
canvasHeight:0
}
}
},
props:{
//決定保存下來的圖片的寬高
canvasInfo:{
type:Object,
default:()=>{
return{
canvasWidth:0,
canvasHeight:0,
canvasId:'canvasId'
}
}
},
//canvas畫布是不是全屏,默認是false。false時使用必須傳canvasInfo
isFullScreen:Boolean
},
created(){
this.userPhoneWHInfo=this.getPhoneSystemInfo()
if(this.isFullScreen){//畫布全屏
this.canvasWH.canvasWidth=this.userPhoneWHInfo.windowWidth
this.canvasWH.canvasHeight=this.userPhoneWHInfo.windowHeight
}else{//指定寬高
this.canvasWH.canvasWidth=this.canvasInfo.canvasWidth
this.canvasWH.canvasHeight=this.canvasInfo.canvasHeight
}
},
mounted(){},
methods:{
/**
*獲取用戶手機屏幕信息
*/
getPhoneSystemInfo(){
constres=uni.getSystemInfoSync();
return{
windowWidth:res.windowWidth,
windowHeight:res.windowHeight
}
},
/**獲取CanvasContext實例
*@param{String}canvasId
*/
getCanvasContextInit(canvasId){
returnuni.createCanvasContext(canvasId,this)
},
/**保存海報組件初始化
*@param{Function}callback(context)回調函數
*/
canvasInit(callback){
letcontext=this.getCanvasContextInit(this.canvasInfo.canvasId)
if(context){
callback({
context:context,
comThis:this
})
}
},
/**將上訴的繪制畫到畫布中并且將畫布導出為圖片
*@paramcontext畫布
*@param{Promise[]}存放Promise的數組
*@param{Function}callback保存圖片后執行的回調函數(本地圖片臨時路徑)
*/
startDrawToImage(context,promiseArr,callback){
//將之前在繪圖上下文中的描述(路徑、變形、樣式)畫到canvas中
letcanvasId=this.canvasInfo.canvasId
lettempFilePath=''
Promise.all(promiseArr).then(res=>{
context.draw(false,async()=>{
callback(awaitthis.canvasToImage(canvasId))
})
})
},
/**
*在canvas繪制一張圖片
*@paramcontext畫布
*@paramsrc圖片資源
*@param_imageWidth圖片寬度
*@param_imageHeight圖片高度
*/
drawCanvasImage(context,src,_imageWidth,_imageHeight,dx,dy){
returnnewPromise((resolve,reject)=>{
uni.getImageInfo({
src:src,
success:res=>{
context.drawImage(res.path,(dx-_imageWidth),(dy-_imageHeight),_imageWidth,_imageHeight)
resolve(context)
},
})
})
},
/**繪制一個圓形頭像
*@paramcontext畫布
*@paramurl圖片地址
*@param_circularX圓心X坐標
*@param_circularY圓心Y坐標
*@param_circularR圓半徑
*/
drawCircularAvatar(context,url,_circularX,_circularY,_circularR){
letdx=_circularX-_circularR;
letdy=_circularY-_circularR;
letdwidth=_circularR*2;
letdheight=_circularR*2
returnnewPromise((resolve,reject)=>{
uni.downloadFile({
url:url,
success:res=>{
context.save()
context.beginPath()
//_circularX圓的x坐標_circularY圓的y坐標_circularR圓的半徑
context.arc(_circularX,_circularY,_circularR,0,2*Math.PI)
context.clip()
//dx:圖像的左上角在目標canvas上X軸的位置
//dy:圖像的左上角在目標canvas上Y軸的位置
//dwidth:在目標畫布上繪制圖像的寬度,允許對繪制的圖像進行縮放
//dheight:在目標畫布上繪制圖像的高度,允許對繪制的圖像進行縮放
context.drawImage(res.tempFilePath,dx,dy,dwidth,dheight)
context.restore()
//context.draw()
resolve(context)
}
})
})
},
/**繪制多行文本注:,和空格都算一個字
*@paramcontext畫布
*@paramtext需要被繪制的文本
*@paramdx左上角x坐標
*@paramdy右上角y坐標
*@paramrowStrnum每行多少個字(默認為text字體個數->單行)
*@paramfontSize文字大小(默認16)
*@paramfontColor文字顏色(默認black)
*@paramlineHeight單行文本行高(默認0)
*/
drawText(options){
let{
context,
text,
dx,
dy,
rowStrnum=text.length,
lineHeight=0,
fontSize=16,
fontColor='black'
}=options
returnnewPromise((resolve,reject)=>{
context.setFontSize(fontSize)
context.setFillStyle(fontColor)
context.setTextBaseline('middle')
//獲取需要繪制的文本寬度
lettextWidth=Number(context.measureText(text).width)
//console.log('textWidth',textWidth)
//獲取文本的字數
lettextNum=text.length
//獲取行數向上取整
letlineNum=Math.ceil(textNum/rowStrnum)
//console.log('textNum',textNum)
//console.log('lineNum',lineNum)
for(leti=0;i<lineNum;i++){
letsliceText=text.slice(i*rowStrnum,(i+1)*rowStrnum)
//fillText的dx=文字最左邊的距離到屏幕政策的距離
context.fillText(sliceText,dx-textWidth,dy+i*lineHeight);
}
resolve(context)
})
},
/**將畫布導出為圖片
*@paramcanvasId畫布標識
*/
canvasToImage(canvasId){
returnnewPromise((resolve,reject)=>{
uni.canvasToTempFilePath({
canvasId:canvasId,//畫布標識
success:res=>{
//在H5平臺下,tempFilePath為base64
resolve(res.tempFilePath)
},
fail:err=>{
console.log('err',err)
reject(err)
}
},this)
})
},
/**保存生成的圖片到本地相冊中
*@param{String}filePath圖片臨時路勁
*/
posterToPhotosAlbum(filePath){
console.log('filePath',filePath)
uni.showLoading({
title:'保存中...'
})
uni.saveImageToPhotosAlbum({
filePath:filePath,
success:(res)=>{
uni.showToast({
title:'保存成功,請前往手機相冊中查看',
mask:true,
icon:'none',
duration:2000
})
},
fail:(err)=>{
console.log('err',err)
if(err.errMsg.includes('deny')||err.errMsg.includes('denied')){//用戶選擇拒絕
this.openSetting()
}elseif(err.errMsg.includes('failcancel')){//用戶在保存圖片時取消了
uni.showToast({
title:'已取消保存,無法保存至相冊',
mask:true,
icon:'none',
duration:2000
})
return
}
},
complete:()=>{
uni.hideLoading()
}
})
},
/**
*打開攝像頭設置權限頁面
*/
openSetting(){
uni.showModal({
title:'溫馨提示',
content:'保存圖片至相冊中,需要您同意添加訪問相冊權限',
cancelText:'拒絕',
confirmText:'同意',
success:res=>{
if(res.confirm){
uni.openSetting({
success:settingdata=>{
if(settingdata.authSetting['scope.writePhotosAlbum']){
console.log('獲取權限成功,給出再次點擊圖片保存到相冊的提示。')
uni.showToast({
title:'授權成功,請再次點擊保存',
icon:'none',
duration:2000,
})
}else{
console.log('獲取權限失敗,給出不給權限就無法正常使用的提示')
uni.showToast({
title:'需要訪問相冊權限',
icon:'none',
duration:2000,
})
}
},
fail:(res)=>{
console.log('err',err)
}
})
}else{
uni.showToast({
title:'已拒絕授權,無法保存至相冊',
mask:true,
icon:'none',
duration:2000
})
return
}
}
})
}
}
}
</script>
<style>
</style>
總結
以上是生活随笔為你收集整理的怎么在小程序中实现保存图片组件功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据字典怎么写_求职数据分析,项目经验该
- 下一篇: 如何安装python中的whl文件