face / index.html
6ee5ali's picture
Add 3 files
e96b052 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Face Blurring Web App</title>
<script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://cdn.jsdelivr.net/npm/face-api.js@0.22.2/dist/face-api.min.js"></script>
<style>
canvas {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex items-center justify-center p-6">
<div class="bg-white p-8 rounded-lg shadow-xl max-w-3xl w-full">
<h1 class="text-3xl font-bold mb-4 text-center">Face Blurring Web App</h1>
<p class="text-gray-600 mb-6 text-center">Upload an image and click "Blur Faces" to automatically blur detected faces.</p>
<div class="mb-4">
<label class="block text-gray-700 font-medium mb-2" for="imageUpload">Upload Image</label>
<input type="file" id="imageUpload" accept="image/*" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded file:border-0 file:text-sm file:font-semibold file:bg-blue-500 file:text-white hover:file:bg-blue-600" />
</div>
<div class="relative mx-auto w-full max-w-md border border-gray-300 rounded overflow-hidden bg-gray-200" style="aspect-ratio: 4/3;">
<img id="uploadedImage" src="" alt="Uploaded Image" class="w-full h-full object-contain hidden" />
<canvas id="overlayCanvas" class="absolute top-0 left-0 w-full h-full"></canvas>
</div>
<div class="mt-6 flex justify-center">
<button id="blurButton" class="bg-indigo-600 hover:bg-indigo-700 text-white font-semibold py-2 px-6 rounded-lg shadow-md transition disabled:opacity-50 disabled:cursor-not-allowed" disabled>
Blur Faces
</button>
</div>
<div id="status" class="mt-4 text-center text-sm text-gray-500"></div>
<a id="downloadLink" class="mt-4 block text-center text-blue-600 hover:underline hidden" download="blurred_image.jpg">Download Blurred Image</a>
</div>
<script>
const imageUpload = document.getElementById('imageUpload');
const uploadedImage = document.getElementById('uploadedImage');
const overlayCanvas = document.getElementById('overlayCanvas');
const blurButton = document.getElementById('blurButton');
const downloadLink = document.getElementById('downloadLink');
const status = document.getElementById('status');
let imageLoaded = false;
let detections = [];
// Load face-api models
Promise.all([
faceapi.nets.tinyFaceDetector.loadFromUri('https://cdn.jsdelivr.net/npm/face-api.js@0.22.2/weights'),
]).then(() => {
status.textContent = 'Models loaded. Ready to blur faces.';
});
imageUpload.addEventListener('change', (e) => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function (event) {
uploadedImage.src = event.target.result;
uploadedImage.onload = () => {
imageLoaded = true;
blurButton.disabled = false;
downloadLink.classList.add('hidden');
status.textContent = 'Image loaded. Click "Blur Faces".';
};
};
reader.readAsDataURL(file);
});
blurButton.addEventListener('click', async () => {
if (!imageLoaded) return;
blurButton.disabled = true;
status.textContent = 'Detecting faces...';
const img = uploadedImage;
const canvas = overlayCanvas;
const displaySize = { width: img.width, height: img.height };
faceapi.matchDimensions(canvas, displaySize);
detections = await faceapi.detectAllFaces(img, new faceapi.TinyFaceDetectorOptions());
status.textContent = `Detected ${detections.length} face(s). Blurring...`;
const offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = img.width;
offscreenCanvas.height = img.height;
const ctx = offscreenCanvas.getContext('2d');
ctx.drawImage(img, 0, 0);
detections.forEach(detection => {
const box = detection.box;
const faceImg = ctx.getImageData(box.x, box.y, box.width, box.height);
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = box.width;
tempCanvas.height = box.height;
tempCtx.putImageData(faceImg, 0, 0);
// Apply blur using a fake blur (as JS doesn't have Gaussian blur built-in)
tempCtx.filter = 'blur(10px)';
ctx.filter = 'blur(10px)';
ctx.drawImage(tempCanvas, box.x, box.y, box.width, box.height);
});
// Draw blurred image back to original container
const blurredImage = offscreenCanvas.toDataURL('image/jpeg');
uploadedImage.src = blurredImage;
// Enable download
downloadLink.href = blurredImage;
downloadLink.classList.remove('hidden');
downloadLink.download = 'blurred_image.jpg';
status.textContent = 'Face blurring completed!';
blurButton.disabled = false;
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-qwensite.hf.space/logo.svg" alt="qwensite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-qwensite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >QwenSite</a> - 🧬 <a href="https://enzostvs-qwensite.hf.space?remix=6ee5ali/face" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>