MarcoMz commited on
Commit
423c2e6
·
verified ·
1 Parent(s): 714a33f

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +785 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Remove Bg
3
- emoji: 🦀
4
  colorFrom: pink
5
- colorTo: red
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: remove-bg
3
+ emoji: 🐳
4
  colorFrom: pink
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,785 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="pt-BR">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Magic BG Remover | Remova fundos de imagens facilmente</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .dropzone {
11
+ border: 2px dashed #9CA3AF;
12
+ transition: all 0.3s ease;
13
+ }
14
+ .dropzone.active {
15
+ border-color: #3B82F6;
16
+ background-color: #EFF6FF;
17
+ }
18
+ .image-preview {
19
+ max-height: 400px;
20
+ object-fit: contain;
21
+ }
22
+ .progress-bar {
23
+ height: 6px;
24
+ background-color: #E5E7EB;
25
+ border-radius: 3px;
26
+ overflow: hidden;
27
+ }
28
+ .progress-fill {
29
+ height: 100%;
30
+ background-color: #3B82F6;
31
+ width: 0%;
32
+ transition: width 0.3s ease;
33
+ }
34
+ .loading-spinner {
35
+ animation: spin 1s linear infinite;
36
+ }
37
+ @keyframes spin {
38
+ 0% { transform: rotate(0deg); }
39
+ 100% { transform: rotate(360deg); }
40
+ }
41
+ .error-message {
42
+ animation: shake 0.5s;
43
+ }
44
+ @keyframes shake {
45
+ 0%, 100% { transform: translateX(0); }
46
+ 10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
47
+ 20%, 40%, 60%, 80% { transform: translateX(5px); }
48
+ }
49
+ .pulse {
50
+ animation: pulse 2s infinite;
51
+ }
52
+ @keyframes pulse {
53
+ 0% { opacity: 1; }
54
+ 50% { opacity: 0.5; }
55
+ 100% { opacity: 1; }
56
+ }
57
+ .checkmark {
58
+ width: 20px;
59
+ height: 20px;
60
+ border-radius: 50%;
61
+ display: block;
62
+ stroke-width: 2;
63
+ stroke: #fff;
64
+ stroke-miterlimit: 10;
65
+ margin: 10% auto;
66
+ box-shadow: inset 0px 0px 0px #4bb71b;
67
+ animation: fill .4s ease-in-out .4s forwards, scale .3s ease-in-out .9s both;
68
+ }
69
+ .checkmark__circle {
70
+ stroke-dasharray: 166;
71
+ stroke-dashoffset: 166;
72
+ stroke-width: 2;
73
+ stroke-miterlimit: 10;
74
+ stroke: #4bb71b;
75
+ fill: none;
76
+ animation: stroke .6s cubic-bezier(0.65, 0, 0.45, 1) forwards;
77
+ }
78
+ .checkmark__check {
79
+ transform-origin: 50% 50%;
80
+ stroke-dasharray: 48;
81
+ stroke-dashoffset: 48;
82
+ animation: stroke .3s cubic-bezier(0.65, 0, 0.45, 1) .8s forwards;
83
+ }
84
+ @keyframes stroke {
85
+ 100% { stroke-dashoffset: 0; }
86
+ }
87
+ @keyframes scale {
88
+ 0%, 100% { transform: none; }
89
+ 50% { transform: scale3d(1.1, 1.1, 1); }
90
+ }
91
+ @keyframes fill {
92
+ 100% { box-shadow: inset 0px 0px 0px 30px #4bb71b; }
93
+ }
94
+ .transparent-bg {
95
+ background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect width="8" height="8" x="0" y="0" fill="%23e5e7eb"/><rect width="8" height="8" x="8" y="8" fill="%23e5e7eb"/></svg>');
96
+ background-size: 16px 16px;
97
+ }
98
+ </style>
99
+ </head>
100
+ <body class="bg-gray-50 min-h-screen">
101
+ <div class="container mx-auto px-4 py-12">
102
+ <!-- Header -->
103
+ <header class="text-center mb-12">
104
+ <h1 class="text-4xl font-bold text-gray-800 mb-2">
105
+ <span class="text-blue-600">Magic</span> BG Remover
106
+ </h1>
107
+ <p class="text-gray-600 max-w-2xl mx-auto">
108
+ Remova o fundo de suas imagens com um clique. Totalmente grátis e sem marcas d'água!
109
+ </p>
110
+ </header>
111
+
112
+ <!-- Main Content -->
113
+ <main class="max-w-4xl mx-auto bg-white rounded-xl shadow-md overflow-hidden">
114
+ <div class="md:flex">
115
+ <!-- Upload Section -->
116
+ <div class="p-8 md:w-1/2">
117
+ <div class="mb-6">
118
+ <h2 class="text-2xl font-semibold text-gray-800 mb-2">Envie sua imagem</h2>
119
+ <p class="text-gray-600">Formatos suportados: JPG, PNG, WEBP (Até 5MB)</p>
120
+ </div>
121
+
122
+ <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer mb-6">
123
+ <div class="flex flex-col items-center justify-center py-8">
124
+ <i class="fas fa-cloud-upload-alt text-4xl text-blue-500 mb-4"></i>
125
+ <p class="text-gray-600 mb-2">Arraste e solte sua imagem aqui</p>
126
+ <p class="text-gray-500 text-sm mb-4">ou</p>
127
+ <label for="fileInput" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-md cursor-pointer transition">
128
+ Selecione do computador
129
+ </label>
130
+ <input id="fileInput" type="file" accept="image/*" class="hidden">
131
+ </div>
132
+ </div>
133
+
134
+ <div id="uploadProgress" class="hidden">
135
+ <div class="flex items-center mb-2">
136
+ <span class="text-gray-700 mr-2">Processando:</span>
137
+ <span id="fileName" class="font-medium text-gray-800 truncate"></span>
138
+ </div>
139
+ <div class="progress-bar mb-2">
140
+ <div id="progressFill" class="progress-fill"></div>
141
+ </div>
142
+ <div class="flex justify-between text-sm text-gray-500">
143
+ <span id="progressText">0%</span>
144
+ <span id="progressStatus">Removendo fundo...</span>
145
+ </div>
146
+ </div>
147
+
148
+ <!-- Error Message -->
149
+ <div id="errorMessage" class="hidden bg-red-50 border-l-4 border-red-500 p-4 mb-4 error-message">
150
+ <div class="flex">
151
+ <div class="flex-shrink-0">
152
+ <i class="fas fa-exclamation-circle text-red-500"></i>
153
+ </div>
154
+ <div class="ml-3">
155
+ <p id="errorText" class="text-sm text-red-700">
156
+ Ocorreu um erro ao tentar remover o fundo. Por favor, tente novamente com uma imagem diferente.
157
+ </p>
158
+ </div>
159
+ </div>
160
+ </div>
161
+
162
+ <!-- Timeout Message -->
163
+ <div id="timeoutMessage" class="hidden bg-yellow-50 border-l-4 border-yellow-500 p-4 mb-4">
164
+ <div class="flex">
165
+ <div class="flex-shrink-0">
166
+ <i class="fas fa-clock text-yellow-500"></i>
167
+ </div>
168
+ <div class="ml-3">
169
+ <p id="timeoutText" class="text-sm text-yellow-700">
170
+ O processo está demorando mais que o normal. Você pode esperar ou tentar novamente.
171
+ </p>
172
+ </div>
173
+ </div>
174
+ </div>
175
+
176
+ <!-- Action Buttons -->
177
+ <div id="actionSection" class="hidden flex gap-3">
178
+ <button id="retryBtn" class="flex-1 bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-md transition">
179
+ <i class="fas fa-redo mr-2"></i> Tentar novamente
180
+ </button>
181
+ <button id="forceCompleteBtn" class="flex-1 bg-green-600 hover:bg-green-700 text-white px-6 py-2 rounded-md transition">
182
+ <i class="fas fa-check mr-2"></i> Finalizar agora
183
+ </button>
184
+ </div>
185
+ </div>
186
+
187
+ <!-- Result Section -->
188
+ <div id="resultSection" class="p-8 md:w-1/2 bg-gray-50 hidden">
189
+ <div class="mb-6">
190
+ <h2 class="text-2xl font-semibold text-gray-800 mb-2">Resultado</h2>
191
+ <p class="text-gray-600">Seu fundo foi removido com sucesso!</p>
192
+ </div>
193
+
194
+ <div class="flex justify-center mb-6">
195
+ <div class="relative">
196
+ <div class="transparent-bg rounded-lg">
197
+ <img id="resultImage" src="" alt="Resultado" class="image-preview rounded-lg shadow">
198
+ </div>
199
+ <div id="loadingIndicator" class="absolute inset-0 flex items-center justify-center bg-black bg-opacity-50 rounded-lg hidden">
200
+ <i class="fas fa-spinner loading-spinner text-4xl text-white"></i>
201
+ </div>
202
+ </div>
203
+ </div>
204
+
205
+ <div class="flex flex-col sm:flex-row gap-3">
206
+ <button id="downloadBtn" class="flex-1 bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-md flex items-center justify-center transition">
207
+ <i class="fas fa-download mr-2"></i> Baixar PNG
208
+ </button>
209
+ <button id="newImageBtn" class="flex-1 border border-gray-300 hover:bg-gray-100 text-gray-700 px-4 py-2 rounded-md flex items-center justify-center transition">
210
+ <i class="fas fa-redo mr-2"></i> Nova imagem
211
+ </button>
212
+ </div>
213
+ </div>
214
+
215
+ <!-- Preview Section (shown during processing) -->
216
+ <div id="previewSection" class="p-8 md:w-1/2 bg-gray-50 hidden">
217
+ <div class="mb-6">
218
+ <h2 class="text-2xl font-semibold text-gray-800 mb-2">Processando sua imagem</h2>
219
+ <p class="text-gray-600">Estamos removendo o fundo da sua imagem...</p>
220
+ </div>
221
+
222
+ <div class="flex justify-center mb-6">
223
+ <div class="relative">
224
+ <img id="previewImage" src="" alt="Pré-visualização" class="image-preview rounded-lg shadow">
225
+ <div class="absolute inset-0 flex items-center justify-center">
226
+ <i class="fas fa-spinner loading-spinner text-4xl text-blue-600"></i>
227
+ </div>
228
+ </div>
229
+ </div>
230
+
231
+ <div class="text-center">
232
+ <p id="processingStatus" class="text-gray-500 pulse">Isso pode levar alguns segundos...</p>
233
+ </div>
234
+ </div>
235
+ </div>
236
+ </main>
237
+
238
+ <!-- Features Section -->
239
+ <section class="max-w-4xl mx-auto mt-16">
240
+ <h2 class="text-2xl font-semibold text-center text-gray-800 mb-8">Por que escolher nosso removedor de fundo?</h2>
241
+
242
+ <div class="grid md:grid-cols-3 gap-8">
243
+ <div class="bg-white p-6 rounded-lg shadow-sm text-center">
244
+ <div class="text-blue-500 text-3xl mb-4">
245
+ <i class="fas fa-bolt"></i>
246
+ </div>
247
+ <h3 class="font-medium text-lg mb-2">Rápido e fácil</h3>
248
+ <p class="text-gray-600">Remova fundos em segundos com nossa tecnologia avançada.</p>
249
+ </div>
250
+
251
+ <div class="bg-white p-6 rounded-lg shadow-sm text-center">
252
+ <div class="text-blue-500 text-3xl mb-4">
253
+ <i class="fas fa-lock"></i>
254
+ </div>
255
+ <h3 class="font-medium text-lg mb-2">Privacidade garantida</h3>
256
+ <p class="text-gray-600">Suas imagens não são armazenadas em nossos servidores.</p>
257
+ </div>
258
+
259
+ <div class="bg-white p-6 rounded-lg shadow-sm text-center">
260
+ <div class="text-blue-500 text-3xl mb-4">
261
+ <i class="fas fa-heart"></i>
262
+ </div>
263
+ <h3 class="font-medium text-lg mb-2">Totalmente grátis</h3>
264
+ <p class="text-gray-600">Sem custos, sem limites, sem marcas d'água.</p>
265
+ </div>
266
+ </div>
267
+ </section>
268
+
269
+ <!-- Footer -->
270
+ <footer class="mt-16 text-center text-gray-500 text-sm">
271
+ <p>© 2023 Magic BG Remover. Todos os direitos reservados.</p>
272
+ <p class="mt-2">Desenvolvido com <i class="fas fa-heart text-red-500"></i> para criativos</p>
273
+ </footer>
274
+ </div>
275
+
276
+ <script>
277
+ document.addEventListener('DOMContentLoaded', function() {
278
+ const dropzone = document.getElementById('dropzone');
279
+ const fileInput = document.getElementById('fileInput');
280
+ const uploadProgress = document.getElementById('uploadProgress');
281
+ const progressFill = document.getElementById('progressFill');
282
+ const progressText = document.getElementById('progressText');
283
+ const progressStatus = document.getElementById('progressStatus');
284
+ const fileName = document.getElementById('fileName');
285
+ const previewSection = document.getElementById('previewSection');
286
+ const previewImage = document.getElementById('previewImage');
287
+ const resultSection = document.getElementById('resultSection');
288
+ const resultImage = document.getElementById('resultImage');
289
+ const downloadBtn = document.getElementById('downloadBtn');
290
+ const newImageBtn = document.getElementById('newImageBtn');
291
+ const loadingIndicator = document.getElementById('loadingIndicator');
292
+ const errorMessage = document.getElementById('errorMessage');
293
+ const errorText = document.getElementById('errorText');
294
+ const actionSection = document.getElementById('actionSection');
295
+ const retryBtn = document.getElementById('retryBtn');
296
+ const forceCompleteBtn = document.getElementById('forceCompleteBtn');
297
+ const processingStatus = document.getElementById('processingStatus');
298
+ const timeoutMessage = document.getElementById('timeoutMessage');
299
+ const timeoutText = document.getElementById('timeoutText');
300
+
301
+ let currentFile = null;
302
+ let originalImageData = null;
303
+ let progressInterval = null;
304
+ let timeoutInterval = null;
305
+ let isProcessing = false;
306
+ let stuckAt95 = false;
307
+ let processingComplete = false;
308
+
309
+ // Handle drag and drop events
310
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
311
+ dropzone.addEventListener(eventName, preventDefaults, false);
312
+ });
313
+
314
+ function preventDefaults(e) {
315
+ e.preventDefault();
316
+ e.stopPropagation();
317
+ }
318
+
319
+ ['dragenter', 'dragover'].forEach(eventName => {
320
+ dropzone.addEventListener(eventName, highlight, false);
321
+ });
322
+
323
+ ['dragleave', 'drop'].forEach(eventName => {
324
+ dropzone.addEventListener(eventName, unhighlight, false);
325
+ });
326
+
327
+ function highlight() {
328
+ dropzone.classList.add('active');
329
+ }
330
+
331
+ function unhighlight() {
332
+ dropzone.classList.remove('active');
333
+ }
334
+
335
+ // Handle dropped files
336
+ dropzone.addEventListener('drop', handleDrop, false);
337
+ fileInput.addEventListener('change', handleFiles, false);
338
+
339
+ function handleDrop(e) {
340
+ const dt = e.dataTransfer;
341
+ const files = dt.files;
342
+ handleFiles({ target: { files } });
343
+ }
344
+
345
+ function handleFiles(e) {
346
+ const files = e.target.files;
347
+ if (files.length === 0) return;
348
+
349
+ const file = files[0];
350
+ if (!file.type.match('image.*')) {
351
+ showError('Por favor, selecione um arquivo de imagem válido.');
352
+ return;
353
+ }
354
+
355
+ if (file.size > 5 * 1024 * 1024) {
356
+ showError('O arquivo é muito grande. Tamanho máximo: 5MB.');
357
+ return;
358
+ }
359
+
360
+ // Hide any previous error
361
+ errorMessage.classList.add('hidden');
362
+ timeoutMessage.classList.add('hidden');
363
+ actionSection.classList.add('hidden');
364
+
365
+ currentFile = file;
366
+ processImage(file);
367
+ }
368
+
369
+ function showError(message) {
370
+ errorText.textContent = message;
371
+ errorMessage.classList.remove('hidden');
372
+ setTimeout(() => {
373
+ errorMessage.classList.remove('error-message');
374
+ setTimeout(() => {
375
+ errorMessage.classList.add('error-message');
376
+ }, 10);
377
+ }, 10);
378
+
379
+ // Show action buttons
380
+ actionSection.classList.remove('hidden');
381
+
382
+ // Reset progress
383
+ clearProgress();
384
+ }
385
+
386
+ function showTimeout() {
387
+ timeoutText.textContent = 'O processo está demorando mais que o normal. Você pode esperar ou tentar novamente.';
388
+ timeoutMessage.classList.remove('hidden');
389
+ actionSection.classList.remove('hidden');
390
+ stuckAt95 = true;
391
+ }
392
+
393
+ function processImage(file) {
394
+ if (isProcessing) return;
395
+ isProcessing = true;
396
+ stuckAt95 = false;
397
+ processingComplete = false;
398
+
399
+ // Show upload progress
400
+ dropzone.classList.add('hidden');
401
+ uploadProgress.classList.remove('hidden');
402
+ fileName.textContent = file.name;
403
+
404
+ // Show preview while processing
405
+ const reader = new FileReader();
406
+ reader.onload = function(e) {
407
+ originalImageData = e.target.result;
408
+ previewImage.src = originalImageData;
409
+ previewSection.classList.remove('hidden');
410
+
411
+ // Start progress simulation
412
+ startProgressSimulation();
413
+
414
+ // Set timeout to check if stuck at 95%
415
+ timeoutInterval = setTimeout(showTimeout, 8000);
416
+
417
+ // Start actual background removal
418
+ removeBackground(file);
419
+ };
420
+ reader.onerror = function() {
421
+ showError('Erro ao ler o arquivo de imagem. Por favor, tente novamente.');
422
+ resetUI();
423
+ };
424
+ reader.readAsDataURL(file);
425
+ }
426
+
427
+ function startProgressSimulation() {
428
+ let progress = 0;
429
+ progressStatus.textContent = "Analisando imagem...";
430
+ processingStatus.textContent = "Analisando a imagem para remoção do fundo...";
431
+
432
+ progressInterval = setInterval(() => {
433
+ if (processingComplete) {
434
+ // If processing is complete, don't update progress
435
+ return;
436
+ }
437
+
438
+ if (stuckAt95) {
439
+ // If stuck at 95%, don't progress further
440
+ return;
441
+ }
442
+
443
+ progress += Math.random() * 5;
444
+
445
+ // Change status messages at certain progress points
446
+ if (progress > 30 && progress < 70) {
447
+ progressStatus.textContent = "Identificando o primeiro plano...";
448
+ processingStatus.textContent = "Identificando os elementos principais da imagem...";
449
+ } else if (progress >= 70) {
450
+ progressStatus.textContent = "Removendo o fundo...";
451
+ processingStatus.textContent = "Processamento final do fundo...";
452
+ }
453
+
454
+ if (progress >= 95) {
455
+ progress = 95; // Hold at 95% until actual completion
456
+ progressStatus.textContent = "Finalizando processamento...";
457
+ processingStatus.textContent = "Ajustes finais no resultado...";
458
+ }
459
+ updateProgress(progress);
460
+ }, 300);
461
+ }
462
+
463
+ function updateProgress(percent) {
464
+ progressFill.style.width = `${percent}%`;
465
+ progressText.textContent = `${Math.round(percent)}%`;
466
+ }
467
+
468
+ function clearProgress() {
469
+ if (progressInterval) {
470
+ clearInterval(progressInterval);
471
+ progressInterval = null;
472
+ }
473
+ if (timeoutInterval) {
474
+ clearTimeout(timeoutInterval);
475
+ timeoutInterval = null;
476
+ }
477
+ progressFill.style.width = '0%';
478
+ progressText.textContent = '0%';
479
+ isProcessing = false;
480
+ stuckAt95 = false;
481
+ processingComplete = false;
482
+ }
483
+
484
+ async function removeBackground(file) {
485
+ try {
486
+ // Simulate API delay (between 3-10 seconds for more realistic processing)
487
+ const delay = 3000 + Math.random() * 7000;
488
+
489
+ // Create a promise that resolves after the delay
490
+ const delayPromise = new Promise(resolve => setTimeout(resolve, delay));
491
+
492
+ // Create a promise that simulates the background removal
493
+ const processPromise = new Promise((resolve, reject) => {
494
+ // Simulate processing steps
495
+ setTimeout(() => {
496
+ // 10% chance to fail for demo purposes
497
+ if (Math.random() < 0.1) {
498
+ reject(new Error('Falha na conexão com o servidor de processamento'));
499
+ } else {
500
+ resolve();
501
+ }
502
+ }, delay);
503
+ });
504
+
505
+ // Wait for both promises
506
+ await Promise.all([delayPromise, processPromise]);
507
+
508
+ // Mark processing as complete before updating UI
509
+ processingComplete = true;
510
+
511
+ // Complete progress
512
+ updateProgress(100);
513
+ clearTimeout(timeoutInterval);
514
+
515
+ // Show completion animation
516
+ processingStatus.innerHTML = '<svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"><circle class="checkmark__circle" cx="26" cy="26" r="25" fill="none"/><path class="checkmark__check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8"/></svg>Processo concluído com sucesso!';
517
+
518
+ // Wait a bit before showing result (additional delay to ensure processing is really done)
519
+ await new Promise(resolve => setTimeout(resolve, 1500));
520
+
521
+ // Show result - simulate transparent background
522
+ previewSection.classList.add('hidden');
523
+
524
+ // Create a canvas to simulate transparent background
525
+ const canvas = document.createElement('canvas');
526
+ const ctx = canvas.getContext('2d');
527
+ const img = new Image();
528
+
529
+ img.onload = function() {
530
+ canvas.width = img.width;
531
+ canvas.height = img.height;
532
+
533
+ // Draw original image
534
+ ctx.drawImage(img, 0, 0);
535
+
536
+ // Get image data
537
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
538
+ const data = imageData.data;
539
+
540
+ // Improved background removal algorithm
541
+ // 1. First pass: Remove edges and very light/dark areas
542
+ for (let i = 0; i < data.length; i += 4) {
543
+ const r = data[i];
544
+ const g = data[i + 1];
545
+ const b = data[i + 2];
546
+
547
+ // Calculate brightness
548
+ const brightness = (r + g + b) / 3;
549
+
550
+ // Check if pixel is at the edges
551
+ const x = (i / 4) % canvas.width;
552
+ const y = Math.floor((i / 4) / canvas.width);
553
+ const isEdge = x < 10 || x > canvas.width - 10 ||
554
+ y < 10 || y > canvas.height - 10;
555
+
556
+ // Remove very light (white) or very dark (black) areas
557
+ if (brightness > 240 || brightness < 15 || isEdge) {
558
+ data[i + 3] = 0; // Make transparent
559
+ }
560
+ }
561
+
562
+ ctx.putImageData(imageData, 0, 0);
563
+
564
+ // 2. Second pass: Flood fill from edges to remove remaining background
565
+ const visited = new Array(canvas.width * canvas.height).fill(false);
566
+ const queue = [];
567
+
568
+ // Add edge pixels to queue
569
+ for (let x = 0; x < canvas.width; x++) {
570
+ queue.push({x, y: 0});
571
+ queue.push({x, y: canvas.height - 1});
572
+ }
573
+ for (let y = 1; y < canvas.height - 1; y++) {
574
+ queue.push({x: 0, y});
575
+ queue.push({x: canvas.width - 1, y});
576
+ }
577
+
578
+ // Process queue
579
+ while (queue.length > 0) {
580
+ const {x, y} = queue.shift();
581
+ const idx = (y * canvas.width + x) * 4;
582
+
583
+ if (visited[y * canvas.width + x]) continue;
584
+ visited[y * canvas.width + x] = true;
585
+
586
+ // Check if pixel is not already transparent
587
+ if (data[idx + 3] > 0) {
588
+ const r = data[idx];
589
+ const g = data[idx + 1];
590
+ const b = data[idx + 2];
591
+ const brightness = (r + g + b) / 3;
592
+
593
+ // If pixel is light enough, make it transparent
594
+ if (brightness > 200) {
595
+ data[idx + 3] = 0;
596
+
597
+ // Add neighbors to queue
598
+ if (x > 0) queue.push({x: x - 1, y});
599
+ if (x < canvas.width - 1) queue.push({x: x + 1, y});
600
+ if (y > 0) queue.push({x, y: y - 1});
601
+ if (y < canvas.height - 1) queue.push({x, y: y + 1});
602
+ }
603
+ }
604
+ }
605
+
606
+ // 3. Final pass: Smooth edges
607
+ const tempData = new Uint8ClampedArray(data);
608
+ for (let i = 0; i < data.length; i += 4) {
609
+ if (data[i + 3] === 0) continue;
610
+
611
+ const x = (i / 4) % canvas.width;
612
+ const y = Math.floor((i / 4) / canvas.width);
613
+
614
+ // Check if pixel is near a transparent pixel
615
+ let nearTransparent = false;
616
+ for (let dx = -1; dx <= 1; dx++) {
617
+ for (let dy = -1; dy <= 1; dy++) {
618
+ const nx = x + dx;
619
+ const ny = y + dy;
620
+
621
+ if (nx >= 0 && nx < canvas.width && ny >= 0 && ny < canvas.height) {
622
+ const nIdx = (ny * canvas.width + nx) * 4;
623
+ if (tempData[nIdx + 3] === 0) {
624
+ nearTransparent = true;
625
+ break;
626
+ }
627
+ }
628
+ }
629
+ if (nearTransparent) break;
630
+ }
631
+
632
+ // If near transparent, make semi-transparent for smooth edges
633
+ if (nearTransparent) {
634
+ data[i + 3] = 128;
635
+ }
636
+ }
637
+
638
+ ctx.putImageData(imageData, 0, 0);
639
+
640
+ // Set the result image
641
+ resultImage.src = canvas.toDataURL('image/png');
642
+ resultSection.classList.remove('hidden');
643
+
644
+ isProcessing = false;
645
+ stuckAt95 = false;
646
+ };
647
+
648
+ img.src = originalImageData;
649
+
650
+ } catch (error) {
651
+ console.error('Error removing background:', error);
652
+ showError('Ocorreu um erro ao tentar remover o fundo: ' + error.message);
653
+ resetUI();
654
+ }
655
+ }
656
+
657
+ // Download button
658
+ downloadBtn.addEventListener('click', function() {
659
+ if (!resultImage.src) return;
660
+
661
+ loadingIndicator.classList.remove('hidden');
662
+
663
+ // Create download link
664
+ const link = document.createElement('a');
665
+ link.href = resultImage.src;
666
+ link.download = `no-bg-${currentFile.name.replace(/\.[^/.]+$/, '')}.png`;
667
+ document.body.appendChild(link);
668
+ link.click();
669
+ document.body.removeChild(link);
670
+
671
+ setTimeout(() => {
672
+ loadingIndicator.classList.add('hidden');
673
+ }, 1000);
674
+ });
675
+
676
+ // New image button
677
+ newImageBtn.addEventListener('click', resetUI);
678
+
679
+ // Retry button
680
+ retryBtn.addEventListener('click', function() {
681
+ if (currentFile) {
682
+ resetUI();
683
+ processImage(currentFile);
684
+ }
685
+ });
686
+
687
+ // Force complete button
688
+ forceCompleteBtn.addEventListener('click', function() {
689
+ if (stuckAt95) {
690
+ // Simulate completion
691
+ processingComplete = true;
692
+ updateProgress(100);
693
+ clearTimeout(timeoutInterval);
694
+ timeoutMessage.classList.add('hidden');
695
+ actionSection.classList.add('hidden');
696
+
697
+ // Show result with warning
698
+ previewSection.classList.add('hidden');
699
+
700
+ // Create a canvas to simulate partial background removal
701
+ const canvas = document.createElement('canvas');
702
+ const ctx = canvas.getImageData();
703
+ const img = new Image();
704
+
705
+ img.onload = function() {
706
+ canvas.width = img.width;
707
+ canvas.height = img.height;
708
+
709
+ // Draw original image
710
+ ctx.drawImage(img, 0, 0);
711
+
712
+ // Simulate partial background removal (only edges)
713
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
714
+ const data = imageData.data;
715
+
716
+ for (let i = 0; i < data.length; i += 4) {
717
+ const isEdge = (i / 4) % canvas.width < 10 ||
718
+ (i / 4) % canvas.width > canvas.width - 10 ||
719
+ Math.floor((i / 4) / canvas.width) < 10 ||
720
+ Math.floor((i / 4) / canvas.width) > canvas.height - 10;
721
+
722
+ if (isEdge) {
723
+ // Make pixel transparent
724
+ data[i + 3] = 0;
725
+ }
726
+ }
727
+
728
+ ctx.putImageData(imageData, 0, 0);
729
+
730
+ // Set the result image
731
+ resultImage.src = canvas.toDataURL('image/png');
732
+ resultSection.classList.remove('hidden');
733
+
734
+ // Add warning to result
735
+ const warning = document.createElement('div');
736
+ warning.className = 'bg-yellow-50 border-l-4 border-yellow-500 p-4 mb-4';
737
+ warning.innerHTML = `
738
+ <div class="flex">
739
+ <div class="flex-shrink-0">
740
+ <i class="fas fa-exclamation-triangle text-yellow-500"></i>
741
+ </div>
742
+ <div class="ml-3">
743
+ <p class="text-sm text-yellow-700">
744
+ O processamento foi forçado. A qualidade pode não ser ideal.
745
+ <br>Recomendamos tentar novamente para um melhor resultado.
746
+ </p>
747
+ </div>
748
+ </div>
749
+ `;
750
+ resultSection.insertBefore(warning, resultSection.firstChild.nextSibling);
751
+
752
+ isProcessing = false;
753
+ stuckAt95 = false;
754
+ };
755
+
756
+ img.src = originalImageData;
757
+ }
758
+ });
759
+
760
+ function resetUI() {
761
+ currentFile = null;
762
+ originalImageData = null;
763
+ resultSection.classList.add('hidden');
764
+ previewSection.classList.add('hidden');
765
+ uploadProgress.classList.add('hidden');
766
+ errorMessage.classList.add('hidden');
767
+ timeoutMessage.classList.add('hidden');
768
+ actionSection.classList.add('hidden');
769
+ dropzone.classList.remove('hidden');
770
+ fileInput.value = '';
771
+ clearProgress();
772
+
773
+ // Remove any warning messages
774
+ const warnings = resultSection.querySelectorAll('.bg-yellow-50');
775
+ warnings.forEach(warning => warning.remove());
776
+ }
777
+
778
+ // Click dropzone to trigger file input
779
+ dropzone.addEventListener('click', function() {
780
+ fileInput.click();
781
+ });
782
+ });
783
+ </script>
784
+ <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-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=MarcoMz/remove-bg" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
785
+ </html>