Sfoglia il codice sorgente

canvas相机调试

dev_YWQ
HolyKnightIX 1 anno fa
parent
commit
7c05fff5f6
12 ha cambiato i file con 346 aggiunte e 464 eliminazioni
  1. BIN
      src/assets/img/photoBtn.png
  2. BIN
      src/assets/img/reTry.png
  3. BIN
      src/assets/img/selectImg.png
  4. BIN
      src/assets/img/success.png
  5. +3
    -3
      src/pages.json
  6. +323
    -56
      src/pages/camera/index.vue
  7. +0
    -177
      src/pages/camera/indexChooseImage.vue
  8. +0
    -82
      src/pages/camera/indexVideo.vue
  9. +0
    -143
      src/pages/camera/indexWebcam.vue
  10. +4
    -1
      src/pages/createing/index.vue
  11. +14
    -2
      src/pages/login/index.vue
  12. +2
    -0
      src/style/my.scss

BIN
src/assets/img/photoBtn.png Vedi File

Prima Dopo
Larghezza: 400  |  Altezza: 400  |  Dimensione: 12 KiB

BIN
src/assets/img/reTry.png Vedi File

Prima Dopo
Larghezza: 400  |  Altezza: 400  |  Dimensione: 9.8 KiB

BIN
src/assets/img/selectImg.png Vedi File

Prima Dopo
Larghezza: 400  |  Altezza: 400  |  Dimensione: 14 KiB

BIN
src/assets/img/success.png Vedi File

Prima Dopo
Larghezza: 400  |  Altezza: 400  |  Dimensione: 17 KiB

+ 3
- 3
src/pages.json Vedi File

@@ -45,9 +45,9 @@
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"navigationStyle": "custom",
"rpxCalcMaxDeviceWidth": 1080,
"rpxCalcBaseDeviceWidth": 1080,
"rpxCalcIncludeWidth": 1080
"rpxCalcMaxDeviceWidth": 2160,
"rpxCalcBaseDeviceWidth": 2160,
"rpxCalcIncludeWidth": 2160
},
"app": {
"requiredBackgroundModes": [


+ 323
- 56
src/pages/camera/index.vue Vedi File

@@ -1,80 +1,347 @@
<template>
<div class="page">
<!-- Top section -->
<div class="top">
<div class="tips">提示区</div>
<div class="showModel">展示模版</div>
<div class="example"></div>
<div class="model">
<img :src="modelUrl" alt="" />
</div>
</div>

<!-- Bottom section -->
<div class="bottom">
<div class="camera">
<video
id="videoPlayer"
class="video-js"
width="600"
height="400"
controls
muted
>
<source src="" />
</video>
<video muted></video>
<div v-show="photoUrl" id="results"></div>
<video
v-if="!isSuccess"
id="video"
muted
autoplay="autoplay"
:controls="false"
></video>

<div v-if="!isSuccess">
<div class="selectImg">
<img src="../../assets/img/selectImg.png" />
<div class="uploadText">上传照片</div>
</div>

<div id="action" @click="takePicture">
<div class="circleInside"></div>
</div>
</div>
<div class="btnBox">
<div class="takeBtn" @click="takePhoto">拍照</div>
<div v-show="photoUrl" class="takeBtn" @click="photoUrl = null">
重拍

<div v-if="isSuccess">
<div class="selectImg">
<img src="../../assets/img/selectImg.png" />
<div class="uploadText">上传照片</div>
</div>

<div class="confirm" @click="confirmPhoto">
<img src="../../assets/img/success.png" />
<div class="uploadText">就这张了</div>
</div>

<div class="reTry" @click="reTry">
<img src="../../assets/img/reTry.png" />
<div class="uploadText">重新拍摄</div>
</div>
</div>

<canvas
v-if="isShowCanvas"
id="canvas"
style="width: 1530; height: 950"
></canvas>

<div v-if="isSuccess" class="preview">
<img :src="imgSrc" />
</div>
</div>
<!-- Top section -->
</div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import videojs from "video.js";

let player;
const photoUrl = ref(null);

let videoElement;
async function initCamera() {
try {
videoElement = document.getElementById("videoPlayer");
console.log(videoElement);
player = videojs(videoElement, {}, function () {});
const stream = await navigator.mediaDevices.getUserMedia({ video: true });

// Attach the stream to the video element
videoElement.srcObject = stream;
videoElement.play();

// Initialize Video.js with the video element
} catch (error) {
console.error("Error accessing camera:", error);
import { onLoad, onShow, onUnload } from "@dcloudio/uni-app";

let imgSrc = ref("");
let isSuccess = ref(false);
let isShowCanvas = ref(true);
let modelUrl = ref("");

const startCamera = () => {
function getUserMedia(constraints, success, error) {
if (navigator.mediaDevices.getUserMedia) {
//最新的标准API
navigator.mediaDevices
.getUserMedia({
audio: {
echoCancellation: true,
},
video: {
facingMode: "user",
},
})
.then(success)
.catch(error);
} else if (navigator.webkitGetUserMedia) {
//webkit核心浏览器
navigator.webkitGetUserMedia(constraints, success, error);
} else if (navigator.mozGetUserMedia) {
//firfox浏览器
navigator.mozGetUserMedia(constraints, success, error);
} else if (navigator.getUserMedia) {
//旧版API
navigator.getUserMedia(constraints, success, error);
}
}
}

function takePhoto() {
// Capture a photo
const videoElement = document.getElementById("videoPlayer");
const canvas = document.createElement("canvas");
canvas.width = videoElement.videoWidth;
canvas.height = videoElement.videoHeight;
const context = canvas.getContext("2d");
context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);

// Set the photo URL
photoUrl.value = canvas.toDataURL("image/png");
}
const video = document.querySelector("video.uni-video-video");
let canvas = document.querySelector("canvas.uni-canvas-canvas");
const action = document.querySelector("#action");
let context = canvas.getContext("2d");

function success(stream) {
//兼容webkit核心浏览器
let CompatibleURL = window.URL || window.webkitURL;
//将视频流设置为video元素的源
console.log(stream);

//video.src = CompatibleURL.createObjectURL(stream);
video.srcObject = stream;
video.play();
}

function error(error) {
console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
}

if (
navigator.mediaDevices.getUserMedia ||
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia
) {
//调用用户媒体设备, 访问摄像头
getUserMedia(
{
audio: false,
video: true,
},
success,
error
);
} else {
alert("不支持访问用户媒体");
}

action.addEventListener("click", function () {
canvas.width = 1530;
canvas.height = 950;
context.drawImage(video, 0, 0);
const dataURL = canvas.toDataURL("image/png");
imgSrc.value = dataURL;
setTimeout(() => {
isShowCanvas.value = false;
isSuccess.value = true;
}, 10);
});

// 备用方案
// action.addEventListener("click", function () {
// context.drawImage(video, -50, -50, 310, 220);
// const dataURL = canvas.toDataURL("image/png");
// imgSrc.value = dataURL;

// setTimeout(() => {
// isShowCanvas.value = false;
// isSuccess.value = true;
// }, 10);
// console.log(dataURL);
// });
};

const takePicture = () => {
console.log("Take Picture !");
};

const confirmPhoto = () => {};

const reTry = () => {
isSuccess.value = false;
isShowCanvas.value = true;
imgSrc.value = "";
setTimeout(() => {
startCamera();
}, 10);
};

onLoad((options) => {
console.log(options, "options");
modelUrl.value = options.modelUrl;
});

onMounted(() => {
initCamera();
console.log(this);

startCamera();
});
</script>

<style lang="scss" scoped>
/* Your styles remain the same */
.page {
width: 100vw;
height: 100vh;
padding: 0;

.top {
display: flex;
width: 100%;
height: 32%;
.example {
width: 60%;
height: 100%;
background-color: #fff;
}
.model {
position: relative;
width: 40%;
height: 100%;
background-color: #000000;
img {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
}
}
}
.bottom {
position: relative;
width: 100%;
height: 68%;
video {
width: 100%;
height: 100%;
}

.selectImg {
position: absolute;
left: 65rpx;
bottom: 75rpx;
width: 68rpx;
height: 68rpx;
border: 5rpx solid #ffffff;
border-radius: 5rpx;
z-index: 99;
img {
position: absolute;
left: 50%;
bottom: 50%;
transform: translate(-50%, 50%);
width: 70%;
height: 70%;
}
.uploadText {
position: absolute;
left: 50%;
bottom: -40rpx;
width: 150%;
font-size: 20rpx;
transform: translateX(-40%);
}
}

#action {
position: absolute;
left: 50%;
bottom: 45rpx;
width: 120rpx;
height: 120rpx;
transform: translateX(-50%);
background-color: #ffffff;
border-radius: 60rpx;
z-index: 99;
.circleInside {
position: absolute;
left: 50%;
bottom: 50%;
transform: translate(-50%, 50%);
width: 100rpx;
height: 100rpx;
background-color: #ffffff;
border-radius: 50%;
border: 6rpx solid #000;
}
}

.confirm {
position: absolute;
left: 50%;
bottom: 75rpx;
width: 80rpx;
height: 80rpx;
// border: 5rpx solid #ffffff;
transform: translateX(-50%);
border-radius: 60rpx;
z-index: 99;
img {
position: absolute;
left: 50%;
bottom: 50%;
transform: translate(-50%, 50%);
width: 100%;
height: 100%;
}
.uploadText {
position: absolute;
left: 50%;
bottom: -40rpx;
width: 150%;
font-size: 20rpx;
transform: translateX(-32%);
}
}

.reTry {
position: absolute;
right: 65rpx;
bottom: 75rpx;
width: 68rpx;
height: 68rpx;
border: 5rpx solid #ffffff;
border-radius: 5rpx;
z-index: 99;
img {
position: absolute;
left: 50%;
bottom: 50%;
transform: translate(-50%, 50%);
width: 70%;
height: 70%;
}
.uploadText {
position: absolute;
left: 50%;
bottom: -40rpx;
width: 150%;
font-size: 20rpx;
transform: translateX(-40%);
}
}

.preview {
position: relative;
width: 100%;
height: 100%;
z-index: 1;
img {
position: absolute;
top: 110rpx;
width: 120%;
height: 60%;
}
}
}
}
</style>

+ 0
- 177
src/pages/camera/indexChooseImage.vue Vedi File

@@ -1,177 +0,0 @@
<template>
<view class="page">
<!-- 顶部 -->
<view class="top">
<view class="tips">提示区</view>
<view class="showModel">展示模版</view>
</view>
<!-- 底部 -->
<view class="bottom">
<view class="camera">
<video
src=""
muted="muted"
id="videoElement"
autoplay="autoplay"
playsinline="playsinline"
></video>
<!-- <view v-show="!photoUrl" id="my_camera"></view>
<view v-show="photoUrl" id="results"></view> -->
</view>
<view class="btnBox">
<view v-show="!photoUrl" class="takeBtn" @click="takePhoto">拍照</view>
<view v-show="photoUrl" class="takeBtn" @click="photoUrl = null"
>重拍</view
>
</view>
</view>
</view>
</template>

// js部分
<script setup>
//#region 引入
import { ref, watch, onMounted } from "vue";
// import Webcam from "webcamjs";
import Webcam from "../../utils/webcam";
//#endregion ----------------------------

//#region 摄像头
setTimeout(() => {
navigator.mediaDevices
.getUserMedia({ video: true })
.then(function (stream) {
console.log(stream);
// 获取到摄像头的视频流
const video = document.getElementById("videoElement");
video.srcObject = stream;
})
.catch((error) => {
console.error("调用摄像头失败", error);
});
}, 1000);
//#endregion ---------------------------------

//#region 相机
// 拍照
const photoUrl = ref(null);
function takePhoto() {
// console.log(Webcam.snap);
uni.chooseImage({
sourceType: ["camera"],
success: function (res) {
console.log(JSON.stringify(res.tempFilePaths));
},
fail: (err) => {
console.error("选择图片失败", err);
uni.showToast({
title: "选择图片失败, 请稍后重试",
icon: "none",
});
},
});
return;
Webcam.snap((res) => {
// Webcam.freeze();
photoUrl.value = res;
document.getElementById("results").innerHTML =
'<img style="width: 100%;height: 100%;" src="' + res + '"/>';
});
}
// 关闭
function closeCamera() {
Webcam.reset();
}
//#endregion ----------------------------

//#region 初始化配置相机
onMounted(() => {
Webcam.set({
// width: 864, //实时摄像机查看器的宽度
// height: 1536, //实时摄像机查看器的高度
width: 864, //实时摄像机查看器的宽度
height: 1536, //实时摄像机查看器的高度
dest_width: 392, //捕获相机图像的宽
dest_height: 698, //捕获相机图像的高
dest_width: 720, //捕获相机图像的宽
dest_height: 720, //捕获相机图像的高
// crop_width: 700, //最终裁剪图像的宽度(以像素为单位),默认为dest_width。
// crop_height: 700, //最终裁剪图像的高度(以像素为单位),默认为dest_height。
image_format: "png", //捕获图像的期望图像格式,可以是“jpeg”或“png”。
jpeg_quality: 90, //对于JPEG图像,这是理想的质量,从0(最差)到100(最好)。
enable_flash: true, //启用或禁用Flash回退,如果没有本机网络摄像头访问。
force_flash: false, //将此设置为true将始终在adobeflash回退模式下运行。
flip_horiz: false, //将此设置为true将水平翻转图像(镜像模式)。
fps: 30, //设置所需的fps(帧/秒)捕获速率。
swfURL: "./webcam.swf", //为adobeflash回退SWF文件设置一个备用位置
flashNotDetectedText: "未检测到flash播放器的文本/html。", //未检测到flash播放器的文本/html。
unfreeze_snap: true, //是否在拍照后解冻相机
upload_name: "webcam", //在上传摄像头图像文件时使用哪个HTTP POST参数名
flip_horiz: true, //是否镜像
});
// DOM元素必须已经创建并且为空。将ID或CSS选择器传递给Webcam.attach()函数(挂载dom)
// Webcam.attach("#my_camera");
});
//#endregion -----------------------------
</script>

<style lang="scss" scoped>
.page {
padding: 0;
width: 100vw;
height: 100vh;
// overflow: hidden;
}
.top {
display: flex;
width: 100vw;
height: 30vh;
.tips {
width: 60%;
height: 30vh;
background-color: #000;
text-align: center;
}
.showModel {
width: 40%;
height: 30vh;
background-color: red;
text-align: center;
}
}
.bottom {
video {
width: 100% !important;
height: 100% !important;
}
display: flex;
width: 100vw;
height: 70vh;
.camera {
width: 80vw;
height: 70vh;
background-color: green;
// #my_camera {
// width: 100% !important;
// height: 100% !important;
// }
// #results {
// width: 100% !important;
// height: 100% !important;
// }
}
.btnBox {
width: 20vw;
height: 70vh;
background-color: skyblue;
.takeBtn {
width: 15vw;
height: 15vw;
border-radius: 50%;
background-color: #444;
line-height: 15vw;
text-align: center;
}
}
}
</style>

+ 0
- 82
src/pages/camera/indexVideo.vue Vedi File

@@ -1,82 +0,0 @@
<template>
<div class="page">
<!-- Top section -->
<div class="top">
<div class="tips">提示区</div>
<div class="showModel">展示模版</div>
</div>

<!-- Bottom section -->
<div class="bottom">
<div class="camera">
<video
ref="video"
class="video-js vjs-default-skin"
width="600"
height="400"
controls
>
<source src="https://playtv-live.ifeng.com/live/06OLEGEGM4G.m3u8" />
</video>
<video
ref="videoElement"
id="videoPlayer"
class="video-js"
muted
></video>
<div v-show="photoUrl" id="results"></div>
</div>
<div class="btnBox">
<div class="takeBtn" @click="takePhoto">拍照</div>
<div v-show="photoUrl" class="takeBtn" @click="photoUrl = null">
重拍
</div>
</div>
</div>
</div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import videojs from "video.js";

let player;
const photoUrl = ref(null);

async function initCamera() {
try {
const videoElement = document.getElementById("videoPlayer");
player = videojs(videoElement, {}, function () {});
const stream = await navigator.mediaDevices.getUserMedia({ video: true });

// Attach the stream to the video element
videoElement.srcObject = stream;
videoElement.play();

// Initialize Video.js with the video element
} catch (error) {
console.error("Error accessing camera:", error);
}
}

function takePhoto() {
// Capture a photo
const videoElement = document.getElementById("videoPlayer");
const canvas = document.createElement("canvas");
canvas.width = videoElement.videoWidth;
canvas.height = videoElement.videoHeight;
const context = canvas.getContext("2d");
context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);

// Set the photo URL
photoUrl.value = canvas.toDataURL("image/png");
}

onMounted(() => {
initCamera();
});
</script>

<style lang="scss" scoped>
/* Your styles remain the same */
</style>

+ 0
- 143
src/pages/camera/indexWebcam.vue Vedi File

@@ -1,143 +0,0 @@
<template>
<view class="page">
<!-- 顶部 -->
<view class="top">
<view class="tips">提示区</view>
<view class="showModel">展示模版</view>
</view>
<!-- 底部 -->
<view class="bottom">
<view class="camera">
<view v-show="!photoUrl" id="my_camera"></view>
<view v-show="photoUrl" id="results"></view>
</view>
<view class="btnBox">
<view class="takeBtn" @click="takePhoto">拍照</view>
<view v-show="photoUrl" class="takeBtn" @click="photoUrl = null"
>重拍</view
>
</view>
</view>
<!-- <view id="results"></view>
<view id="my_camera"></view>
<view @click="takePhoto">拍照</view>
<view @click="closeCamera">关闭</view> -->
</view>
</template>

// js部分
<script setup>
//#region 引入
import { ref, watch, onMounted } from "vue";
// import Webcam from "webcamjs";
import Webcam from "../../utils/webcam";
//#endregion ----------------------------

//#region 相机
// 拍照
const photoUrl = ref(null);
function takePhoto() {
// console.log(Webcam.snap);
Webcam.snap((res) => {
photoUrl.value = res;
document.getElementById("results").innerHTML =
'<img style="width: 100%;height: 100%;" src="' + res + '"/>';
});
}
// 关闭
function closeCamera() {
Webcam.reset();
}
//#endregion ----------------------------

//#region 初始化配置相机
onMounted(() => {
Webcam.set({
// width: 864, //实时摄像机查看器的宽度
// height: 1536, //实时摄像机查看器的高度
width: 864, //实时摄像机查看器的宽度
height: 1536, //实时摄像机查看器的高度
// dest_width: 392, //捕获相机图像的宽
// dest_height: 698, //捕获相机图像的高
dest_width: 720, //捕获相机图像的宽
dest_height: 720, //捕获相机图像的高
// crop_width: 700, //最终裁剪图像的宽度(以像素为单位),默认为dest_width。
// crop_height: 700, //最终裁剪图像的高度(以像素为单位),默认为dest_height。
image_format: "png", //捕获图像的期望图像格式,可以是“jpeg”或“png”。
jpeg_quality: 90, //对于JPEG图像,这是理想的质量,从0(最差)到100(最好)。
enable_flash: true, //启用或禁用Flash回退,如果没有本机网络摄像头访问。
force_flash: false, //将此设置为true将始终在adobeflash回退模式下运行。
flip_horiz: false, //将此设置为true将水平翻转图像(镜像模式)。
fps: 30, //设置所需的fps(帧/秒)捕获速率。
swfURL: "./webcam.swf", //为adobeflash回退SWF文件设置一个备用位置
flashNotDetectedText: "未检测到flash播放器的文本/html。", //未检测到flash播放器的文本/html。
unfreeze_snap: true, //是否在拍照后解冻相机
upload_name: "webcam", //在上传摄像头图像文件时使用哪个HTTP POST参数名
flip_horiz: true, //是否镜像
});
// DOM元素必须已经创建并且为空。将ID或CSS选择器传递给Webcam.attach()函数(挂载dom)
Webcam.attach("#my_camera");
});
//#endregion -----------------------------
</script>

<style lang="scss" scoped>
.page {
padding: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.top {
display: flex;
width: 100vw;
height: 30vh;
.tips {
width: 60%;
height: 30vh;
background-color: #000;
text-align: center;
}
.showModel {
width: 40%;
height: 30vh;
background-color: red;
text-align: center;
}
}
.bottom {
video {
width: 100% !important;
height: 100% !important;
}
display: flex;
width: 100vw;
height: 70vh;
.camera {
width: 80vw;
height: 70vh;
background-color: green;
// #my_camera {
// width: 100% !important;
// height: 100% !important;
// }
// #results {
// width: 100% !important;
// height: 100% !important;
// }
}
.btnBox {
width: 20vw;
height: 70vh;
background-color: skyblue;
.takeBtn {
width: 15vw;
height: 15vw;
border-radius: 50%;
background-color: #444;
line-height: 15vw;
text-align: center;
}
}
}
</style>

+ 4
- 1
src/pages/createing/index.vue Vedi File

@@ -196,7 +196,10 @@ onUnload(() => {

//#region
function toCamera() {
uni.navigateTo({ url: "/pages/camera/index" });
const url = styleData.value.coverImg;
uni.navigateTo({
url: `/pages/camera/index?modelUrl=${url}`,
});
}
//#endregion ---------------------



+ 14
- 2
src/pages/login/index.vue Vedi File

@@ -23,7 +23,19 @@ function toChooseStyle() {

//#region getImei
function Imei() {
getIMEI();
try {
const IMEI = getIMEI();
uni.showToast({
title: IMEI,
icon: "success",
});
} catch (error) {
uni.showToast({
title: "Error",
icon: "error",
});
}

// cordova.exec(
// function (imei) {
// console.log("IMEI:", imei);
@@ -63,7 +75,7 @@ function Imei() {
align-items: center;
padding: 100rpx 0;
width: 100%;
height: 400rpx;
height: 300rpx;
background-color: rgba($color: #000000, $alpha: 0.5);
.IMEI {
position: absolute;


+ 2
- 0
src/style/my.scss Vedi File

@@ -47,6 +47,8 @@ view {
}

.orangeBtn {
position: absolute;
bottom: 100rpx;
background-color: #FF4F00;
width: 520rpx;
height: 100rpx;


Caricamento…
Annulla
Salva