import gradio as gr from PIL import Image import io import time import tempfile from pathlib import Path import zipfile def compress_image(file, quality=75, format_type="webp"): """Simple image compression function""" if file is None: return None, "Please upload an image" try: # Open image img = Image.open(file.name) original_size = Path(file.name).stat().st_size / 1024 # Compress to selected format output = io.BytesIO() if format_type == "webp": img.save(output, format='WEBP', quality=quality, method=4) extension = ".webp" elif format_type == "jpeg": if img.mode in ('RGBA', 'LA', 'P'): # Convert to RGB for JPEG rgb_img = Image.new('RGB', img.size, (255, 255, 255)) rgb_img.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None) img = rgb_img img.save(output, format='JPEG', quality=quality, optimize=True) extension = ".jpg" else: # png img.save(output, format='PNG', optimize=True) extension = ".png" output.seek(0) compressed_size = len(output.getvalue()) / 1024 saved_percent = (1 - compressed_size / original_size) * 100 # Save to temp file for download temp_path = tempfile.NamedTemporaryFile(delete=False, suffix=extension) temp_path.write(output.getvalue()) temp_path.close() info = f"""✅ Success! Original: {original_size:.1f} KB Compressed: {compressed_size:.1f} KB Saved: {saved_percent:.1f}% Format: {format_type.upper()} Quality: {quality}""" return temp_path.name, info except Exception as e: return None, f"❌ Error: {str(e)}" def compress_batch(files, quality=75, format_type="webp"): """Batch compression""" if not files: return None, "Please upload files" compressed_paths = [] total_saved = 0 with tempfile.TemporaryDirectory() as temp_dir: for file in files: try: img = Image.open(file.name) original_size = Path(file.name).stat().st_size / 1024 output = io.BytesIO() if format_type == "webp": img.save(output, format='WEBP', quality=quality) ext = ".webp" elif format_type == "jpeg": if img.mode in ('RGBA', 'LA', 'P'): rgb_img = Image.new('RGB', img.size, (255, 255, 255)) rgb_img.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None) img = rgb_img img.save(output, format='JPEG', quality=quality) ext = ".jpg" else: img.save(output, format='PNG', optimize=True) ext = ".png" output.seek(0) compressed_size = len(output.getvalue()) / 1024 saved = (1 - compressed_size / original_size) * 100 total_saved += saved # Save file temp_file = Path(temp_dir) / f"compressed_{Path(file.name).stem}{ext}" with open(temp_file, 'wb') as f: f.write(output.getvalue()) compressed_paths.append(temp_file) except Exception as e: print(f"Error: {e}") if not compressed_paths: return None, "No files could be compressed" # Create ZIP zip_path = Path(temp_dir) / "compressed_images.zip" with zipfile.ZipFile(zip_path, 'w') as zipf: for path in compressed_paths: zipf.write(path, path.name) # Copy to persistent location final_zip = Path("/tmp") / f"batch_{int(time.time())}.zip" import shutil shutil.copy(zip_path, final_zip) avg_saved = total_saved / len(compressed_paths) info = f"✅ Compressed {len(compressed_paths)} files\nAverage saving: {avg_saved:.1f}%" return str(final_zip), info # Create interface with gr.Blocks(title="Image Compressor", theme=gr.themes.Soft()) as demo: gr.Markdown(""" # 🚀 Image Compressor **Simple, fast, and private - all processing happens in your browser!** ### Features: - Compress JPEG, PNG, WebP - Batch processing with ZIP download - Adjustable quality - No uploads to server """) with gr.Tabs(): with gr.TabItem("Single Image"): with gr.Row(): with gr.Column(): input_file = gr.File(label="Upload Image", file_types=["image"]) format_choice = gr.Radio( choices=["webp", "jpeg", "png"], value="webp", label="Output Format" ) quality_slider = gr.Slider( minimum=30, maximum=100, value=75, label="Quality (higher = better quality, larger file)" ) compress_btn = gr.Button("Compress", variant="primary") with gr.Column(): output_file = gr.File(label="Download Compressed Image") info_text = gr.Textbox(label="Results", lines=8) with gr.TabItem("Batch Processing"): batch_files = gr.File( label="Upload Multiple Images", file_types=["image"], file_count="multiple" ) batch_format = gr.Radio( choices=["webp", "jpeg", "png"], value="webp", label="Output Format" ) batch_quality = gr.Slider( minimum=30, maximum=100, value=75, label="Quality" ) batch_btn = gr.Button("Compress All", variant="primary") batch_output = gr.File(label="Download ZIP") batch_info = gr.Textbox(label="Results", lines=5) # Connect functions compress_btn.click( compress_image, inputs=[input_file, quality_slider, format_choice], outputs=[output_file, info_text] ) batch_btn.click( compress_batch, inputs=[batch_files, batch_quality, batch_format], outputs=[batch_output, batch_info] ) # Launch if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)