Webカメラの上に透かし的なものを重ねたい
完成形
コード
<template> <div class="root"> <div class="photo"> <video ref="video" id="video"></video> <canvas ref="canvas" id="canvas"></canvas> <div class="l2"> <canvas id="camera_record_box"></canvas> </div> </div> <div> <div class="button1" @click="capture()">写真を撮影</div> <div class="button1" @click="takePicture()">写真を選択</div> <div class="button1" @click="captures = []">リセット</div> </div> <div class="captureWrap"> <div class="capture" v-for="c in captures" v-bind:key="c.d"> <img v-bind:src="c" /> </div> </div> </div> </template> <script lang="ts"> import { defineComponent, ref, onMounted } from "vue"; import { Camera } from "@capacitor/camera"; export default defineComponent({ setup() { const video = ref(); const canvas = ref(); const captures = ref([]) as any; const constraints = { audio: false, video: { width: 390, height: 390, facingMode: "user", // facingMode: { // exact: "environment", // }, }, }; onMounted(() => { if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { navigator.mediaDevices .getUserMedia(constraints) .then((stream) => { video.value.srcObject = stream; video.value.play(); }) .catch((e: any) => { console.log("ERROR: ", e); }); } }); const capture = () => { if (captures.value.length < 4) { canvas.value.getContext("2d").drawImage(video.value, 0, 0, 390, 390); captures.value.push(canvas.value.toDataURL("image/png")); console.log(captures.value); } }; const takePicture = async () => { const image = await Camera.pickImages({ quality: 90, limit: 4, // source: CameraSource.Photos, // allowEditing: true, // resultType: CameraResultType.Base64, }); for (let item in image.photos) { if (captures.value.length < 4) { const base64Data = await base64FromPath(image.photos[item].webPath); captures.value.push(base64Data); } } }; const base64FromPath = async (path: string): Promise<string> => { const response = await fetch(path); const blob = await response.blob(); return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = reject; reader.onload = () => { if (typeof reader.result === "string") { resolve(reader.result); } else { reject("method did not return a string"); } }; reader.readAsDataURL(blob); }); }; return { capture, video, canvas, captures, takePicture }; }, }); </script> <style lang="scss"> .root { margin: 0 auto; width: 390px; position: relative; } .photo { width: 390px; height: 390px; margin-bottom: 24px; } .l2 { top: 0; position: absolute; } #camera_record_box { position: absolute; width: 390px; height: 390px; background-image: url("../square-1.png"); opacity: 0.5; } #canvas { display: none; } .captureWrap { width: 100%; display: flex; flex-wrap: wrap; gap: 12px; .capture { img { width: 100px; height: 100px; } } } .button1 { background-color: red; color: #fff; padding: 16px; margin-bottom: 12px; } </style>