91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在小程序中實現保存圖片組件功能

發布時間:2021-10-27 11:04:09 來源:億速云 閱讀:212 作者:iii 欄目:移動開發

這篇文章主要講解了“怎么在小程序中實現保存圖片組件功能”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么在小程序中實現保存圖片組件功能”吧!

思路

首先聲明下組件采用的是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>
		<view class="savePosterItem">
			<image v-show="tempFilePath" :src="tempFilePath"></image>
			<save-poster-com v-show="!tempFilePath" ref="savePoster" :canvasInfo="canvasInfo"></save-poster-com>
		</view>
		
		
		<button class="savePosterBtn" type="primary" @click="saveBtnFun">保存海報</button>
	</view>
</template>

<script>
	import SavePosterCom from '@/components/SavePosterCom/SavePosterCom.vue'
	export default {
		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
			}) => {
				// 獲取畫布寬高
				let canvasWH = comThis.canvasWH
				// 繪制海報背景圖
				let promise_1 = drawCanvasImage(context, this.canvasBgUrl, canvasWH.canvasWidth, canvasWH.canvasHeight)
				// 必須先繪制玩海報背景圖 再去操作其他繪制內容
				promise_1.then(res => {
					let promise_2 = drawCircularAvatar(context, this.avatarUrl, canvasWH.canvasWidth / 2, canvasWH.canvasHeight /
						7, 70)
					
					let promise_3 = drawText({
						context: context,
						text: '皮皮蝦仁',
						dx: (canvasWH.canvasWidth / 2) + 60,
						dy: canvasWH.canvasHeight / 4,
						fontSize: 30,
						fontColor: '#5D4037'
					})
					
					let promise_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>
	export default {
		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() {
				const res = uni.getSystemInfoSync();
				return {
					windowWidth: res.windowWidth,
					windowHeight: res.windowHeight
				}
			},
			/** 獲取 CanvasContext實例
			* @param {String} canvasId 
			*/
			getCanvasContextInit(canvasId) {
				return uni.createCanvasContext(canvasId, this)
			},
			/** 保存海報組件初始化
			* @param {Function} callback(context) 回調函數
			*/
			canvasInit(callback) {
				let context = this.getCanvasContextInit(this.canvasInfo.canvasId)
				if (context) {
					callback({
						context: context,
						comThis: this
					})
				}
			},
			/** 將上訴的繪制畫到畫布中 并且 將畫布導出為圖片
			*  @param context 畫布
			*  @param {Promise[]} 存放Promise的數組 
			*  @param {Function} callback 保存圖片后執行的回調函數(本地圖片臨時路徑)
			*/
			startDrawToImage(context, promiseArr, callback) {
				// 將之前在繪圖上下文中的描述(路徑、變形、樣式)畫到 canvas 中
				let canvasId = this.canvasInfo.canvasId
				let tempFilePath = ''
				Promise.all(promiseArr).then(res => {
					context.draw(false, async () => {
						callback(await this.canvasToImage(canvasId))
					})
				})
			},
			/**
			* 在canvas繪制一張圖片
			* @param context 畫布
			* @param src 圖片資源
			* @param _imageWidth 圖片寬度
			* @param _imageHeight 圖片高度 
			*/
			drawCanvasImage(context, src, _imageWidth, _imageHeight, dx, dy) {
				return new Promise((resolve, reject) => {
					uni.getImageInfo({
						src: src,
						success: res => {
							context.drawImage(res.path, (dx - _imageWidth), (dy - _imageHeight), _imageWidth, _imageHeight)
							resolve(context)
						},
					})
				})
			},
			/** 繪制一個圓形頭像
			* @param  context 畫布 
			* @param  url     圖片地址
			* @param  _circularX  圓心X坐標
			* @param  _circularY  圓心Y坐標
			* @param  _circularR  圓半徑
			*/
			drawCircularAvatar(context, url, _circularX, _circularY, _circularR) {
				let dx = _circularX - _circularR;
				let dy = _circularY - _circularR;
				let dwidth = _circularR * 2;
				let dheight = _circularR * 2
				return new Promise((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)
						}
					})
				})
			},
			/** 繪制多行文本 注:, 和 空格都算一個字
			* @param context 畫布
			* @param text 需要被繪制的文本
			* @param dx 左上角x坐標
			* @param dy 右上角y坐標
			* @param rowStrnum 每行多少個字 (默認為text字體個數->單行)
			* @param fontSize 文字大小 (默認16)
			* @param fontColor 文字顏色 (默認black)
			* @param lineHeight 單行文本行高 (默認0)
			*/
			drawText(options) {
				let {
					context,
					text,
					dx,
					dy,
					rowStrnum = text.length,
					lineHeight = 0,
					fontSize = 16,
					fontColor = 'black'
				} = options
				return new Promise((resolve, reject) => {
					context.setFontSize(fontSize)
					context.setFillStyle(fontColor)
					context.setTextBaseline('middle')
					// 獲取需要繪制的文本寬度
					let textWidth = Number(context.measureText(text).width)
					// console.log('textWidth',textWidth)
					// 獲取文本的字數 
					let textNum = text.length
					// 獲取行數 向上取整
					let lineNum = Math.ceil(textNum / rowStrnum)
					// console.log('textNum',textNum)
					// console.log('lineNum',lineNum)
					for (let i = 0; i < lineNum; i++) {
						let sliceText = text.slice(i * rowStrnum, (i + 1) * rowStrnum)
						// fillText 的 dx = 文字最左邊的距離到屏幕政策的距離
						context.fillText(sliceText, dx - textWidth, dy + i * lineHeight);
					}
					resolve(context)
				})
			},
			/** 將畫布導出為圖片
			* @param canvasId 畫布標識
			*/
			canvasToImage(canvasId) {
				return new Promise((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()
						} else if (err.errMsg.includes('fail cancel')) { // 用戶在保存圖片時 取消了
							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>

感謝各位的閱讀,以上就是“怎么在小程序中實現保存圖片組件功能”的內容了,經過本文的學習后,相信大家對怎么在小程序中實現保存圖片組件功能這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

php
AI

中山市| 大悟县| 宜昌市| 汝南县| 西畴县| 都匀市| 三台县| 麻城市| 阿拉善盟| 察雅县| 北流市| 海南省| 交城县| 屏山县| 萝北县| 新巴尔虎左旗| 张家口市| 桓台县| 阜新| 东乌珠穆沁旗| 织金县| 华宁县| 阜阳市| 从江县| 佛坪县| 板桥市| 同心县| 金沙县| 南城县| 高邮市| 清水县| 海南省| 南陵县| 大同市| 申扎县| 罗定市| 厦门市| 阳泉市| 大姚县| 无为县| 阿合奇县|