Add fixed aspect ratio and image scaling on download
This commit is contained in:
parent
272fb59545
commit
1bed329472
11
index.html
11
index.html
@ -39,10 +39,13 @@
|
|||||||
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Capture a photo from your webcam and save it using the student number.</p>
|
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Capture a photo from your webcam and save it using the student number.</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="relative bg-black rounded-xl overflow-hidden aspect-video flex items-center justify-center">
|
<div class="space-y-2">
|
||||||
<video id="video" class="w-full h-full object-cover" autoplay playsinline muted></video>
|
<div class="relative bg-black rounded-xl overflow-hidden aspect-[145/185] max-w-[280px] mx-auto flex items-center justify-center">
|
||||||
<img id="preview-img" class="hidden w-full h-full object-cover" alt="Captured student photo">
|
<video id="video" class="w-full h-full object-cover" autoplay playsinline muted></video>
|
||||||
<p id="camera-status" class="absolute text-gray-300 text-sm">Requesting camera access…</p>
|
<img id="preview-img" class="hidden w-full h-full object-cover" alt="Captured student photo">
|
||||||
|
<p id="camera-status" class="absolute text-gray-300 text-sm px-4 text-center">Requesting camera access…</p>
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-gray-400 dark:text-gray-500 text-center">Frame matches the final 145×185 photo — fill it with the student's face and shoulders.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<canvas id="canvas" class="hidden"></canvas>
|
<canvas id="canvas" class="hidden"></canvas>
|
||||||
|
|||||||
27
js/app.js
27
js/app.js
@ -7,6 +7,10 @@ const inputError = document.getElementById('input-error');
|
|||||||
const captureBtn = document.getElementById('capture-btn');
|
const captureBtn = document.getElementById('capture-btn');
|
||||||
const downloadLink = document.getElementById('download-link');
|
const downloadLink = document.getElementById('download-link');
|
||||||
|
|
||||||
|
const OUTPUT_WIDTH = 145;
|
||||||
|
const OUTPUT_HEIGHT = 185;
|
||||||
|
const TARGET_RATIO = OUTPUT_WIDTH / OUTPUT_HEIGHT;
|
||||||
|
|
||||||
let captured = false;
|
let captured = false;
|
||||||
|
|
||||||
async function startCamera() {
|
async function startCamera() {
|
||||||
@ -53,10 +57,27 @@ function capturePhoto() {
|
|||||||
}
|
}
|
||||||
inputError.classList.add('hidden');
|
inputError.classList.add('hidden');
|
||||||
|
|
||||||
canvas.width = video.videoWidth;
|
const videoWidth = video.videoWidth;
|
||||||
canvas.height = video.videoHeight;
|
const videoHeight = video.videoHeight;
|
||||||
|
const videoRatio = videoWidth / videoHeight;
|
||||||
|
|
||||||
|
let sx, sy, sw, sh;
|
||||||
|
if (videoRatio > TARGET_RATIO) {
|
||||||
|
sh = videoHeight;
|
||||||
|
sw = sh * TARGET_RATIO;
|
||||||
|
sx = (videoWidth - sw) / 2;
|
||||||
|
sy = 0;
|
||||||
|
} else {
|
||||||
|
sw = videoWidth;
|
||||||
|
sh = sw / TARGET_RATIO;
|
||||||
|
sx = 0;
|
||||||
|
sy = (videoHeight - sh) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.width = OUTPUT_WIDTH;
|
||||||
|
canvas.height = OUTPUT_HEIGHT;
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
ctx.drawImage(video, sx, sy, sw, sh, 0, 0, OUTPUT_WIDTH, OUTPUT_HEIGHT);
|
||||||
|
|
||||||
const dataUrl = canvas.toDataURL('image/png');
|
const dataUrl = canvas.toDataURL('image/png');
|
||||||
const filename = `${sanitizeFilename(studentNumber)}.png`;
|
const filename = `${sanitizeFilename(studentNumber)}.png`;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user