Alibrown commited on
Commit
300c1b4
·
verified ·
1 Parent(s): 1838770

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +206 -0
app.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from PIL import Image
3
+ import io
4
+ import time
5
+
6
+ def compress_image(image, target_format='webp', quality=85):
7
+ """
8
+ Compress and convert image to specified format
9
+ """
10
+ try:
11
+ if image is None:
12
+ return None, "No image provided"
13
+
14
+ # Convert format name for PIL
15
+ save_format = 'JPEG' if target_format.lower() == 'jpg' else target_format.upper()
16
+
17
+ # Create byte buffer
18
+ img_byte_arr = io.BytesIO()
19
+
20
+ # Handle different format requirements
21
+ if target_format.lower() in ['jpg', 'jpeg']:
22
+ # Convert to RGB if necessary for JPEG
23
+ if image.mode in ('RGBA', 'LA', 'P'):
24
+ image = image.convert('RGB')
25
+ image.save(img_byte_arr, format='JPEG', quality=quality, optimize=True)
26
+ elif target_format.lower() == 'png':
27
+ # PNG doesn't use quality parameter
28
+ image.save(img_byte_arr, format='PNG', optimize=True)
29
+ elif target_format.lower() == 'webp':
30
+ image.save(img_byte_arr, format='WEBP', quality=quality, optimize=True)
31
+
32
+ img_byte_arr.seek(0)
33
+ optimized_image = Image.open(img_byte_arr)
34
+
35
+ return optimized_image, None
36
+
37
+ except Exception as e:
38
+ return None, f"Compression error: {str(e)}"
39
+
40
+ def calculate_file_size(image, format_name, quality=85):
41
+ """Calculate file size for given format and quality"""
42
+ try:
43
+ img_byte_arr = io.BytesIO()
44
+ save_format = 'JPEG' if format_name.lower() == 'jpg' else format_name.upper()
45
+
46
+ if format_name.lower() in ['jpg', 'jpeg']:
47
+ if image.mode in ('RGBA', 'LA', 'P'):
48
+ image = image.convert('RGB')
49
+ image.save(img_byte_arr, format='JPEG', quality=quality, optimize=True)
50
+ elif format_name.lower() == 'png':
51
+ image.save(img_byte_arr, format='PNG', optimize=True)
52
+ elif format_name.lower() == 'webp':
53
+ image.save(img_byte_arr, format='WEBP', quality=quality, optimize=True)
54
+
55
+ return len(img_byte_arr.getvalue())
56
+ except:
57
+ return 0
58
+
59
+ def process_image(image, target_format, quality):
60
+ """Main processing function for Gradio interface"""
61
+
62
+ if image is None:
63
+ return None, "Please upload an image first", None
64
+
65
+ try:
66
+ # Get original image info
67
+ original_format = getattr(image, 'format', 'Unknown').lower()
68
+ if original_format == 'jpeg':
69
+ original_format = 'jpg'
70
+
71
+ # Calculate original size
72
+ original_size = calculate_file_size(image, original_format, 95) # Assume high quality for original
73
+
74
+ # Process image
75
+ optimized_image, error = compress_image(image, target_format, quality)
76
+
77
+ if error:
78
+ return None, error, None
79
+
80
+ # Calculate optimized size
81
+ optimized_size = calculate_file_size(optimized_image, target_format, quality)
82
+
83
+ # Calculate compression ratio
84
+ if original_size > 0:
85
+ compression_ratio = ((original_size - optimized_size) / original_size) * 100
86
+ else:
87
+ compression_ratio = 0
88
+
89
+ # Create info text
90
+ info_text = f"""
91
+ **Optimization Results:**
92
+ - Original format: {original_format.upper()}
93
+ - Target format: {target_format.upper()}
94
+ - Original size: ~{original_size:,} bytes
95
+ - Optimized size: ~{optimized_size:,} bytes
96
+ - Compression: {compression_ratio:.1f}%
97
+ - Quality setting: {quality}%
98
+ """
99
+
100
+ return optimized_image, info_text, optimized_image
101
+
102
+ except Exception as e:
103
+ return None, f"Processing error: {str(e)}", None
104
+
105
+ def create_interface():
106
+ """Create and configure Gradio interface"""
107
+
108
+ with gr.Blocks(title="Image Optimizer", theme=gr.themes.Soft()) as demo:
109
+
110
+ gr.Markdown("# 🖼️ Image Optimizer")
111
+ gr.Markdown("Upload an image and optimize it by changing format and compression settings.")
112
+
113
+ with gr.Row():
114
+ with gr.Column(scale=1):
115
+ # Input controls
116
+ input_image = gr.Image(
117
+ label="Upload Image",
118
+ type="pil",
119
+ sources=["upload"],
120
+ interactive=True
121
+ )
122
+
123
+ target_format = gr.Dropdown(
124
+ choices=["webp", "jpg", "png"],
125
+ value="webp",
126
+ label="Target Format",
127
+ info="WebP usually provides best compression"
128
+ )
129
+
130
+ quality = gr.Slider(
131
+ minimum=10,
132
+ maximum=95,
133
+ value=85,
134
+ step=5,
135
+ label="Quality",
136
+ info="Higher = better quality, larger file"
137
+ )
138
+
139
+ optimize_btn = gr.Button(
140
+ "🚀 Optimize Image",
141
+ variant="primary",
142
+ size="lg"
143
+ )
144
+
145
+ with gr.Column(scale=1):
146
+ # Output
147
+ output_image = gr.Image(
148
+ label="Optimized Image",
149
+ type="pil",
150
+ interactive=False
151
+ )
152
+
153
+ info_output = gr.Markdown(
154
+ label="Results",
155
+ value="Upload an image and click optimize to see results."
156
+ )
157
+
158
+ download_file = gr.File(
159
+ label="Download Optimized Image",
160
+ visible=False
161
+ )
162
+
163
+ # Auto-update on parameter change
164
+ def update_preview(image, fmt, qual):
165
+ if image is not None:
166
+ return process_image(image, fmt, qual)
167
+ return None, "Upload an image to see preview", None
168
+
169
+ # Event handlers
170
+ optimize_btn.click(
171
+ fn=process_image,
172
+ inputs=[input_image, target_format, quality],
173
+ outputs=[output_image, info_output, download_file]
174
+ )
175
+
176
+ # Auto-update when parameters change (optional - remove if too slow)
177
+ target_format.change(
178
+ fn=update_preview,
179
+ inputs=[input_image, target_format, quality],
180
+ outputs=[output_image, info_output, download_file]
181
+ )
182
+
183
+ quality.change(
184
+ fn=update_preview,
185
+ inputs=[input_image, target_format, quality],
186
+ outputs=[output_image, info_output, download_file]
187
+ )
188
+
189
+ gr.Markdown("""
190
+ ### Tips:
191
+ - **WebP** format usually provides the best compression ratio
192
+ - **Quality 85%** is often a good balance between size and quality
193
+ - **PNG** is lossless but creates larger files
194
+ - **JPG** is good for photos, but doesn't support transparency
195
+ """)
196
+
197
+ return demo
198
+
199
+ if __name__ == "__main__":
200
+ demo = create_interface()
201
+ demo.launch(
202
+ server_name="0.0.0.0", # For HuggingFace Spaces
203
+ server_port=7860, # Standard port for HF Spaces
204
+ share=False,
205
+ show_error=True
206
+ )