瀏覽代碼

faet:优化海报文字和图片下载不清楚问题

wangsisi 3 周之前
父節點
當前提交
905c5f75e9
共有 2 個文件被更改,包括 74 次插入78 次删除
  1. 1 3
      pages/tabBar/tree/tree.vue
  2. 73 75
      utils/canvasUtils.js

+ 1 - 3
pages/tabBar/tree/tree.vue

@@ -96,9 +96,7 @@
 			:clockinType="clockinType" @clockinCallback="getBySampleId"></blessingsPopup>
 		
 		<!-- canvas生成图片 - 隐藏的canvas元素 -->
-		<canvas id="posterCanvas" canvas-id="posterCanvas" style="width: 690rpx;height: 1140rpx;position: fixed;left: 750rpx;top: 2000rpx;z-index: 9999;"></canvas>
-		
-
+		<canvas id="posterCanvas" canvas-id="posterCanvas" style="width: 1380rpx;height: 2280rpx;position: fixed;left: 750rpx;top: 2000rpx;z-index: 9999;"></canvas>
 	</view>
 </template>
 

+ 73 - 75
utils/canvasUtils.js

@@ -52,26 +52,26 @@ export class CanvasUtils {
 	drawPoster(data) {
 		return new Promise(async (resolve, reject) => {
 			try {
-				// 基础参数
-				const w = uni.upx2px(690)
-				const top = uni.upx2px(0)
-				const r = uni.upx2px(24)
+				// 基础参数 - 使用2倍分辨率提高清晰度
+				const w = uni.upx2px(690) * 2
+				const top = uni.upx2px(0) * 2
+				const r = uni.upx2px(24) * 2
 				
-				// 计算内容布局参数
+				// 计算内容布局参数 - 使用2倍分辨率
 				const watermarkArr = data.treeObj.watermarkArr || [];
-				const lineHeight = uni.upx2px(40); // 水印文字行间距
-				const startY = uni.upx2px(870); // 水印文字起始Y坐标
+				const lineHeight = uni.upx2px(40) * 2; // 水印文字行间距
+				const startY = uni.upx2px(870) * 2; // 水印文字起始Y坐标
 				const lastWatermarkY = startY + ((watermarkArr.length - 1) * lineHeight);
 				
-				const logoHeight = uni.upx2px(80);
-				const logoSpacing = uni.upx2px(26);
+				const logoHeight = uni.upx2px(80) * 2;
+				const logoSpacing = uni.upx2px(26) * 2;
 				const logoY = lastWatermarkY - logoHeight - logoSpacing;
 				const brandTextY = logoY + logoHeight + logoSpacing;
 				
 				// 使用固定高度,确保有足够空间显示所有内容
 				// 计算canvas高度(根据内容自适应)
-				const bottomMargin = uni.upx2px(20); // 底部边距
-				const h = brandTextY + uni.upx2px(30) + bottomMargin; // 30rpx是文字高度估算
+				const bottomMargin = uni.upx2px(20) * 2; // 底部边距
+				const h = brandTextY + uni.upx2px(30) * 2 + bottomMargin; // 30rpx是文字高度估算
 				
 				
 				// 下载所有图片到本地
@@ -138,54 +138,48 @@ export class CanvasUtils {
 				ctx.setFillStyle('#000000')
 				ctx.setTextAlign('left')                    // 设置文字对齐方式
 				ctx.setTextBaseline('top')                  // 设置文字基线
-				ctx.font = `bold ${uni.upx2px(36)}px "SweiSpringCJKtc", Arial, sans-serif`  // 设置字体样式:粗体 + 自定义字体
-				ctx.fillText(data.treeObj.year, uni.upx2px(26), uni.upx2px(34))
+				ctx.font = `bold ${uni.upx2px(36) * 2}px "SweiSpringCJKtc", Arial, sans-serif`  // 设置字体样式:粗体 + 自定义字体
+				ctx.fillText(data.treeObj.year, uni.upx2px(26) * 2, uni.upx2px(34) * 2)
 
 				// 绘制月份
-				ctx.font = `bold ${uni.upx2px(172)}px "SweiSpringCJKtc", Arial, sans-serif`  // 设置字体样式:粗体 + 自定义字体,172rpx大小
-				ctx.fillText(data.treeObj.monthNumber, uni.upx2px(26), uni.upx2px(76))
+				ctx.font = `bold ${uni.upx2px(172) * 2}px "SweiSpringCJKtc", Arial, sans-serif`  // 设置字体样式:粗体 + 自定义字体,172rpx大小
+				ctx.fillText(data.treeObj.monthNumber, uni.upx2px(26) * 2, uni.upx2px(76) * 2)
 				
 				// 绘制斜线
-				ctx.setLineWidth(uni.upx2px(4))  // 设置线条宽度
+				ctx.setLineWidth(uni.upx2px(4) * 2)  // 设置线条宽度
 				ctx.beginPath()
-				ctx.moveTo(uni.upx2px(160), uni.upx2px(180))  // 斜线起点(右上角)
-				ctx.lineTo(uni.upx2px(140), uni.upx2px(220))  // 斜线终点(左下角)
+				ctx.moveTo(uni.upx2px(160) * 2, uni.upx2px(180) * 2)  // 斜线起点(右上角)
+				ctx.lineTo(uni.upx2px(140) * 2, uni.upx2px(220) * 2)  // 斜线终点(左下角)
 				ctx.stroke()
 				
 				// 绘制日
-				ctx.font = `bold ${uni.upx2px(48)}px "SweiSpringCJKtc", Arial, sans-serif`  // 设置字体样式:粗体 + 自定义字体,172rpx大小
-				ctx.fillText(data.treeObj.day, uni.upx2px(162), uni.upx2px(180))
+				ctx.font = `bold ${uni.upx2px(48) * 2}px "SweiSpringCJKtc", Arial, sans-serif`  // 设置字体样式:粗体 + 自定义字体,172rpx大小
+				ctx.fillText(data.treeObj.day, uni.upx2px(162) * 2, uni.upx2px(180) * 2)
 
 				// 绘制二维码图片
 				if (downloadedImages.qrCodeUrl) {
 					try {
-						ctx.drawImage(downloadedImages.qrCodeUrl, uni.upx2px(w - -190), uni.upx2px(34), uni.upx2px(130), uni.upx2px(142));
+						ctx.drawImage(downloadedImages.qrCodeUrl, uni.upx2px(545) * 2, uni.upx2px(34) * 2, uni.upx2px(130) * 2, uni.upx2px(142) * 2);
 					} catch (error) {
 					}
 				}
-				
-				// 添加品种
-				ctx.setFontSize(uni.upx2px(24))
-				ctx.fillText(data.treeObj.pz, uni.upx2px(w - -218), uni.upx2px(190))
-
-				// 绘制树龄
-				ctx.setFontSize(uni.upx2px(24))
-				ctx.fillText(`${data.treeObj.age}年 ${data.treeObj.age > 9 ? "老树" : "树龄"}`, uni.upx2px(w - -104), uni.upx2px(190))
-				
-				// 绘制气候适宜
-				ctx.setFontSize(uni.upx2px(24))
-				ctx.fillText(data.treeObj.phenology, uni.upx2px(w - -32), uni.upx2px(230))
 
-				// 绘制采摘方式
-				ctx.setFontSize(uni.upx2px(24))
-				ctx.fillText(`气候适宜-${data.treeObj.howTxt || "果园采摘"}`, uni.upx2px(w - -114), uni.upx2px(230))
+				// 添加品种 绘制树龄 - 靠右对齐
+				ctx.setFontSize(uni.upx2px(24) * 2)
+				ctx.setTextAlign('right')
+				ctx.fillText(`${data.treeObj.pz} ${data.treeObj.age}年 ${data.treeObj.age > 9 ? "老树" : "树龄"}`, uni.upx2px(665) * 2, uni.upx2px(186) * 2)
+				
+				// 绘制气候适宜 绘制采摘方式 - 靠右对齐
+				ctx.setFontSize(uni.upx2px(24) * 2)
+				ctx.setTextAlign('right')
+				ctx.fillText(`${data.treeObj.phenology} 气候适宜-${data.treeObj.howTxt || "果园采摘"}`, uni.upx2px(665) * 2, uni.upx2px(225) * 2)
 
 				// 绘制树图片(带圆角)
-				const imgX = uni.upx2px(26);
-				const imgY = uni.upx2px(280);
-				const imgW = uni.upx2px(640);
-				const imgH = uni.upx2px(480);
-				const radius = uni.upx2px(10);
+				const imgX = uni.upx2px(26) * 2;
+				const imgY = uni.upx2px(280) * 2;
+				const imgW = uni.upx2px(640) * 2;
+				const imgH = uni.upx2px(480) * 2;
+				const radius = uni.upx2px(10) * 2;
 				
 				// 创建圆角路径
 				ctx.beginPath();
@@ -217,12 +211,12 @@ export class CanvasUtils {
 				ctx.restore();
 
 				// 绘制图片文字背景和边框(圆角)
-				const textX = uni.upx2px(w - -104);
-				const textY = uni.upx2px(316);
-				const textWidth = uni.upx2px(180); // 背景宽度
-				const textHeight = uni.upx2px(18);  // 背景高度
-				const padding = uni.upx2px(16);     // 内边距
-				const textRadius = uni.upx2px(30);  // 圆角半径
+				const textX = uni.upx2px(450) * 2;
+				const textY = uni.upx2px(316) * 2;
+				const textWidth = uni.upx2px(180) * 2; // 背景宽度
+				const textHeight = uni.upx2px(18) * 2;  // 背景高度
+				const padding = uni.upx2px(16) * 2;     // 内边距
+				const textRadius = uni.upx2px(25) * 2;  // 圆角半径
 				
 				// 绘制黑色半透明背景(圆角)
 				ctx.setFillStyle('rgba(0, 0, 0, 0.6)');
@@ -241,7 +235,7 @@ export class CanvasUtils {
 				
 				// 绘制白色边框(圆角)
 				ctx.setStrokeStyle('rgba(255, 255, 255, 0.39)');
-				ctx.setLineWidth(uni.upx2px(2));
+				ctx.setLineWidth(uni.upx2px(2) * 2);
 				ctx.beginPath();
 				ctx.moveTo(textX - padding + textRadius, textY - padding);
 				ctx.lineTo(textX - padding + textWidth + padding * 2 - textRadius, textY - padding);
@@ -260,13 +254,13 @@ export class CanvasUtils {
 				ctx.setTextAlign('center');
 				ctx.setTextBaseline('middle');
 				// 重置字体为默认字体
-				ctx.font = `bold ${uni.upx2px(20)}px Arial, sans-serif`;
+				ctx.font = `bold ${uni.upx2px(20) * 2}px Arial, sans-serif`;
 				ctx.fillText(`${data.treeObj.pz}-${data.treeObj.countyName}`, textX + textWidth / 2, textY + textHeight / 2);
 				
 				// 绘制树牌文字背景
 				if (downloadedImages.treeNameBgUrl) {
 					try {
-						ctx.drawImage(downloadedImages.treeNameBgUrl, uni.upx2px(40), uni.upx2px(486), uni.upx2px(276), uni.upx2px(274));
+						ctx.drawImage(downloadedImages.treeNameBgUrl, uni.upx2px(40) * 2, uni.upx2px(486) * 2, uni.upx2px(276) * 2, uni.upx2px(274) * 2);
 					} catch (error) {
 						console.error('树牌背景图片绘制失败:', error);
 					}
@@ -274,41 +268,41 @@ export class CanvasUtils {
 
 				// 绘制树牌文字
 				ctx.setFillStyle('#ffffff');
-				ctx.font = `bold ${uni.upx2px(36)}px "jiangxizhuokai", Arial, sans-serif` 
-				ctx.fillText(`【${data.treeName}】`, uni.upx2px(178), uni.upx2px(565))
+				ctx.font = `bold ${uni.upx2px(36) * 2}px "jiangxizhuokai", Arial, sans-serif` 
+				ctx.fillText(`【${data.treeName}】`, uni.upx2px(178) * 2, uni.upx2px(565) * 2)
 
-				ctx.font = `bold ${uni.upx2px(18)}px "jiangxizhuokai", Arial, sans-serif` 
-				ctx.fillText(`${data.userInfo.nickname || data.userInfo.name}  ${data.treeObj.year}.${data.treeObj.monthNumber >= 10 ? data.treeObj.monthNumber : "0" + data.treeObj.monthNumber}.${data.treeObj.day}`, uni.upx2px(178), uni.upx2px(610))
+				ctx.font = `bold ${uni.upx2px(18) * 2}px "jiangxizhuokai", Arial, sans-serif` 
+				ctx.fillText(`${data.userInfo.nickname || data.userInfo.name}  ${data.treeObj.year}.${data.treeObj.monthNumber >= 10 ? data.treeObj.monthNumber : "0" + data.treeObj.monthNumber}.${data.treeObj.day}`, uni.upx2px(178) * 2, uni.upx2px(610) * 2)
 				
 				// 绘制横线(在水印文字上面)
 				ctx.setStrokeStyle('#000000');  // 设置线条颜色为黑色
-				ctx.setLineWidth(uni.upx2px(2));
+				ctx.setLineWidth(uni.upx2px(2) * 2);
 				
 				// 计算第一行水印文字的长度
 				const firstWatermarkText = data.treeObj.watermarkArr[0] || '';
-				ctx.font = `bold ${uni.upx2px(24)}px "SweiSpringCJKtc", Arial, sans-serif`;
+				ctx.font = `bold ${uni.upx2px(24) * 2}px "SweiSpringCJKtc", Arial, sans-serif`;
 				const textMetrics = ctx.measureText(firstWatermarkText);
 				const watermarkTextWidth = textMetrics.width;
 				
 				ctx.beginPath();
-				ctx.moveTo(uni.upx2px(36), uni.upx2px(820));  // 横线起点,左边距离36rpx
-				ctx.lineTo(uni.upx2px(36) + watermarkTextWidth, uni.upx2px(820));  // 横线终点,根据文字长度
+				ctx.moveTo(uni.upx2px(36) * 2, uni.upx2px(820) * 2);  // 横线起点,左边距离36rpx
+				ctx.lineTo(uni.upx2px(36) * 2 + watermarkTextWidth, uni.upx2px(820) * 2);  // 横线终点,根据文字长度
 				ctx.stroke();
 
 				// 绘制水印文字(根据数组长度动态生成)
 				ctx.setFillStyle('#000000');
-				ctx.font = `bold ${uni.upx2px(24)}px "SweiSpringCJKtc", Arial, sans-serif` 
+				ctx.font = `bold ${uni.upx2px(24) * 2}px "SweiSpringCJKtc", Arial, sans-serif` 
 				ctx.setTextAlign('left');  // 设置左对齐,确保第一个字在指定位置
 				
 				watermarkArr.forEach((text, index) => {
 					const y = startY + (index * lineHeight);
-					ctx.fillText(text, uni.upx2px(36), y);
+					ctx.fillText(text, uni.upx2px(36) * 2, y);
 				});
 
 				// 绘制logo(与最后一条水印文字对齐)
 				if (downloadedImages.logoUrl) {
 					try {
-						ctx.drawImage(downloadedImages.logoUrl, uni.upx2px(w - -230), logoY, uni.upx2px(76), logoHeight);
+						ctx.drawImage(downloadedImages.logoUrl, uni.upx2px(590) * 2, logoY, uni.upx2px(76) * 2, logoHeight);
 					} catch (error) {
 						console.error('logo图片绘制失败:', error);
 					}
@@ -316,8 +310,8 @@ export class CanvasUtils {
 
 				// 绘制飞鸟有味(与logo保持间距)
 				ctx.setFillStyle('#000000');
-				ctx.font = `bold ${uni.upx2px(22)}px "SweiSpringCJKtc", Arial, sans-serif` 
-				ctx.fillText(`飞鸟有味`, uni.upx2px(w - -225), brandTextY);
+				ctx.font = `bold ${uni.upx2px(22) * 2}px "SweiSpringCJKtc", Arial, sans-serif` 
+				ctx.fillText(`飞鸟有味`, uni.upx2px(580) * 2, brandTextY);
 
 				ctx.draw(false, () => {
 					// 等待canvas渲染完成
@@ -353,12 +347,12 @@ export class CanvasUtils {
 	}
 
 	// 保存到相册
-	saveToAlbum() {
-		return new Promise((resolve, reject) => {
-			uni.showLoading({
-				title: '正在生成图片...',
-				mask: true
-			});
+			saveToAlbum() {
+			return new Promise((resolve, reject) => {
+				uni.showLoading({
+					title: '正在生成海报...',
+					mask: true
+				});
 			
 			// 先检查canvas是否存在
 			const query = uni.createSelectorQuery();
@@ -377,10 +371,10 @@ export class CanvasUtils {
 				
 				uni.canvasToTempFilePath({
 					canvasId: this.canvasId,
-					width: 690,
-					height: 1140, // 固定高度1140rpx
-					destWidth: 690,
-					destHeight: 1140, // 固定高度1140rpx
+					width: 1380, // 2倍分辨率宽度
+					height: 2280, // 2倍分辨率高度
+					destWidth: 1380, // 2倍分辨率宽度
+					destHeight: 2280, // 2倍分辨率高度
 					fileType: 'png',
 					success: (res) => {
 						uni.hideLoading();
@@ -390,12 +384,16 @@ export class CanvasUtils {
 							mask: true
 						});
 						
+						// 生成带时间戳的海报文件名
+						const timestamp = new Date().getTime();
+						const posterFileName = `海报_${timestamp}.png`;
+						
 						uni.saveImageToPhotosAlbum({
 							filePath: res.tempFilePath,
 							success: () => {
 								uni.hideLoading();
 								uni.showToast({
-									title: '保存成功',
+									title: '海报保存成功',
 									icon: 'success',
 									duration: 2000
 								});
@@ -465,7 +463,7 @@ export class CanvasUtils {
 		} catch (error) {
 			console.error('海报生成和保存失败:', error);
 			uni.showToast({
-				title: error.message || '保存失败',
+				title: error.message || '海报保存失败',
 				icon: 'none'
 			});
 			return false;