Daniel251 commited on
Commit
3a12e42
·
verified ·
1 Parent(s): a90094f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +110 -164
app.py CHANGED
@@ -1,45 +1,45 @@
1
  """
2
  🎨 Basic Image Adjustments
3
- App 2 do Photoshop AI Ecosystem - Ajustes básicos de imagem
 
4
  """
 
5
  import gradio as gr
6
  from PIL import Image, ImageEnhance, ImageOps
7
  import tempfile
8
  import numpy as np
9
 
 
 
10
  def process_image(image, brightness=1.0, contrast=1.0, saturation=1.0, sharpness=1.0, auto_contrast=False):
11
  """Processa imagem com ajustes básicos"""
12
  if image is None:
13
  return None
14
 
15
  try:
16
- # Converter para PIL Image se for numpy array
17
  if isinstance(image, np.ndarray):
18
- img = Image.fromarray(image.astype('uint8'), 'RGB')
19
  else:
20
  img = image
21
 
22
- # Aplicar contraste automático se solicitado
23
  if auto_contrast:
24
  img = ImageOps.autocontrast(img, cutoff=2)
25
 
26
- # Aplicar ajustes na ordem correta
27
- # 1. Brilho
28
  if brightness != 1.0:
29
  enhancer = ImageEnhance.Brightness(img)
30
  img = enhancer.enhance(brightness)
31
 
32
- # 2. Contraste
33
  if contrast != 1.0:
34
  enhancer = ImageEnhance.Contrast(img)
35
  img = enhancer.enhance(contrast)
36
 
37
- # 3. Saturação
38
  if saturation != 1.0:
39
  enhancer = ImageEnhance.Color(img)
40
  img = enhancer.enhance(saturation)
41
 
42
- # 4. Nitidez
43
  if sharpness != 1.0:
44
  enhancer = ImageEnhance.Sharpness(img)
45
  img = enhancer.enhance(sharpness)
@@ -47,177 +47,121 @@ def process_image(image, brightness=1.0, contrast=1.0, saturation=1.0, sharpness
47
  return img
48
 
49
  except Exception as e:
50
- print(f"Erro no processamento: {e}")
51
  return image
52
 
53
- def get_preset(preset_name):
54
  """Retorna valores de preset"""
55
  presets = {
56
- 'vibrant': [1.2, 1.3, 1.4, 1.1, False],
57
- 'soft': [1.05, 0.9, 0.8, 0.9, False],
58
- 'dramatic': [0.9, 1.4, 0.9, 1.3, False],
59
- 'retro': [1.0, 1.1, 0.6, 1.0, False],
60
- 'bw': [1.0, 1.2, 0.0, 1.1, False],
61
- 'reset': [1.0, 1.0, 1.0, 1.0, False]
62
  }
63
- return presets.get(preset_name, [1.0, 1.0, 1.0, 1.0, False])
64
 
65
- def save_temp_image(image):
66
- """Salva imagem em arquivo temporário para download"""
67
  if image is None:
68
  return None
69
 
70
- temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png", prefix="adjusted_")
71
- image.save(temp_file.name, "PNG", optimize=True)
72
- return temp_file.name
 
 
 
73
 
74
- # Interface Gradio
75
- with gr.Blocks(
76
- title="🎨 Basic Image Adjustments",
77
- theme=gr.themes.Soft(),
78
- css="""
79
- .slider-container { margin: 15px 0; }
80
- .preset-btn { margin: 5px; width: 100%; }
81
  .header { text-align: center; padding: 20px; }
82
- .image-container { border: 2px solid #e0e0e0; border-radius: 10px; padding: 10px; }
 
 
 
83
  """
84
- ) as demo:
85
 
86
  # Cabeçalho
87
  gr.HTML("""
88
  <div class="header">
89
- <h1>🎨 Basic Image Adjustments</h1>
90
- <p><strong>App 2 do Photoshop AI Ecosystem</strong></p>
91
- <p>Ajuste brilho, contraste, saturação e nitidez de suas imagens</p>
92
  </div>
93
  """)
94
 
95
  with gr.Row():
96
- # Coluna da esquerda - Upload e Controles
97
  with gr.Column(scale=1):
98
  gr.Markdown("### 📤 Upload da Imagem")
 
99
 
100
- image_input = gr.Image(
101
- label="Arraste ou clique para selecionar",
102
- type="pil",
103
- height=200
104
- )
105
-
106
- gr.Markdown("### ⚙️ Controles de Ajuste")
107
 
108
- brightness = gr.Slider(
109
- minimum=0.0,
110
- maximum=2.0,
111
- value=1.0,
112
- step=0.1,
113
- label="☀️ Brilho",
114
- info="0.0 = Escuro | 1.0 = Normal | 2.0 = Brilhante"
115
- )
116
 
117
- contrast = gr.Slider(
118
- minimum=0.0,
119
- maximum=2.0,
120
- value=1.0,
121
- step=0.1,
122
- label="🎭 Contraste",
123
- info="0.0 = Baixo | 1.0 = Normal | 2.0 = Alto"
124
- )
125
-
126
- saturation = gr.Slider(
127
- minimum=0.0,
128
- maximum=2.0,
129
- value=1.0,
130
- step=0.1,
131
- label="🌈 Saturação",
132
- info="0.0 = P&B | 1.0 = Normal | 2.0 = Intenso"
133
- )
134
-
135
- sharpness = gr.Slider(
136
- minimum=0.0,
137
- maximum=2.0,
138
- value=1.0,
139
- step=0.1,
140
- label="🔍 Nitidez",
141
- info="0.0 = Borrado | 1.0 = Normal | 2.0 = Nítido"
142
- )
143
-
144
- auto_contrast = gr.Checkbox(
145
- label="⚡ Contraste Automático",
146
- value=False,
147
- info="Otimiza automaticamente o contraste"
148
- )
149
-
150
- # Coluna da direita - Presets e Resultado
151
  with gr.Column(scale=1):
152
  gr.Markdown("### 🎨 Presets Rápidos")
153
 
154
  with gr.Row():
155
- vibrant_btn = gr.Button("Vibrante", variant="secondary", size="sm", min_width=100)
156
- soft_btn = gr.Button("Suave", variant="secondary", size="sm", min_width=100)
157
-
158
- with gr.Row():
159
- dramatic_btn = gr.Button("Dramático", variant="secondary", size="sm", min_width=100)
160
- retro_btn = gr.Button("Retrô", variant="secondary", size="sm", min_width=100)
161
 
162
  with gr.Row():
163
- bw_btn = gr.Button("Preto & Branco", variant="secondary", size="sm", min_width=100)
164
- reset_btn = gr.Button("🔄 Resetar", variant="stop", size="sm", min_width=100)
 
165
 
166
  # Visualização
167
  with gr.Row():
168
  with gr.Column():
169
  gr.Markdown("### 👁️ Original")
170
- original_display = gr.Image(
171
- label="Imagem Original",
172
- type="pil",
173
- interactive=False,
174
- height=300
175
- )
176
 
177
  with gr.Column():
178
  gr.Markdown("### ✨ Ajustada")
179
- processed_display = gr.Image(
180
- label="Imagem Ajustada",
181
- type="pil",
182
- interactive=False,
183
- height=300
184
- )
185
 
186
- # Exportação
187
  with gr.Row():
188
  with gr.Column():
189
- gr.Markdown("### 💾 Exportar Imagem")
190
-
191
- export_btn = gr.Button(
192
- "📥 Download Imagem Ajustada",
193
- variant="primary",
194
- size="lg"
195
- )
196
-
197
- download_output = gr.File(
198
- label="Faça download da imagem processada",
199
- interactive=False
200
- )
201
 
202
- # Event Handlers
203
 
204
- # Atualizar imagem original quando upload for feito
205
- def update_original(image):
206
- return image
 
 
207
 
208
  image_input.change(
209
- fn=update_original,
210
  inputs=[image_input],
211
- outputs=[original_display]
212
  )
213
 
214
- # Processar imagem em tempo real quando controles mudarem
215
- def update_processed(image, bright, cont, sat, sharp, auto):
216
- if image is None:
217
- return None
218
- return process_image(image, bright, cont, sat, sharp, auto)
219
 
220
- # Conectar todos os controles à função de processamento
221
  controls = [brightness, contrast, saturation, sharpness, auto_contrast]
222
 
223
  for control in controls:
@@ -227,82 +171,84 @@ with gr.Blocks(
227
  outputs=[processed_display]
228
  )
229
 
230
- # Também processar quando imagem for carregada
231
- image_input.change(
232
- fn=lambda img: process_image(img, 1.0, 1.0, 1.0, 1.0, False) if img else None,
233
- inputs=[image_input],
234
- outputs=[processed_display]
235
- )
236
-
237
  # Presets
 
 
 
 
 
 
 
 
 
 
238
  vibrant_btn.click(
239
- fn=lambda: get_preset('vibrant'),
240
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
241
  )
242
 
243
  soft_btn.click(
244
- fn=lambda: get_preset('soft'),
245
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
246
  )
247
 
248
  dramatic_btn.click(
249
- fn=lambda: get_preset('dramatic'),
250
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
251
  )
252
 
253
  retro_btn.click(
254
- fn=lambda: get_preset('retro'),
255
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
256
  )
257
 
258
  bw_btn.click(
259
- fn=lambda: get_preset('bw'),
260
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
261
  )
262
 
263
  reset_btn.click(
264
- fn=lambda: get_preset('reset'),
265
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
266
  )
267
 
268
- # Exportação
269
- export_btn.click(
270
- fn=save_temp_image,
271
  inputs=[processed_display],
272
- outputs=[download_output]
273
  )
274
 
275
- # Informações e guia
276
- with gr.Accordion("📖 Guia de Uso", open=False):
277
  gr.Markdown("""
278
- ## Como usar este app:
279
-
280
- 1. **Carregue uma imagem** clicando na área de upload
281
- 2. **Ajuste os controles** deslizantes para modificar:
282
- - **Brilho**: Controla a luminosidade geral
283
- - **Contraste**: Aumenta/diminui diferença entre cores
284
- - **Saturação**: Controla intensidade das cores (0 = P&B)
285
- - **Nitidez**: Melhora definição dos detalhes
286
  3. **Use presets** para efeitos rápidos
287
  4. **Compare** original vs. ajustada
288
- 5. **Exporte** com o botão de download
289
 
290
  ## Dicas:
291
  - **Retratos**: Brilho 1.05, Contraste 1.1, Saturação 0.9
292
  - **Paisagens**: Brilho 1.1, Contraste 1.2, Saturação 1.2
293
  - **Produtos**: Brilho 1.0, Contraste 1.3, Saturação 1.0
 
 
 
 
 
294
  """)
295
 
296
  # Rodapé
297
  gr.HTML("""
298
- <div style="text-align: center; margin-top: 30px; padding: 20px; background: #f5f5f5; border-radius: 10px;">
299
  <p><strong>🎨 Basic Image Adjustments</strong> - App 2 do Photoshop AI Ecosystem</p>
300
- <p style="font-size: 0.9em; color: #666;">
301
- Cada app faz uma coisa específica, e faz bem!<br>
302
- Este app apenas ajusta brilho, contraste, saturação e nitidez.
303
  </p>
304
  </div>
305
  """)
306
 
307
- # Para Hugging Face Spaces, não precisa chamar demo.launch()
308
- # O Spaces detecta automaticamente a variável 'demo'
 
1
  """
2
  🎨 Basic Image Adjustments
3
+ Ajustes básicos de imagem
4
+ Otimizado para Hugging Face Spaces
5
  """
6
+
7
  import gradio as gr
8
  from PIL import Image, ImageEnhance, ImageOps
9
  import tempfile
10
  import numpy as np
11
 
12
+ # ========== FUNÇÕES PRINCIPAIS ==========
13
+
14
  def process_image(image, brightness=1.0, contrast=1.0, saturation=1.0, sharpness=1.0, auto_contrast=False):
15
  """Processa imagem com ajustes básicos"""
16
  if image is None:
17
  return None
18
 
19
  try:
20
+ # Converter para PIL Image
21
  if isinstance(image, np.ndarray):
22
+ img = Image.fromarray(image)
23
  else:
24
  img = image
25
 
26
+ # Aplicar contraste automático
27
  if auto_contrast:
28
  img = ImageOps.autocontrast(img, cutoff=2)
29
 
30
+ # Aplicar ajustes
 
31
  if brightness != 1.0:
32
  enhancer = ImageEnhance.Brightness(img)
33
  img = enhancer.enhance(brightness)
34
 
 
35
  if contrast != 1.0:
36
  enhancer = ImageEnhance.Contrast(img)
37
  img = enhancer.enhance(contrast)
38
 
 
39
  if saturation != 1.0:
40
  enhancer = ImageEnhance.Color(img)
41
  img = enhancer.enhance(saturation)
42
 
 
43
  if sharpness != 1.0:
44
  enhancer = ImageEnhance.Sharpness(img)
45
  img = enhancer.enhance(sharpness)
 
47
  return img
48
 
49
  except Exception as e:
50
+ print(f"Erro: {e}")
51
  return image
52
 
53
+ def get_preset_values(preset_name):
54
  """Retorna valores de preset"""
55
  presets = {
56
+ 'vibrant': {'brightness': 1.2, 'contrast': 1.3, 'saturation': 1.4, 'sharpness': 1.1, 'auto_contrast': False},
57
+ 'soft': {'brightness': 1.05, 'contrast': 0.9, 'saturation': 0.8, 'sharpness': 0.9, 'auto_contrast': False},
58
+ 'dramatic': {'brightness': 0.9, 'contrast': 1.4, 'saturation': 0.9, 'sharpness': 1.3, 'auto_contrast': False},
59
+ 'retro': {'brightness': 1.0, 'contrast': 1.1, 'saturation': 0.6, 'sharpness': 1.0, 'auto_contrast': False},
60
+ 'bw': {'brightness': 1.0, 'contrast': 1.2, 'saturation': 0.0, 'sharpness': 1.1, 'auto_contrast': False},
61
+ 'reset': {'brightness': 1.0, 'contrast': 1.0, 'saturation': 1.0, 'sharpness': 1.0, 'auto_contrast': False}
62
  }
63
+ return presets.get(preset_name, presets['reset'])
64
 
65
+ def save_image_for_download(image):
66
+ """Salva imagem para download"""
67
  if image is None:
68
  return None
69
 
70
+ try:
71
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png", prefix="adjusted_")
72
+ image.save(temp_file.name, "PNG", optimize=True)
73
+ return temp_file.name
74
+ except:
75
+ return None
76
 
77
+ # ========== INTERFACE GRADIO ==========
78
+
79
+ # Criar interface sem parâmetros no construtor (compatível com Gradio 6+)
80
+ with gr.Blocks(title="🎨 Basic Image Adjustments") as demo:
81
+
82
+ # CSS customizado
83
+ demo.css = """
84
  .header { text-align: center; padding: 20px; }
85
+ .slider-label { font-weight: bold; margin-bottom: 5px; }
86
+ .preset-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
87
+ .image-box { border: 1px solid #ddd; border-radius: 8px; padding: 10px; }
88
+ .download-btn { width: 100%; margin-top: 20px; }
89
  """
 
90
 
91
  # Cabeçalho
92
  gr.HTML("""
93
  <div class="header">
94
+ <h1 style="color: #4a6fa5;">🎨 Basic Image Adjustments</h1>
95
+ <p style="font-size: 1.1em;"><strong>App 2 do Photoshop AI Ecosystem</strong></p>
96
+ <p style="color: #666;">Ajuste brilho, contraste, saturação e nitidez</p>
97
  </div>
98
  """)
99
 
100
  with gr.Row():
101
+ # Coluna 1: Upload
102
  with gr.Column(scale=1):
103
  gr.Markdown("### 📤 Upload da Imagem")
104
+ image_input = gr.Image(type="pil", label="Clique ou arraste uma imagem", height=150)
105
 
106
+ gr.Markdown("### ⚙️ Controles")
 
 
 
 
 
 
107
 
108
+ brightness = gr.Slider(0.0, 2.0, 1.0, step=0.1, label="☀️ Brilho")
109
+ contrast = gr.Slider(0.0, 2.0, 1.0, step=0.1, label="🎭 Contraste")
110
+ saturation = gr.Slider(0.0, 2.0, 1.0, step=0.1, label="🌈 Saturação")
111
+ sharpness = gr.Slider(0.0, 2.0, 1.0, step=0.1, label="🔍 Nitidez")
 
 
 
 
112
 
113
+ auto_contrast = gr.Checkbox(label="⚡ Contraste Automático", value=False)
114
+
115
+ # Coluna 2: Presets
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  with gr.Column(scale=1):
117
  gr.Markdown("### 🎨 Presets Rápidos")
118
 
119
  with gr.Row():
120
+ vibrant_btn = gr.Button("Vibrante", variant="secondary")
121
+ soft_btn = gr.Button("Suave", variant="secondary")
122
+ dramatic_btn = gr.Button("Dramático", variant="secondary")
 
 
 
123
 
124
  with gr.Row():
125
+ retro_btn = gr.Button("Retrô", variant="secondary")
126
+ bw_btn = gr.Button("P&B", variant="secondary")
127
+ reset_btn = gr.Button("Resetar", variant="stop")
128
 
129
  # Visualização
130
  with gr.Row():
131
  with gr.Column():
132
  gr.Markdown("### 👁️ Original")
133
+ original_display = gr.Image(type="pil", interactive=False, height=250, label="Original")
 
 
 
 
 
134
 
135
  with gr.Column():
136
  gr.Markdown("### ✨ Ajustada")
137
+ processed_display = gr.Image(type="pil", interactive=False, height=250, label="Ajustada")
 
 
 
 
 
138
 
139
+ # Download
140
  with gr.Row():
141
  with gr.Column():
142
+ gr.Markdown("### 💾 Download")
143
+ download_btn = gr.Button("📥 Baixar Imagem Ajustada", variant="primary", size="lg")
144
+ download_file = gr.File(label="Arquivo para download", interactive=False)
 
 
 
 
 
 
 
 
 
145
 
146
+ # ========== EVENT HANDLERS ==========
147
 
148
+ # Quando imagem é carregada
149
+ def update_displays(image):
150
+ if image is None:
151
+ return None, None
152
+ return image, process_image(image, 1.0, 1.0, 1.0, 1.0, False)
153
 
154
  image_input.change(
155
+ fn=update_displays,
156
  inputs=[image_input],
157
+ outputs=[original_display, processed_display]
158
  )
159
 
160
+ # Processar quando controles mudam
161
+ def update_processed(img, b, c, s, sh, ac):
162
+ return process_image(img, b, c, s, sh, ac)
 
 
163
 
164
+ # Conectar todos os controles
165
  controls = [brightness, contrast, saturation, sharpness, auto_contrast]
166
 
167
  for control in controls:
 
171
  outputs=[processed_display]
172
  )
173
 
 
 
 
 
 
 
 
174
  # Presets
175
+ def apply_preset(preset_name):
176
+ preset = get_preset_values(preset_name)
177
+ return [
178
+ preset['brightness'],
179
+ preset['contrast'],
180
+ preset['saturation'],
181
+ preset['sharpness'],
182
+ preset['auto_contrast']
183
+ ]
184
+
185
  vibrant_btn.click(
186
+ fn=lambda: apply_preset('vibrant'),
187
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
188
  )
189
 
190
  soft_btn.click(
191
+ fn=lambda: apply_preset('soft'),
192
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
193
  )
194
 
195
  dramatic_btn.click(
196
+ fn=lambda: apply_preset('dramatic'),
197
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
198
  )
199
 
200
  retro_btn.click(
201
+ fn=lambda: apply_preset('retro'),
202
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
203
  )
204
 
205
  bw_btn.click(
206
+ fn=lambda: apply_preset('bw'),
207
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
208
  )
209
 
210
  reset_btn.click(
211
+ fn=lambda: apply_preset('reset'),
212
  outputs=[brightness, contrast, saturation, sharpness, auto_contrast]
213
  )
214
 
215
+ # Download
216
+ download_btn.click(
217
+ fn=save_image_for_download,
218
  inputs=[processed_display],
219
+ outputs=[download_file]
220
  )
221
 
222
+ # Guia de uso
223
+ with gr.Accordion("📖 Como usar", open=False):
224
  gr.Markdown("""
225
+ ## Instruções:
226
+ 1. **Faça upload** de uma imagem
227
+ 2. **Ajuste os controles** deslizantes
 
 
 
 
 
228
  3. **Use presets** para efeitos rápidos
229
  4. **Compare** original vs. ajustada
230
+ 5. **Baixe** o resultado
231
 
232
  ## Dicas:
233
  - **Retratos**: Brilho 1.05, Contraste 1.1, Saturação 0.9
234
  - **Paisagens**: Brilho 1.1, Contraste 1.2, Saturação 1.2
235
  - **Produtos**: Brilho 1.0, Contraste 1.3, Saturação 1.0
236
+
237
+ ## Valores:
238
+ - **0.0** = Mínimo efeito
239
+ - **1.0** = Normal (padrão)
240
+ - **2.0** = Máximo efeito
241
  """)
242
 
243
  # Rodapé
244
  gr.HTML("""
245
+ <div style="text-align: center; margin-top: 30px; padding: 15px; background: #f8f9fa; border-radius: 8px;">
246
  <p><strong>🎨 Basic Image Adjustments</strong> - App 2 do Photoshop AI Ecosystem</p>
247
+ <p style="color: #666; font-size: 0.9em;">
248
+ Cada app tem uma função específica • Este app apenas ajusta brilho, contraste, saturação e nitidez
 
249
  </p>
250
  </div>
251
  """)
252
 
253
+ # ========== FIM DO APLICATIVO ==========
254
+ # Não chame demo.launch() - O Hugging Face cuida disso