質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

690閲覧

ウェブサイト内でカメラを使用して写真を撮影・ダウンロードする(スマホ用)

harapara

総合スコア39

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2022/06/07 05:18

編集2022/07/06 03:07

ウェブサイト内でスマホの内カメを起動し、自身の顔を撮影→確認→ダウンロードが出来るようにしたいです。
(実際は顔の上にフレームをのせるので、顔以外は写りません。)
確認の部分でvideoを画像として切り取り、canvasに描画するのですが、その際(上下の黒フレーム分?)顔が伸びてしまいます。
何か良い方法ないでしょうか。。
スマホで使用したいのですが、カメラ比率は色々だと思っており、黒フレーム込みで切り取りたいです。

参考サイト:https://blog.katsubemakito.net/html5/camera2
参考サイト:https://github.com/dotnsf/html_camera_inside

html

1<!DOCTYPE html> 2<html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge" /> 6 <meta name="viewport" content="width=645" /> 7 <title>HTML Camera Inside</title> 8 <script src="//code.jquery.com/jquery-2.0.3.min.js"></script> 9 <style> 10 * { 11 margin: 0; 12 padding: 0; 13 box-sizing: border-box; 14 } 15 html, 16 body { 17 height: 100%; 18 text-align: center; 19 } 20 body { 21 background-color: #000; 22 position: relative; 23 } 24 video { 25 position: absolute; 26 z-index: 10; 27 } 28 .container { 29 width: 100%; 30 max-width: 645px; 31 position: relative; 32 margin: auto; 33 height: 100%; 34 } 35 #frame, 36 #video, 37 #dialog-outer { 38 position: absolute; 39 width: 645px; 40 left: 0; 41 top: 0; 42 } 43 #frame { 44 z-index: 2; 45 } 46 #video { 47 z-index: 10; 48 background-color: black; 49 } 50 #dialog-outer { 51 z-index: 30; 52 background: #fff; 53 height: 100%; 54 position: fixed; 55 text-align: center; 56 display: none; 57 } 58 button { 59 background-color: #fff; 60 border: none; 61 cursor: pointer; 62 outline: none; 63 padding: 0; 64 appearance: none; 65 padding: 0.5rem 2rem; 66 font-size: 3rem; 67 } 68 #dialog-result-close { 69 position: fixed; 70 padding: 3px; 71 right: 3px; 72 top: 3px; 73 font-size: 2rem; 74 background-color: rgba(244, 244, 244, 0.8); 75 } 76 #btn-shutter { 77 position: absolute; 78 bottom: 3px; 79 left: 50%; 80 transform: translate(-50%, -50%); 81 z-index: 30; 82 } 83 #dialog-result-dl { 84 position: absolute; 85 bottom: 4px; 86 left: 0; 87 width: 100%; 88 } 89 </style> 90 </head> 91 <body> 92 <!-- video(visible) --> 93 <div class="container" id="videoPreview" style="text-align: center"> 94 <h4>Video Preview</h4> 95 <canvas id="frame" width="645" height="860"></canvas> 96 </div> 97 98 <!-- canvas(invisible) --> 99 <div 100 class="container" 101 id="canvasPreview" 102 style="text-align: center; display: none" 103 > 104 <h4>Canvas Preview</h4> 105 </div> 106 <!-- シャッター --> 107 <div id="shutter-inner"> 108 <button id="btn-shutter" type="button">撮影</button> 109 </div> 110 <!-- 最終結果 --> 111 <div id="dialog-outer"> 112 <div id="dialog-result" class="dialog"> 113 <div id="dialog-result-close">Close</div> 114 <p><canvas id="result" width="645" height="860"></canvas></p> 115 <button id="dialog-result-dl" type="button">download</button> 116 </div> 117 118 <!-- NowLoading --> 119 <div id="dialog-nowloading" class="dialog">...Now Loading</div> 120 </div> 121 <script> 122 var cameraSize = { w: 645, h: 860 }; 123 var canvasSize = { w: 645, h: 860 }; 124 var resolution = { w: 1080, h: 720 }; 125 var video = null; 126 var media = null; 127 var canvas = null; 128 var ctx = null; 129 const FRAME = document.querySelector("#frame"); 130 131 $(function () { 132 //. video 133 video = document.createElement("video"); 134 video.id = "video"; 135 video.width = cameraSize.w; 136 video.height = cameraSize.h; 137 video.setAttribute("autoplay", true); //. #1 138 video.setAttribute("muted", ""); //. #1 139 video.setAttribute("playsinline", ""); //. #1 140 document.getElementById("videoPreview").appendChild(video); 141 142 //. media 143 var data = { 144 audio: false, //. no voice/mic 145 video: { 146 facingMode: "user", //. front 147 width: { ideal: resolution.w }, 148 height: { ideal: resolution.h }, 149 }, 150 }; 151 media = navigator.mediaDevices 152 .getUserMedia(data) 153 .then(function (stream) { 154 video.srcObject = stream; 155 }) 156 .then(function (err) {}); 157 158 //. canvas 159 canvas = document.createElement("canvas"); 160 canvas.id = "canvas"; 161 canvas.width = canvasSize.w; 162 canvas.height = canvasSize.h; 163 document.getElementById("canvasPreview").appendChild(canvas); 164 165 //. context 166 ctx = canvas.getContext("2d"); 167 168 document.querySelector("#btn-shutter").addEventListener("click", () => { 169 // 画像の生成 170 onShutter(); // カメラ映像から静止画を取得 171 concatCanvas("#result", ["#canvas", "#frame"]); // フレームと合成 172 173 // 最終結果ダイアログを表示 174 setTimeout(() => { 175 // 演出目的で少しタイミングをずらす 176 dialogShow("#dialog-result"); 177 }, 300); 178 }); 179 180 document 181 .querySelector("#dialog-result-dl") 182 .addEventListener("click", (e) => { 183 canvasDownload("#result"); 184 }); 185 //----------------------------- 186 // ダイアログ 187 //----------------------------- 188 // 閉じるボタン 189 document 190 .querySelector("#dialog-result-close") 191 .addEventListener("click", (e) => { 192 // video.play(); 193 dialogHide("#dialog-result"); 194 }); 195 }); 196 197 /** 198 * シャッターボタンをクリック 199 * 200 * @return {void} 201 **/ 202 function onShutter() { 203 const STILL = document.querySelector("#canvas"); // <canvas> 204 const VIDEO = document.querySelector("#video"); // <video> 205 206 const ctx = canvas.getContext("2d"); 207 // 前回の結果を消去 208 ctx.clearRect(0, 0, STILL.width, STILL.height); 209 210 // videoを画像として切り取り、canvasに描画 211 ctx.drawImage(VIDEO, 0, 0, STILL.width, STILL.height); 212 } 213 214 /** 215 * Canvas合成 216 * 217 * @param {string} base 合成結果を描画するcanvas(id) 218 * @param {array} asset 合成する素材canvas(id) 219 * @return {void} 220 */ 221 async function concatCanvas(base, asset) { 222 const canvas = document.querySelector(base); 223 const ctx = canvas.getContext("2d"); 224 225 for (let i = 0; i < asset.length; i++) { 226 const image1 = await getImagefromCanvas(asset[i]); 227 ctx.drawImage(image1, 0, 0, canvas.width, canvas.height); 228 } 229 } 230 231 /** 232 * Canvasを画像として取得 233 * 234 * @param {string} id 対象canvasのid 235 * @return {object} 236 */ 237 function getImagefromCanvas(id) { 238 return new Promise((resolve, reject) => { 239 const image = new Image(); 240 const ctx = document.querySelector(id).getContext("2d"); 241 image.onload = () => resolve(image); 242 image.onerror = (e) => reject(e); 243 image.src = ctx.canvas.toDataURL(); 244 }); 245 } 246 247 /** 248 * ダイアログを表示 249 * 250 * @param {string} id 251 **/ 252 function dialogShow(id) { 253 document.querySelector("#dialog-outer").style.display = "block"; 254 document.querySelector(id).style.display = "block"; 255 } 256 257 /** 258 * ダイアログを非表示 259 * 260 * @param {string} id 261 **/ 262 function dialogHide(id) { 263 document.querySelector("#dialog-outer").style.display = "none"; 264 document.querySelector(id).style.display = "none"; 265 } 266 </script> 267 </body> 268</html> 269 270

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

黒フレーム込みで切り抜くという方法ではないですが。
videoを画像として切り取り、canvasに描画する際、画像のサイズを固定にするのではなく
videoの高さを取得し、それを使用しました。

html

1/** 2 * シャッターボタンをクリック 3 * 4 * @return {void} 5 **/ 6 function onShutter() { 7 const STILL = document.querySelector("#canvas"); 8 const VIDEO = document.querySelector("#video"); 9 const h = $("#video").innerHeight(); // ←追加 10 11 const ctx = canvas.getContext("2d"); 12 // 前回の結果を消去 13 ctx.clearRect(0, 0, STILL.width, STILL.height); 14 15 // videoを画像として切り取り、canvasに描画 16 ctx.drawImage(VIDEO, 0, 0, STILL.width, h); // ←変更 17 }

投稿2022/06/08 02:26

harapara

総合スコア39

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問