Daniel251 commited on
Commit
1f751ca
·
verified ·
1 Parent(s): 61bc548

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +258 -294
app.py CHANGED
@@ -9,6 +9,10 @@ import os
9
  from pathlib import Path
10
  import numpy as np
11
  from typing import Optional, Tuple
 
 
 
 
12
 
13
  class BasicAdjustmentsApp:
14
  """Micro-app dedicado apenas a ajustes básicos de imagem"""
@@ -16,18 +20,17 @@ class BasicAdjustmentsApp:
16
  def __init__(self):
17
  self.supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.webp']
18
 
19
- def load_image(self, file_path: str) -> Tuple[Optional[Image.Image], str]:
20
  """Carrega imagem para edição"""
21
  try:
22
- if not file_path:
23
  return None, "⚠️ Por favor, selecione uma imagem"
24
 
25
- if not os.path.exists(file_path):
26
- return None, "❌ Arquivo não encontrado"
27
-
28
- ext = Path(file_path).suffix.lower()
29
- if ext not in self.supported_formats:
30
- return None, f"❌ Formato não suportado: {ext}"
31
 
32
  img = Image.open(file_path)
33
 
@@ -50,19 +53,11 @@ class BasicAdjustmentsApp:
50
  auto_contrast: bool = False) -> Image.Image:
51
  """
52
  Aplica todos os ajustes básicos à imagem
53
-
54
- Args:
55
- image: Imagem PIL original
56
- brightness: Fator de brilho (0.0 a 2.0)
57
- contrast: Fator de contraste (0.0 a 2.0)
58
- saturation: Fator de saturação (0.0 a 2.0)
59
- sharpness: Fator de nitidez (0.0 a 2.0)
60
- auto_contrast: Aplicar contraste automático
61
-
62
- Returns:
63
- Imagem ajustada
64
  """
65
  try:
 
 
 
66
  # Fazer uma cópia para não modificar a original
67
  adjusted = image.copy()
68
 
@@ -109,6 +104,9 @@ class BasicAdjustmentsApp:
109
  def export_image(self, image: Image.Image, format: str = "PNG") -> Optional[str]:
110
  """Exporta imagem ajustada"""
111
  try:
 
 
 
112
  format_lower = format.lower()
113
  suffix = f".{format_lower}"
114
 
@@ -143,290 +141,256 @@ class BasicAdjustmentsApp:
143
  # Criar instância do app
144
  adjustment_app = BasicAdjustmentsApp()
145
 
146
- # Interface Gradio
147
- def create_interface():
148
- """Cria interface com controles bem organizados"""
149
 
150
- with gr.Blocks(
151
- title="✨ Basic Adjustments",
152
- theme=gr.themes.Soft(),
153
- css="""
154
- .slider-container {
155
- padding: 10px;
156
- border-radius: 8px;
157
- background: #f5f5f5;
158
- margin-bottom: 10px;
159
- }
160
- .preset-btn {
161
- margin: 5px;
162
- }
163
- .compare-container {
164
- display: flex;
165
- gap: 10px;
166
- }
167
- """
168
- ) as app:
169
-
170
- # Cabeçalho
171
- gr.Markdown("# ✨ Basic Adjustments")
172
- gr.Markdown("### App 2 do Photoshop AI Ecosystem - Ajustes Básicos")
173
- gr.Markdown("Ajuste brilho, contraste, saturação e nitidez de imagens")
174
-
175
- with gr.Row():
176
- # Coluna da esquerda - Upload e Controles
177
- with gr.Column(scale=1):
178
- gr.Markdown("## 📤 Importar Imagem")
179
-
180
- # Upload com destaque
181
- file_input = gr.File(
182
- label="Arraste ou clique para selecionar",
183
- file_types=["image"],
184
- height=100
185
- )
186
-
187
- load_btn = gr.Button(
188
- "📥 Carregar Imagem",
189
- variant="primary",
190
- size="lg",
191
- elem_classes="load-btn"
192
- )
193
-
194
- status_display = gr.Textbox(
195
- label="Status",
196
- value="Aguardando imagem...",
197
- interactive=False
198
- )
199
-
200
- # Presets rápidos
201
- gr.Markdown("## 🎨 Presets Rápidos")
202
- with gr.Row():
203
- preset_vibrant = gr.Button("Vibrante", variant="secondary", size="sm")
204
- preset_soft = gr.Button("Suave", variant="secondary", size="sm")
205
- preset_dramatic = gr.Button("Dramático", variant="secondary", size="sm")
206
- preset_retro = gr.Button("Retrô", variant="secondary", size="sm")
207
- preset_bw = gr.Button("Preto & Branco", variant="secondary", size="sm")
208
-
209
- reset_btn = gr.Button("🔄 Resetar Ajustes", variant="stop", size="lg")
210
 
211
- # Coluna do meio - Controles de Ajuste
212
- with gr.Column(scale=2):
213
- gr.Markdown("## ⚙️ Controles de Ajuste")
214
-
215
- # Brilho
216
- gr.Markdown("### ☀️ Brilho")
217
- brightness_slider = gr.Slider(
218
- minimum=0.0,
219
- maximum=2.0,
220
- value=1.0,
221
- step=0.05,
222
- label="",
223
- info="0 = Escuro total, 1 = Normal, 2 = Muito brilhante"
224
- )
225
-
226
- # Contraste
227
- gr.Markdown("### 🎭 Contraste")
228
- contrast_slider = gr.Slider(
229
- minimum=0.0,
230
- maximum=2.0,
231
- value=1.0,
232
- step=0.05,
233
- label="",
234
- info="0 = Sem contraste, 1 = Normal, 2 = Alto contraste"
235
- )
236
- auto_contrast = gr.Checkbox(label="Contraste Automático", value=False)
237
-
238
- # Saturação
239
- gr.Markdown("### 🌈 Saturação")
240
- saturation_slider = gr.Slider(
241
- minimum=0.0,
242
- maximum=2.0,
243
- value=1.0,
244
- step=0.05,
245
- label="",
246
- info="0 = Preto & Branco, 1 = Normal, 2 = Cores intensas"
247
- )
248
-
249
- # Nitidez
250
- gr.Markdown("### 🔍 Nitidez")
251
- sharpness_slider = gr.Slider(
252
- minimum=0.0,
253
- maximum=2.0,
254
- value=1.0,
255
- step=0.05,
256
- label="",
257
- info="0 = Borrado, 1 = Normal, 2 = Muito nítido"
258
- )
259
-
260
- # Linha de Visualização
261
- with gr.Row():
262
- with gr.Column():
263
- gr.Markdown("## 👁️ Original")
264
- original_image = gr.Image(
265
- label="Imagem Original",
266
- type="pil",
267
- interactive=False,
268
- height=400
269
- )
270
 
271
- with gr.Column():
272
- gr.Markdown("## Ajustada")
273
- adjusted_image = gr.Image(
274
- label="Imagem Ajustada",
275
- type="pil",
276
- interactive=False,
277
- height=400
278
- )
279
-
280
- # Linha de Ações
281
- with gr.Row():
282
- with gr.Column():
283
- gr.Markdown("## 💾 Exportar")
284
-
285
- format_select = gr.Dropdown(
286
- label="Formato de Saída",
287
- choices=["PNG", "JPEG", "WEBP"],
288
- value="PNG"
289
- )
290
-
291
- export_btn = gr.Button(
292
- "📤 Exportar Imagem Ajustada",
293
- variant="primary",
294
- size="lg"
295
- )
296
-
297
- download_output = gr.File(
298
- label="Download",
299
- interactive=False
300
- )
301
-
302
- # Seção de Informações
303
- with gr.Accordion("📖 Guia Rápido", open=False):
304
- gr.Markdown("""
305
- ### Como usar:
306
 
307
- 1. **Carregue uma imagem** usando o botão acima
308
- 2. **Ajuste os controles** deslizantes para modificar a imagem
309
- 3. **Use presets** para efeitos rápidos
310
- 4. **Compare** original vs. ajustada
311
- 5. **Exporte** quando estiver satisfeito
312
 
313
- ### Dicas:
314
- - **Brilho**: Ajuste a luminosidade geral
315
- - **Contraste**: Aumente para mais impacto visual
316
- - **Saturação**: Controle a intensidade das cores
317
- - **Nitidez**: Melhore os detalhes da imagem
318
- - **Contraste Automático**: Otimiza automaticamente o contraste
319
 
320
- ### Valores Recomendados:
321
- - **Retratos**: Brilho 1.05, Contraste 1.1, Saturação 0.9
322
- - **Paisagens**: Brilho 1.1, Contraste 1.2, Saturação 1.2
323
- - **Produtos**: Brilho 1.0, Contraste 1.3, Saturação 1.0
324
- """)
325
 
326
- # Event Handlers
327
-
328
- # Carregar imagem
329
- load_btn.click(
330
- fn=adjustment_app.load_image,
331
- inputs=[file_input],
332
- outputs=[original_image, status_display]
333
- ).then(
334
- fn=lambda img: img if img else None,
335
- inputs=[original_image],
336
- outputs=[adjusted_image]
337
- )
338
-
339
- # Aplicar ajustes em tempo real
340
- for slider in [brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]:
341
- slider.change(
342
- fn=adjustment_app.apply_adjustments,
343
- inputs=[
344
- original_image,
345
- brightness_slider,
346
- contrast_slider,
347
- saturation_slider,
348
- sharpness_slider,
349
- auto_contrast
350
- ],
351
- outputs=[adjusted_image]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  )
353
 
354
- # Presets
355
- def apply_preset(preset_name):
356
- preset = adjustment_app.get_preset(preset_name)
357
- return [
358
- preset['brightness'],
359
- preset['contrast'],
360
- preset['saturation'],
361
- preset['sharpness'],
362
- False # auto_contrast
363
- ]
364
-
365
- preset_vibrant.click(
366
- fn=apply_preset,
367
- inputs=[gr.Text("vibrant", visible=False)],
368
- outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
369
- )
370
-
371
- preset_soft.click(
372
- fn=apply_preset,
373
- inputs=[gr.Text("soft", visible=False)],
374
- outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
375
- )
376
-
377
- preset_dramatic.click(
378
- fn=apply_preset,
379
- inputs=[gr.Text("dramatic", visible=False)],
380
- outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
381
- )
382
-
383
- preset_retro.click(
384
- fn=apply_preset,
385
- inputs=[gr.Text("retro", visible=False)],
386
- outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
387
- )
388
-
389
- preset_bw.click(
390
- fn=apply_preset,
391
- inputs=[gr.Text("black_white", visible=False)],
392
- outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
393
- )
394
-
395
- # Resetar
396
- def reset_all():
397
- reset_vals = adjustment_app.reset_adjustments()
398
- return [
399
- reset_vals['brightness'],
400
- reset_vals['contrast'],
401
- reset_vals['saturation'],
402
- reset_vals['sharpness'],
403
- reset_vals['auto_contrast']
404
- ]
405
-
406
- reset_btn.click(
407
- fn=reset_all,
408
- outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
409
- )
410
-
411
- # Exportar
412
- export_btn.click(
413
- fn=adjustment_app.export_image,
414
- inputs=[adjusted_image, format_select],
415
- outputs=[download_output]
416
- )
417
 
418
- # Footer
419
- gr.Markdown("---")
420
- gr.Markdown("**✨ App 2 - Basic Adjustments** | Apenas ajustes básicos | Parte do Photoshop AI Ecosystem")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
 
422
- return app
 
 
423
 
424
- # Ponto de entrada
425
- if __name__ == "__main__":
426
- interface = create_interface()
427
- interface.launch(
428
- server_name="0.0.0.0",
429
- server_port=7861,
430
- share=False,
431
- debug=True
432
- )
 
9
  from pathlib import Path
10
  import numpy as np
11
  from typing import Optional, Tuple
12
+ import warnings
13
+
14
+ # Suprimir avisos específicos
15
+ warnings.filterwarnings("ignore", category=UserWarning)
16
 
17
  class BasicAdjustmentsApp:
18
  """Micro-app dedicado apenas a ajustes básicos de imagem"""
 
20
  def __init__(self):
21
  self.supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.webp']
22
 
23
+ def load_image(self, file) -> Tuple[Optional[Image.Image], str]:
24
  """Carrega imagem para edição"""
25
  try:
26
+ if file is None:
27
  return None, "⚠️ Por favor, selecione uma imagem"
28
 
29
+ # Em Gradio no Spaces, 'file' é um objeto temporário
30
+ if hasattr(file, 'name'):
31
+ file_path = file.name
32
+ else:
33
+ file_path = file
 
34
 
35
  img = Image.open(file_path)
36
 
 
53
  auto_contrast: bool = False) -> Image.Image:
54
  """
55
  Aplica todos os ajustes básicos à imagem
 
 
 
 
 
 
 
 
 
 
 
56
  """
57
  try:
58
+ if image is None:
59
+ return None
60
+
61
  # Fazer uma cópia para não modificar a original
62
  adjusted = image.copy()
63
 
 
104
  def export_image(self, image: Image.Image, format: str = "PNG") -> Optional[str]:
105
  """Exporta imagem ajustada"""
106
  try:
107
+ if image is None:
108
+ return None
109
+
110
  format_lower = format.lower()
111
  suffix = f".{format_lower}"
112
 
 
141
  # Criar instância do app
142
  adjustment_app = BasicAdjustmentsApp()
143
 
144
+ # Interface Gradio SIMPLIFICADA para Spaces
145
+ with gr.Blocks(title="✨ Basic Adjustments") as app:
 
146
 
147
+ # Cabeçalho
148
+ gr.Markdown("# ✨ Basic Adjustments")
149
+ gr.Markdown("### App 2 - Ajustes Básicos de Imagem")
150
+
151
+ with gr.Row():
152
+ # Coluna da esquerda - Upload
153
+ with gr.Column(scale=1):
154
+ gr.Markdown("## 📤 Importar")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
+ file_input = gr.Image(
157
+ label="Arraste ou clique para selecionar",
158
+ type="pil",
159
+ height=200
160
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
+ load_btn = gr.Button(
163
+ "📥 Carregar Imagem",
164
+ variant="primary",
165
+ size="lg"
166
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
+ status_display = gr.Textbox(
169
+ label="Status",
170
+ value="Aguardando imagem...",
171
+ interactive=False
172
+ )
173
 
174
+ # Presets rápidos
175
+ gr.Markdown("## 🎨 Presets Rápidos")
176
+ with gr.Row():
177
+ preset_vibrant = gr.Button("Vibrante", variant="secondary")
178
+ preset_soft = gr.Button("Suave", variant="secondary")
179
+ preset_dramatic = gr.Button("Dramático", variant="secondary")
180
 
181
+ with gr.Row():
182
+ preset_retro = gr.Button("Retrô", variant="secondary")
183
+ preset_bw = gr.Button("P&B", variant="secondary")
184
+ reset_btn = gr.Button("🔄 Resetar", variant="stop")
 
185
 
186
+ # Coluna do meio - Controles
187
+ with gr.Column(scale=2):
188
+ gr.Markdown("## ⚙️ Controles")
189
+
190
+ # Brilho
191
+ brightness_slider = gr.Slider(
192
+ minimum=0.0,
193
+ maximum=2.0,
194
+ value=1.0,
195
+ step=0.05,
196
+ label="☀️ Brilho",
197
+ info="0 = Escuro, 1 = Normal, 2 = Brilhante"
198
+ )
199
+
200
+ # Contraste
201
+ contrast_slider = gr.Slider(
202
+ minimum=0.0,
203
+ maximum=2.0,
204
+ value=1.0,
205
+ step=0.05,
206
+ label="🎭 Contraste",
207
+ info="0 = Baixo, 1 = Normal, 2 = Alto"
208
+ )
209
+
210
+ auto_contrast = gr.Checkbox(label="Contraste Automático", value=False)
211
+
212
+ # Saturação
213
+ saturation_slider = gr.Slider(
214
+ minimum=0.0,
215
+ maximum=2.0,
216
+ value=1.0,
217
+ step=0.05,
218
+ label="🌈 Saturação",
219
+ info="0 = P&B, 1 = Normal, 2 = Intenso"
220
+ )
221
+
222
+ # Nitidez
223
+ sharpness_slider = gr.Slider(
224
+ minimum=0.0,
225
+ maximum=2.0,
226
+ value=1.0,
227
+ step=0.05,
228
+ label="🔍 Nitidez",
229
+ info="0 = Borrado, 1 = Normal, 2 = Nítido"
230
+ )
231
+
232
+ # Visualização
233
+ with gr.Row():
234
+ with gr.Column():
235
+ gr.Markdown("## 👁️ Original")
236
+ original_image = gr.Image(
237
+ label="Original",
238
+ type="pil",
239
+ interactive=False,
240
+ height=300
241
  )
242
 
243
+ with gr.Column():
244
+ gr.Markdown("## ✨ Ajustada")
245
+ adjusted_image = gr.Image(
246
+ label="Ajustada",
247
+ type="pil",
248
+ interactive=False,
249
+ height=300
250
+ )
251
+
252
+ # Exportação
253
+ with gr.Row():
254
+ with gr.Column():
255
+ gr.Markdown("## 💾 Exportar")
256
+
257
+ format_select = gr.Dropdown(
258
+ label="Formato",
259
+ choices=["PNG", "JPEG", "WEBP"],
260
+ value="PNG"
261
+ )
262
+
263
+ export_btn = gr.Button(
264
+ "📤 Exportar Imagem",
265
+ variant="primary",
266
+ size="lg"
267
+ )
268
+
269
+ download_output = gr.File(
270
+ label="Download",
271
+ interactive=False
272
+ )
273
+
274
+ # Event Handlers
275
+
276
+ # Carregar imagem
277
+ def load_and_display(file):
278
+ if file is None:
279
+ return None, "⚠️ Selecione uma imagem primeiro", None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
 
281
+ img, status = adjustment_app.load_image(file)
282
+ return img, status, img
283
+
284
+ load_btn.click(
285
+ fn=load_and_display,
286
+ inputs=[file_input],
287
+ outputs=[original_image, status_display, adjusted_image]
288
+ )
289
+
290
+ # Aplicar ajustes
291
+ def apply_all_adjustments(img, bright, cont, sat, sharp, auto):
292
+ if img is None:
293
+ return None
294
+ return adjustment_app.apply_adjustments(img, bright, cont, sat, sharp, auto)
295
+
296
+ # Conectar sliders
297
+ brightness_slider.change(
298
+ fn=apply_all_adjustments,
299
+ inputs=[original_image, brightness_slider, contrast_slider,
300
+ saturation_slider, sharpness_slider, auto_contrast],
301
+ outputs=[adjusted_image]
302
+ )
303
+
304
+ contrast_slider.change(
305
+ fn=apply_all_adjustments,
306
+ inputs=[original_image, brightness_slider, contrast_slider,
307
+ saturation_slider, sharpness_slider, auto_contrast],
308
+ outputs=[adjusted_image]
309
+ )
310
+
311
+ saturation_slider.change(
312
+ fn=apply_all_adjustments,
313
+ inputs=[original_image, brightness_slider, contrast_slider,
314
+ saturation_slider, sharpness_slider, auto_contrast],
315
+ outputs=[adjusted_image]
316
+ )
317
+
318
+ sharpness_slider.change(
319
+ fn=apply_all_adjustments,
320
+ inputs=[original_image, brightness_slider, contrast_slider,
321
+ saturation_slider, sharpness_slider, auto_contrast],
322
+ outputs=[adjusted_image]
323
+ )
324
+
325
+ auto_contrast.change(
326
+ fn=apply_all_adjustments,
327
+ inputs=[original_image, brightness_slider, contrast_slider,
328
+ saturation_slider, sharpness_slider, auto_contrast],
329
+ outputs=[adjusted_image]
330
+ )
331
+
332
+ # Presets
333
+ def apply_preset(preset_name):
334
+ preset = adjustment_app.get_preset(preset_name)
335
+ return [
336
+ preset['brightness'],
337
+ preset['contrast'],
338
+ preset['saturation'],
339
+ preset['sharpness'],
340
+ False
341
+ ]
342
+
343
+ preset_vibrant.click(
344
+ fn=lambda: apply_preset('vibrant'),
345
+ outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
346
+ )
347
+
348
+ preset_soft.click(
349
+ fn=lambda: apply_preset('soft'),
350
+ outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
351
+ )
352
+
353
+ preset_dramatic.click(
354
+ fn=lambda: apply_preset('dramatic'),
355
+ outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
356
+ )
357
+
358
+ preset_retro.click(
359
+ fn=lambda: apply_preset('retro'),
360
+ outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
361
+ )
362
+
363
+ preset_bw.click(
364
+ fn=lambda: apply_preset('black_white'),
365
+ outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
366
+ )
367
+
368
+ # Resetar
369
+ def reset_all():
370
+ reset_vals = adjustment_app.reset_adjustments()
371
+ return [
372
+ reset_vals['brightness'],
373
+ reset_vals['contrast'],
374
+ reset_vals['saturation'],
375
+ reset_vals['sharpness'],
376
+ reset_vals['auto_contrast']
377
+ ]
378
+
379
+ reset_btn.click(
380
+ fn=reset_all,
381
+ outputs=[brightness_slider, contrast_slider, saturation_slider, sharpness_slider, auto_contrast]
382
+ )
383
+
384
+ # Exportar
385
+ export_btn.click(
386
+ fn=adjustment_app.export_image,
387
+ inputs=[adjusted_image, format_select],
388
+ outputs=[download_output]
389
+ )
390
 
391
+ # Footer
392
+ gr.Markdown("---")
393
+ gr.Markdown("**✨ App 2 - Photoshop AI Ecosystem** | Apenas ajustes básicos")
394
 
395
+ # Para Hugging Face Spaces, não chamamos launch() manualmente
396
+ # O Spaces automaticamente executa o app quando detecta 'app' como variável