susipb commited on
Commit
2459747
·
verified ·
1 Parent(s): 5aedce4

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +6 -4
  2. index.html +398 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Converter Webp
3
- emoji: 📈
4
  colorFrom: green
5
- colorTo: green
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: converter-webp
3
+ emoji: 🐳
4
  colorFrom: green
5
+ colorTo: red
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,398 @@
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>Conversor WEBP para PNG/JPG/JPEG</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 #3b82f6;
12
+ transition: all 0.3s ease;
13
+ }
14
+ .dropzone.active {
15
+ border-color: #10b981;
16
+ background-color: #f0f9ff;
17
+ }
18
+ .progress-bar {
19
+ transition: width 0.3s ease;
20
+ }
21
+ #previewContainer {
22
+ transition: all 0.3s ease;
23
+ }
24
+ .download-btn:hover {
25
+ transform: translateY(-2px);
26
+ }
27
+ </style>
28
+ </head>
29
+ <body class="bg-gray-50 min-h-screen">
30
+ <div class="container mx-auto px-4 py-8 max-w-4xl">
31
+ <header class="text-center mb-8">
32
+ <h1 class="text-3xl font-bold text-blue-600 mb-2">
33
+ <i class="fas fa-exchange-alt mr-2"></i>Conversor de Imagens
34
+ </h1>
35
+ <p class="text-gray-600">Converta arquivos WEBP para PNG, JPG ou JPEG gratuitamente</p>
36
+ </header>
37
+
38
+ <div class="bg-white rounded-xl shadow-lg overflow-hidden mb-8">
39
+ <div class="p-6">
40
+ <div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer mb-6">
41
+ <div class="mx-auto w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mb-4">
42
+ <i class="fas fa-cloud-upload-alt text-blue-500 text-2xl"></i>
43
+ </div>
44
+ <h3 class="text-lg font-medium text-gray-700 mb-1">Arraste e solte seus arquivos aqui</h3>
45
+ <p class="text-gray-500 text-sm mb-4">ou clique para selecionar</p>
46
+ <input type="file" id="fileInput" class="hidden" accept="image/webp" multiple>
47
+ <button id="selectFilesBtn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md transition">
48
+ <i class="fas fa-folder-open mr-2"></i>Selecionar Arquivos
49
+ </button>
50
+ </div>
51
+
52
+ <div id="progressContainer" class="hidden mb-6">
53
+ <div class="flex justify-between mb-1">
54
+ <span class="text-sm font-medium text-gray-700">Progresso</span>
55
+ <span id="progressPercent" class="text-sm font-medium text-gray-700">0%</span>
56
+ </div>
57
+ <div class="w-full bg-gray-200 rounded-full h-2.5">
58
+ <div id="progressBar" class="progress-bar bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div>
59
+ </div>
60
+ </div>
61
+
62
+ <div id="settings" class="mb-6 hidden">
63
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
64
+ <div class="bg-gray-50 p-4 rounded-lg">
65
+ <label class="block text-sm font-medium text-gray-700 mb-2">Formato de Saída</label>
66
+ <select id="outputFormat" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
67
+ <option value="png">PNG</option>
68
+ <option value="jpeg">JPEG</option>
69
+ <option value="jpg">JPG</option>
70
+ </select>
71
+ </div>
72
+ <div class="bg-gray-50 p-4 rounded-lg">
73
+ <label class="block text-sm font-medium text-gray-700 mb-2">Qualidade (JPEG)</label>
74
+ <input id="quality" type="range" min="1" max="100" value="80" class="w-full" disabled>
75
+ <div class="flex justify-between text-xs text-gray-500 mt-1">
76
+ <span>Baixa</span>
77
+ <span id="qualityValue">80%</span>
78
+ <span>Alta</span>
79
+ </div>
80
+ </div>
81
+ <div class="bg-gray-50 p-4 rounded-lg">
82
+ <label class="block text-sm font-medium text-gray-700 mb-2">Nome do Arquivo</label>
83
+ <input id="fileName" type="text" class="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Nome personalizado (opcional)">
84
+ </div>
85
+ </div>
86
+ </div>
87
+
88
+ <div id="previewContainer" class="hidden">
89
+ <h3 class="text-lg font-medium text-gray-700 mb-4">Pré-visualização</h3>
90
+ <div id="previewGrid" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4"></div>
91
+ </div>
92
+ </div>
93
+
94
+ <div id="actionButtons" class="bg-gray-50 px-6 py-4 hidden">
95
+ <div class="flex flex-wrap justify-between items-center gap-4">
96
+ <div>
97
+ <span id="fileCount" class="text-sm text-gray-600"></span>
98
+ </div>
99
+ <div class="flex gap-2">
100
+ <button id="clearAllBtn" class="text-gray-600 hover:text-gray-800 px-4 py-2 rounded-md border border-gray-300 hover:bg-gray-100 transition">
101
+ <i class="fas fa-trash-alt mr-2"></i>Limpar Tudo
102
+ </button>
103
+ <button id="convertBtn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-md transition">
104
+ <i class="fas fa-exchange-alt mr-2"></i>Converter Tudo
105
+ </button>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </div>
110
+
111
+ <div class="bg-white rounded-xl shadow-lg overflow-hidden mb-8">
112
+ <div class="p-6">
113
+ <h2 class="text-xl font-bold text-gray-800 mb-4">Como converter WEBP para PNG/JPG/JPEG?</h2>
114
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
115
+ <div class="flex items-start">
116
+ <div class="bg-blue-100 p-3 rounded-full mr-4">
117
+ <i class="fas fa-upload text-blue-500"></i>
118
+ </div>
119
+ <div>
120
+ <h3 class="font-medium text-gray-800 mb-1">1. Envie seus arquivos</h3>
121
+ <p class="text-gray-600 text-sm">Arraste e solte ou clique para selecionar arquivos WEBP.</p>
122
+ </div>
123
+ </div>
124
+ <div class="flex items-start">
125
+ <div class="bg-blue-100 p-3 rounded-full mr-4">
126
+ <i class="fas fa-cog text-blue-500"></i>
127
+ </div>
128
+ <div>
129
+ <h3 class="font-medium text-gray-800 mb-1">2. Configure as opções</h3>
130
+ <p class="text-gray-600 text-sm">Escolha o formato de saída e ajuste a qualidade.</p>
131
+ </div>
132
+ </div>
133
+ <div class="flex items-start">
134
+ <div class="bg-blue-100 p-3 rounded-full mr-4">
135
+ <i class="fas fa-download text-blue-500"></i>
136
+ </div>
137
+ <div>
138
+ <h3 class="font-medium text-gray-800 mb-1">3. Baixe os arquivos</h3>
139
+ <p class="text-gray-600 text-sm">Converta e baixe suas imagens no formato desejado.</p>
140
+ </div>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </div>
145
+
146
+ <footer class="text-center text-gray-500 text-sm">
147
+ <p>© 2023 Conversor WEBP. Todos os direitos reservados.</p>
148
+ <p class="mt-1">Conversor online gratuito e seguro - seus arquivos não são enviados para nossos servidores.</p>
149
+ </footer>
150
+ </div>
151
+
152
+ <script>
153
+ document.addEventListener('DOMContentLoaded', function() {
154
+ // Elementos DOM
155
+ const dropzone = document.getElementById('dropzone');
156
+ const fileInput = document.getElementById('fileInput');
157
+ const selectFilesBtn = document.getElementById('selectFilesBtn');
158
+ const progressContainer = document.getElementById('progressContainer');
159
+ const progressBar = document.getElementById('progressBar');
160
+ const progressPercent = document.getElementById('progressPercent');
161
+ const settings = document.getElementById('settings');
162
+ const previewContainer = document.getElementById('previewContainer');
163
+ const previewGrid = document.getElementById('previewGrid');
164
+ const actionButtons = document.getElementById('actionButtons');
165
+ const fileCount = document.getElementById('fileCount');
166
+ const clearAllBtn = document.getElementById('clearAllBtn');
167
+ const convertBtn = document.getElementById('convertBtn');
168
+ const outputFormat = document.getElementById('outputFormat');
169
+ const quality = document.getElementById('quality');
170
+ const qualityValue = document.getElementById('qualityValue');
171
+ const fileName = document.getElementById('fileName');
172
+
173
+ let files = [];
174
+
175
+ // Atualizar valor da qualidade
176
+ quality.addEventListener('input', function() {
177
+ qualityValue.textContent = `${this.value}%`;
178
+ });
179
+
180
+ // Habilitar/desabilitar controle de qualidade baseado no formato
181
+ outputFormat.addEventListener('change', function() {
182
+ quality.disabled = this.value === 'png';
183
+ });
184
+
185
+ // Drag and drop events
186
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
187
+ dropzone.addEventListener(eventName, preventDefaults, false);
188
+ });
189
+
190
+ function preventDefaults(e) {
191
+ e.preventDefault();
192
+ e.stopPropagation();
193
+ }
194
+
195
+ ['dragenter', 'dragover'].forEach(eventName => {
196
+ dropzone.addEventListener(eventName, highlight, false);
197
+ });
198
+
199
+ ['dragleave', 'drop'].forEach(eventName => {
200
+ dropzone.addEventListener(eventName, unhighlight, false);
201
+ });
202
+
203
+ function highlight() {
204
+ dropzone.classList.add('active');
205
+ }
206
+
207
+ function unhighlight() {
208
+ dropzone.classList.remove('active');
209
+ }
210
+
211
+ dropzone.addEventListener('drop', handleDrop, false);
212
+
213
+ function handleDrop(e) {
214
+ const dt = e.dataTransfer;
215
+ const droppedFiles = dt.files;
216
+ handleFiles(droppedFiles);
217
+ }
218
+
219
+ // Selecionar arquivos via botão
220
+ selectFilesBtn.addEventListener('click', () => fileInput.click());
221
+
222
+ fileInput.addEventListener('change', function() {
223
+ handleFiles(this.files);
224
+ this.value = ''; // Resetar input para permitir selecionar o mesmo arquivo novamente
225
+ });
226
+
227
+ // Processar arquivos selecionados
228
+ function handleFiles(newFiles) {
229
+ const validFiles = Array.from(newFiles).filter(file =>
230
+ file.type === 'image/webp' || file.name.toLowerCase().endsWith('.webp')
231
+ );
232
+
233
+ if (validFiles.length === 0) {
234
+ alert('Por favor, selecione apenas arquivos WEBP.');
235
+ return;
236
+ }
237
+
238
+ files = [...files, ...validFiles];
239
+ updateUI();
240
+ showPreviews(validFiles);
241
+ }
242
+
243
+ // Mostrar pré-visualizações
244
+ function showPreviews(newFiles) {
245
+ newFiles.forEach(file => {
246
+ const reader = new FileReader();
247
+
248
+ reader.onload = function(e) {
249
+ const previewItem = document.createElement('div');
250
+ previewItem.className = 'bg-gray-50 rounded-lg overflow-hidden border border-gray-200';
251
+
252
+ previewItem.innerHTML = `
253
+ <div class="p-4">
254
+ <div class="aspect-w-16 aspect-h-9 mb-3">
255
+ <img src="${e.target.result}" alt="Preview" class="w-full h-auto rounded">
256
+ </div>
257
+ <div class="flex justify-between items-center">
258
+ <div class="truncate text-sm text-gray-700" title="${file.name}">${file.name}</div>
259
+ <button class="text-red-500 hover:text-red-700 delete-btn" data-name="${file.name}">
260
+ <i class="fas fa-times"></i>
261
+ </button>
262
+ </div>
263
+ <div class="text-xs text-gray-500 mt-1">${formatFileSize(file.size)}</div>
264
+ </div>
265
+ `;
266
+
267
+ previewGrid.appendChild(previewItem);
268
+
269
+ // Adicionar evento para botão de deletar
270
+ previewItem.querySelector('.delete-btn').addEventListener('click', function() {
271
+ const fileName = this.getAttribute('data-name');
272
+ removeFile(fileName);
273
+ });
274
+ };
275
+
276
+ reader.readAsDataURL(file);
277
+ });
278
+ }
279
+
280
+ // Remover arquivo individual
281
+ function removeFile(fileName) {
282
+ files = files.filter(file => file.name !== fileName);
283
+ updateUI();
284
+
285
+ // Remover pré-visualização
286
+ const previewItems = previewGrid.querySelectorAll('.delete-btn');
287
+ previewItems.forEach(item => {
288
+ if (item.getAttribute('data-name') === fileName) {
289
+ item.closest('div').parentNode.parentNode.remove();
290
+ }
291
+ });
292
+
293
+ // Esconder seções se não houver mais arquivos
294
+ if (files.length === 0) {
295
+ previewContainer.classList.add('hidden');
296
+ settings.classList.add('hidden');
297
+ actionButtons.classList.add('hidden');
298
+ }
299
+ }
300
+
301
+ // Limpar tudo
302
+ clearAllBtn.addEventListener('click', function() {
303
+ files = [];
304
+ previewGrid.innerHTML = '';
305
+ updateUI();
306
+ previewContainer.classList.add('hidden');
307
+ settings.classList.add('hidden');
308
+ actionButtons.classList.add('hidden');
309
+ });
310
+
311
+ // Converter arquivos
312
+ convertBtn.addEventListener('click', function() {
313
+ if (files.length === 0) return;
314
+
315
+ progressContainer.classList.remove('hidden');
316
+ progressBar.style.width = '0%';
317
+ progressPercent.textContent = '0%';
318
+
319
+ const format = outputFormat.value;
320
+ const qualityValue = quality.disabled ? null : parseInt(quality.value) / 100;
321
+ const customName = fileName.value.trim();
322
+
323
+ let processed = 0;
324
+
325
+ files.forEach((file, index) => {
326
+ const reader = new FileReader();
327
+
328
+ reader.onload = function(e) {
329
+ const img = new Image();
330
+
331
+ img.onload = function() {
332
+ const canvas = document.createElement('canvas');
333
+ canvas.width = img.width;
334
+ canvas.height = img.height;
335
+ const ctx = canvas.getContext('2d');
336
+ ctx.drawImage(img, 0, 0);
337
+
338
+ let outputFilename = customName
339
+ ? `${customName}${index > 0 ? `_${index}` : ''}.${format}`
340
+ : file.name.replace(/\.webp$/i, `.${format}`);
341
+
342
+ canvas.toBlob(function(blob) {
343
+ const url = URL.createObjectURL(blob);
344
+ const a = document.createElement('a');
345
+ a.href = url;
346
+ a.download = outputFilename;
347
+ document.body.appendChild(a);
348
+ a.click();
349
+ document.body.removeChild(a);
350
+ URL.revokeObjectURL(url);
351
+
352
+ processed++;
353
+ updateProgress(processed, files.length);
354
+
355
+ if (processed === files.length) {
356
+ setTimeout(() => {
357
+ progressContainer.classList.add('hidden');
358
+ }, 1000);
359
+ }
360
+ }, `image/${format}`, qualityValue);
361
+ };
362
+
363
+ img.src = e.target.result;
364
+ };
365
+
366
+ reader.readAsDataURL(file);
367
+ });
368
+ });
369
+
370
+ // Atualizar progresso
371
+ function updateProgress(current, total) {
372
+ const percent = Math.round((current / total) * 100);
373
+ progressBar.style.width = `${percent}%`;
374
+ progressPercent.textContent = `${percent}%`;
375
+ }
376
+
377
+ // Atualizar UI baseado nos arquivos
378
+ function updateUI() {
379
+ if (files.length > 0) {
380
+ fileCount.textContent = `${files.length} arquivo${files.length !== 1 ? 's' : ''} selecionado${files.length !== 1 ? 's' : ''}`;
381
+ settings.classList.remove('hidden');
382
+ previewContainer.classList.remove('hidden');
383
+ actionButtons.classList.remove('hidden');
384
+ }
385
+ }
386
+
387
+ // Formatar tamanho do arquivo
388
+ function formatFileSize(bytes) {
389
+ if (bytes === 0) return '0 Bytes';
390
+ const k = 1024;
391
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
392
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
393
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
394
+ }
395
+ });
396
+ </script>
397
+ <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=susipb/converter-webp" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
398
+ </html>