File size: 5,836 Bytes
e96b052
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<!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>