uniapp 微信小程序生成水印图片
·
效果

源码
这是页面,记得配置pages.json
<template>
<view class="bg-white camera-continer" :style="[state.style]">
<camera :device-position="state.devicePosition" :flash="state.flashLamp" style="width: 100%;height: 100%;">
<cover-view class="camera-content">
<cover-view class="text-white padding water-mark">
<cover-image style="width: 118px; height: 40px;" src="@/static/lsf-logo.png"></cover-image>
<cover-view class="margin-top-sm address">{{ state.address }}</cover-view>
<cover-view class="margin-top-sm">{{ state.time }}</cover-view>
</cover-view>
<cover-view class="padding bg-white flex justify-around align-center handler">
<cover-image class="camera-icon" src="@/static/img/icons/camera-switching-fill.png"
@click="switchCamera"></cover-image>
<cover-image class="camera-btn" src="@/static/img/icons/photography-creativi.png"
@click="takePhoto"></cover-image>
<cover-image class="lamp-icon" :src="'/static/img/icons/'+lampIcon+'.png'" @click="switchLamp"></cover-image>
</cover-view>
</cover-view>
</camera>
</view>
<canvas :style="{ width: state.width + 'px', height: state.height + 'px' }" canvas-id="canvas-photo"></canvas>
</template>
<script setup lang="ts">
/**
* @author 全易
* @time 2024-08-15 10:10:00
* @description 水印相机
* @use 父页面这样跳: https://blog.csdn.net/qq_42618566/article/details/141322992
uni.navigateTo({
url: "/components/watermark-camera",
events: {
emits(data) {
console.log("水印相机的照片:", data)
}
}
})
*/
import CheckinApi from "@/apps/check-in/api/checkin"
import { watch, ref, reactive, computed, onBeforeUnmount, onMounted, getCurrentInstance } from "vue";
import { onShow, onLoad } from "@dcloudio/uni-app";
import { Tool } from "../utils/Tool";
let interval = null;
const instance = getCurrentInstance();
const state = reactive({
width: null,
height: null,
devicePosition: "back",
flashLamp: "auto",
time: "时间:",
address: "地址:加载中...",
imgList: [],
style: { 'padding-bottom': null }
});
uni.startDeviceMotionListening({
success: (e) => {
console.log("监听设备方向:", e);
uni.onDeviceMotionChange((res) => {
// console.log("设备方向:", res)
const alpha = res.alpha;
const beta = res.beta;
const gamma = res.gamma;
if (Math.abs(beta) < 10 && Math.abs(gamma) < 10) {
console.log("正竖屏");
} else if (Math.abs(beta) > 170 && Math.abs(gamma) < 10) {
console.log("倒竖屏");
} else if (Math.abs(beta) < 10 && Math.abs(gamma - 90) < 10) {
console.log("右横屏");
} else if (Math.abs(beta) < 10 && Math.abs(gamma + 90) < 10) {
console.log("左横屏");
}
});
}
});
initWaterMark();
const systemInfo = uni.getSystemInfoSync();
state.style = {
'padding-bottom': (systemInfo.safeAreaInsets.bottom || 15) + 'px'
}
onHide(() => {
uni.stopDeviceMotionListening();
clearInterval(interval);
})
const lampIcon = computed(() => {
switch (state.flashLamp) {
case "off":
return "flash_off";
case "on":
return "flash";
case "auto":
return "flash_auto";
default:
return "flash_auto"
}
})
function initWaterMark() {
getPosition();
interval = setInterval(updateTime(), 60000);
};
function updateTime() {
const now = new Date().getTime()
state.time = "时间:" + uni.$u.timeFormat(now, 'yyyy-mm-dd hh:MM');
// state.time += Tool.now()
return updateTime;
};
// 切换摄像头
function switchCamera() {
if (state.devicePosition === 'front') {
state.devicePosition = 'back'
} else {
state.devicePosition = 'front'
}
};
// 切换闪光灯
function switchLamp() {
if (state.flashLamp === 'auto') {
state.flashLamp = 'on'
} else if (state.flashLamp === 'on') {
state.flashLamp = 'off'
} else if (state.flashLamp === 'off') {
state.flashLamp = 'auto'
}
};
function getPosition() {
uni.getLocation({
type: 'gcj02',
async success(res) {
const position = await CheckinApi.reverseGeocoding({
lon: res.longitude,
lat: res.latitude
});
if (position.code === 0) {
state.address = "地址:" + position.data.address;
}
},
fail(err) {
console.log('调用Location接口异常', err);
if (err?.errMsg?.includes("fail auth deny")) {
uni.getSetting({
success: (res) => {
if (!res.authSetting['scope.userLocation']) {
uni.showModal({
title: '未开启地理授权',
content: '您的位置信息将用于连锁峰水印相机的展示',
confirmText: "授权",
success: res => {
if (res.confirm) {
uni.openSetting()
}
}
})
}
}
})
} else {
uni.$u.toast('获取地理位置失败,请确认手机的定位服务是否打开!');
}
}
})
};
function takePhoto() {
if (state.address === '地址:加载中...') {
return uni.showToast({
icon: "none",
title: "地址未加载出来"
})
};
uni.showLoading({
title: "正在生成",
mask: true
});
const ccc = uni.createCameraContext();
ccc.takePhoto({
quality: 'high',
success: (res) => {
createWatermark(res.tempImagePath);
}
});
};
function createWatermark(image) {
uni.getImageInfo({
src: image,
success: res => {
state.width = res.width / 3;
state.height = res.height / 3.01;
const ctx = uni.createCanvasContext('canvas-photo');
const padding = 10; // 边距
const fontSize = 11; // 字号
const fontColor = '#FFFFFF'; // 字号
const lineHeight = 15; // 行高
ctx.drawImage(image, 0, 0, state.width, state.height);
ctx.drawImage("/static/lsf-logo.png", padding, state.height * 0.83, 70, 20);
// 文本集合
const text = ["时间:" + Tool.now(), state.address]; // 需要填充两个文本
let nextStart = state.height * 0.91; // 文本的起点
text.forEach((line) => {
nextStart = fillFeedText({
ctx,
text: line,
x: padding,
y: nextStart,
maxWidth: state.width - padding - 10,
lineHeight,
color: fontColor,
size: fontSize
})
});
ctx.draw(false, () => {
setTimeout(() => {
uni.canvasToTempFilePath({
canvasId: 'canvas-photo',
success: ctf => {
uni.navigateBack();
const eventChannel = instance.proxy.getOpenerEventChannel();
eventChannel.emit('emits', {
image: ctf.tempFilePath
});
uni.hideLoading();
}
});
}, 100)
});
}
});
};
// 填充自动换行的文本
function fillFeedText({ ctx, text, x, y, maxWidth, lineHeight, color, size }) {
// 文本配置
ctx.setFontSize(size);
ctx.setFillStyle(color);
ctx.setShadow(0, 0, 3, 'rgba(0, 0, 0, 0.4)');
ctx.fillStyle = '#FFFFFF'; // 填充颜色(黑色)
ctx.strokeStyle = '#FFFFFF'; // 边框颜色
ctx.lineWidth = 0.8; // 边框宽度
// 计算文本换行宽高,换行逻辑
const words = text.split('');
let line = '';
const lines = [];
for (let i = 0; i < words.length; i++) {
const word = words[i];
const testLine = line + word;
const metrics = ctx.measureText(testLine);
if (metrics.width > maxWidth && i > 0) {
lines.push(line);
line = word;
} else {
line = testLine;
}
};
// 填充文本
lines.push(line);
let nextStart : number;
lines.forEach((line, index) => {
ctx.fillText(line, x, y + ((index++) * lineHeight), maxWidth);
nextStart = y + ((index++) * lineHeight)
});
return nextStart;
}
</script>
<style scoped lang="scss">
.camera-continer {
width: 100vw;
height: 100vh;
overflow: hidden;
}
.camera-content {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
.address {
white-space: normal;
/* 允许换行 */
overflow-wrap: break-word;
/* 在单词边界处换行 */
word-wrap: break-word;
/* 兼容旧版本的浏览器 */
max-width: 100%;
}
.water-mark {}
.handler {
padding-bottom: 0;
.camera-icon,
.lamp-icon {
width: 60rpx;
}
.camera-btn {
width: 80rpx;
padding: 15px;
border: 8rpx #434343 solid;
border-radius: 50%;
}
}
}
#canvas-photo {
position: fixed;
top: -999999px;
}
</style>
uni-app canvas文本自动换行 https://quanyi.blog.csdn.net/article/details/142566671
更多推荐
所有评论(0)