DILSHAD737 commited on
Commit
71aee75
Β·
verified Β·
1 Parent(s): dae099f

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +268 -0
  2. requirements.txt +12 -0
app.py ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import tempfile
3
+ import os
4
+ from pathlib import Path
5
+ import zipfile
6
+ import time
7
+ from PIL import Image
8
+ import numpy as np
9
+
10
+ from utils.compressor import ImageCompressor
11
+ from utils.ai_analyzer import ContentAnalyzer
12
+ from utils.advanced import AdvancedFeatures
13
+
14
+ # Initialize components
15
+ compressor = ImageCompressor()
16
+ analyzer = ContentAnalyzer()
17
+ advanced = AdvancedFeatures()
18
+
19
+ def compress_single_image(file, preset="auto", target_size=None):
20
+ """Compress a single image"""
21
+ if file is None:
22
+ return None, "No file uploaded", None
23
+
24
+ try:
25
+ input_path = Path(file.name)
26
+
27
+ # Apply preset
28
+ if preset == "auto":
29
+ # Let AI decide
30
+ content_type, strategy = analyzer.analyze(input_path)
31
+ method = strategy.get("method", "avif")
32
+ quality = strategy.get("quality", 75)
33
+ elif preset == "extreme":
34
+ method = "avif"
35
+ quality = 60
36
+ elif preset == "high_quality":
37
+ method = "avif"
38
+ quality = 90
39
+ elif preset == "web_optimized":
40
+ method = "webp"
41
+ quality = 80
42
+ elif preset == "lossless":
43
+ method = "webp_lossless"
44
+ quality = 100
45
+ else:
46
+ method = "avif"
47
+ quality = 75
48
+
49
+ # Create output path
50
+ output_path = input_path.parent / f"compressed_{input_path.stem}"
51
+
52
+ # Compress
53
+ start_time = time.time()
54
+ result_path, ratio = compressor.compress(
55
+ input_path,
56
+ output_path,
57
+ method=method,
58
+ quality=quality
59
+ )
60
+ compression_time = time.time() - start_time
61
+
62
+ # Calculate metrics
63
+ original_size = input_path.stat().st_size / 1024 # KB
64
+ compressed_size = Path(result_path).stat().st_size / 1024
65
+
66
+ # Calculate SSIM if both images exist
67
+ ssim_score = None
68
+ try:
69
+ ssim_score = advanced.calculate_ssim(input_path, result_path)
70
+ except:
71
+ pass
72
+
73
+ info = f"""
74
+ βœ… Compression Complete!
75
+
76
+ Original: {original_size:.1f} KB
77
+ Compressed: {compressed_size:.1f} KB
78
+ Saved: {ratio:.1f}%
79
+ Time: {compression_time:.2f}s
80
+ Method: {method}
81
+ Quality: {quality}
82
+ """
83
+
84
+ if ssim_score:
85
+ info += f"\nSSIM Score: {ssim_score:.3f} (1.0 = identical)"
86
+
87
+ return result_path, info, None
88
+
89
+ except Exception as e:
90
+ return None, f"❌ Error: {str(e)}", None
91
+
92
+ def compress_batch(files, preset="auto"):
93
+ """Compress multiple images and return ZIP"""
94
+ if not files:
95
+ return None, "No files uploaded"
96
+
97
+ temp_dir = tempfile.mkdtemp()
98
+ compressed_files = []
99
+ total_saved = 0
100
+
101
+ for file in files:
102
+ try:
103
+ input_path = Path(file.name)
104
+ output_path = Path(temp_dir) / f"compressed_{input_path.name}"
105
+
106
+ _, ratio = compressor.compress(input_path, output_path, method="auto")
107
+ compressed_files.append(output_path)
108
+ total_saved += ratio
109
+
110
+ except Exception as e:
111
+ print(f"Error compressing {file.name}: {e}")
112
+
113
+ # Create ZIP
114
+ zip_path = Path(temp_dir) / "compressed_images.zip"
115
+ with zipfile.ZipFile(zip_path, 'w') as zipf:
116
+ for cf in compressed_files:
117
+ zipf.write(cf, cf.name)
118
+
119
+ info = f"Compressed {len(compressed_files)} files\nAverage saving: {total_saved/len(compressed_files):.1f}%"
120
+
121
+ return zip_path, info
122
+
123
+ def compare_images(original, compressed):
124
+ """Create side-by-side comparison with slider"""
125
+ if original is None or compressed is None:
126
+ return None
127
+
128
+ # Load images
129
+ orig_img = Image.open(original)
130
+ comp_img = Image.open(compressed)
131
+
132
+ # Resize to same height for comparison
133
+ target_height = 400
134
+ ratio = target_height / orig_img.size[1]
135
+ new_width = int(orig_img.size[0] * ratio)
136
+ orig_img = orig_img.resize((new_width, target_height), Image.Resampling.LANCZOS)
137
+ comp_img = comp_img.resize((new_width, target_height), Image.Resampling.LANCZOS)
138
+
139
+ # Create comparison image (side by side)
140
+ total_width = new_width * 2
141
+ comparison = Image.new('RGB', (total_width, target_height))
142
+ comparison.paste(orig_img, (0, 0))
143
+ comparison.paste(comp_img, (new_width, 0))
144
+
145
+ return comparison
146
+
147
+ # Create Gradio interface
148
+ with gr.Blocks(title="AI Image Compressor", theme=gr.themes.Soft()) as demo:
149
+ gr.Markdown("""
150
+ # πŸš€ AI-Powered Image Compressor
151
+ ### Better than imagecompressor.com - with AI analysis, AVIF support, and quality guarantees
152
+
153
+ **Features:**
154
+ - πŸ€– AI automatically detects image type (photo, screenshot, graphic)
155
+ - πŸ“¦ AVIF support (30% smaller than WebP)
156
+ - πŸ“Š SSIM quality validation
157
+ - 🎯 Target file size optimization
158
+ - πŸ”„ Batch processing with ZIP download
159
+ - πŸ’― Lossless compression option
160
+ """)
161
+
162
+ with gr.Tabs():
163
+ with gr.TabItem("πŸ“Έ Single Image"):
164
+ with gr.Row():
165
+ with gr.Column():
166
+ input_image = gr.File(label="Upload Image", file_types=["image"])
167
+ preset = gr.Radio(
168
+ choices=["auto", "extreme", "high_quality", "web_optimized", "lossless"],
169
+ value="auto",
170
+ label="Compression Preset",
171
+ info="auto = AI chooses best method"
172
+ )
173
+ compress_btn = gr.Button("Compress!", variant="primary")
174
+
175
+ with gr.Column():
176
+ output_image = gr.File(label="Download Compressed Image")
177
+ info_text = gr.Textbox(label="Compression Info", lines=8)
178
+
179
+ with gr.Row():
180
+ compare_btn = gr.Button("Compare Original vs Compressed")
181
+ comparison = gr.Image(label="Side-by-Side Comparison")
182
+
183
+ with gr.TabItem("πŸ“¦ Batch Processing"):
184
+ batch_files = gr.File(label="Upload Multiple Images", file_types=["image"], file_count="multiple")
185
+ batch_preset = gr.Radio(
186
+ choices=["auto", "extreme", "high_quality", "web_optimized"],
187
+ value="auto",
188
+ label="Compression Preset"
189
+ )
190
+ batch_btn = gr.Button("Compress All", variant="primary")
191
+ batch_output = gr.File(label="Download ZIP with Compressed Images")
192
+ batch_info = gr.Textbox(label="Batch Info", lines=5)
193
+
194
+ with gr.TabItem("πŸ“Š Quality Analysis"):
195
+ quality_img = gr.File(label="Upload Image", file_types=["image"])
196
+ analyze_btn = gr.Button("Analyze Image")
197
+ analysis_result = gr.JSON(label="Content Analysis")
198
+ ssim_result = gr.Textbox(label="Quality Metrics")
199
+
200
+ # Connect functions
201
+ compress_btn.click(
202
+ compress_single_image,
203
+ inputs=[input_image, preset],
204
+ outputs=[output_image, info_text, comparison]
205
+ )
206
+
207
+ compare_btn.click(
208
+ compare_images,
209
+ inputs=[input_image, output_image],
210
+ outputs=[comparison]
211
+ )
212
+
213
+ batch_btn.click(
214
+ compress_batch,
215
+ inputs=[batch_files, batch_preset],
216
+ outputs=[batch_output, batch_info]
217
+ )
218
+
219
+ def analyze_image(file):
220
+ if file is None:
221
+ return {"error": "No file"}, "No file uploaded"
222
+
223
+ content_type, strategy = analyzer.analyze(Path(file.name))
224
+
225
+ # Calculate additional metrics
226
+ img = Image.open(file.name)
227
+ width, height = img.size
228
+ format = img.format
229
+ mode = img.mode
230
+
231
+ analysis = {
232
+ "Content Type": content_type,
233
+ "Recommended Strategy": strategy,
234
+ "Image Details": {
235
+ "Dimensions": f"{width}x{height}",
236
+ "Format": format,
237
+ "Color Mode": mode,
238
+ "Megapixels": f"{width*height/1e6:.2f} MP"
239
+ }
240
+ }
241
+
242
+ # Estimate potential savings
243
+ if content_type == "screenshot_or_text":
244
+ savings = "80-95% with lossless WebP"
245
+ elif content_type == "graphic":
246
+ savings = "70-90% with PNG quantization"
247
+ else:
248
+ savings = "60-85% with AVIF"
249
+
250
+ quality_text = f"""
251
+ πŸ“Š Analysis Complete
252
+
253
+ Estimated Savings: {savings}
254
+ Best Format: {strategy.get('method', 'AVIF').upper()}
255
+ Recommended Quality: {strategy.get('quality', 75)}
256
+ """
257
+
258
+ return analysis, quality_text
259
+
260
+ analyze_btn.click(
261
+ analyze_image,
262
+ inputs=[quality_img],
263
+ outputs=[analysis_result, ssim_result]
264
+ )
265
+
266
+ # Launch
267
+ if __name__ == "__main__":
268
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio==4.16.0
2
+ pillow
3
+ opencv-python-headless==4.8.1.78
4
+ numpy==1.24.3
5
+ torch==2.1.0
6
+ torchvision==0.16.0
7
+ imageio==2.31.6
8
+ imageio-ffmpeg==0.4.9
9
+ scikit-image==0.22.0
10
+ piexif==1.1.3
11
+ pillow-heif==0.13.0
12
+ cairosvg==2.7.0