quarterturn commited on
Commit
48c57a9
·
verified ·
1 Parent(s): 7441cd4

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +124 -0
app.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import subprocess
3
+ import shutil
4
+ from pathlib import Path
5
+ import time
6
+
7
+ # Persistent temp directory for the Space
8
+ WORK_DIR = Path("/tmp/image_converter")
9
+ WORK_DIR.mkdir(exist_ok=True)
10
+
11
+ def convert_images(image_files):
12
+ if not image_files:
13
+ return None, "No files uploaded."
14
+
15
+ # Unique job folder
16
+ job_id = str(int(time.time()))
17
+ job_dir = WORK_DIR / job_id
18
+ job_dir.mkdir(exist_ok=True)
19
+ output_dir = job_dir / "outputs"
20
+ output_dir.mkdir(exist_ok=True)
21
+
22
+ results = []
23
+ successful = 0
24
+ supported_exts = {".png", ".jpg", ".jpeg", ".bmp", ".tiff", ".gif", ".webp"}
25
+
26
+ for idx, uploaded_file in enumerate(image_files):
27
+ orig_path = Path(uploaded_file.name)
28
+ suffix = orig_path.suffix.lower()
29
+ if suffix not in supported_exts:
30
+ results.append(f"⚠️ Skipped {orig_path.name}: unsupported format {suffix}")
31
+ continue
32
+
33
+ stem = orig_path.stem
34
+ input_path = job_dir / f"input_{idx}{suffix}"
35
+ shutil.copy(uploaded_file.name, input_path)
36
+
37
+ out_jpg = output_dir / f"{stem}small.jpg"
38
+
39
+ try:
40
+ # ImageMagick command: resize to fit 240x240, center crop to 240x240, auto-orient
41
+ result = subprocess.run([
42
+ "magick", str(input_path),
43
+ "-resize", "240x240",
44
+ "-gravity", "Center",
45
+ "-crop", "240x240+0+0",
46
+ "+repage",
47
+ "-auto-orient",
48
+ str(out_jpg)
49
+ ], capture_output=True, text=True)
50
+
51
+ if result.returncode != 0:
52
+ error_msg = result.stderr.strip() or "Unknown error"
53
+ results.append(f"❌ Failed {orig_path.name}: {error_msg}")
54
+ continue
55
+
56
+ successful += 1
57
+ results.append(f"✅ {orig_path.name} → {stem}small.jpg")
58
+
59
+ except Exception as e:
60
+ results.append(f"❌ Error on {orig_path.name}: {str(e)}")
61
+
62
+ if successful == 0:
63
+ shutil.rmtree(job_dir)
64
+ return None, "\n".join(results)
65
+
66
+ # Create ZIP with all converted JPGs
67
+ zip_path = job_dir / f"converted_images_{job_id}.zip"
68
+ shutil.make_archive(str(zip_path.with_suffix("")), 'zip', output_dir)
69
+
70
+ status_text = f"Processed {successful}/{len(image_files)} images successfully.\n\n" + "\n".join(results)
71
+ return str(zip_path), status_text
72
+
73
+
74
+ def clear_old_jobs():
75
+ cutoff = time.time() - 3600 # 1 hour
76
+ for job in WORK_DIR.iterdir():
77
+ if job.is_dir() and job.name.isdigit():
78
+ if job.stat().st_mtime < cutoff:
79
+ shutil.rmtree(job, ignore_errors=True)
80
+
81
+
82
+ # Gradio Interface
83
+ with gr.Blocks(title="Image to 240×240 JPG Converter") as demo:
84
+ gr.Markdown("# Image → 240×240 Square JPG")
85
+ gr.Markdown("""
86
+ Upload one or more images (.png, .jpg, .jpeg, .bmp, .tiff, .gif, .webp).
87
+ Each image will be:
88
+ - Resized to fit within 240×240
89
+ - Center-cropped to exactly 240×240
90
+ - Auto-oriented (based on EXIF)
91
+ - Saved as high-quality JPG named `originalnamesmall.jpg`
92
+ """)
93
+
94
+ with gr.Row():
95
+ with gr.Column(scale=3):
96
+ file_input = gr.File(
97
+ label="Upload Images",
98
+ file_count="multiple",
99
+ type="filepath"
100
+ )
101
+ with gr.Column(scale=1):
102
+ convert_btn = gr.Button("Convert", variant="primary", size="lg")
103
+
104
+ status_output = gr.Textbox(
105
+ label="Status Log",
106
+ lines=12,
107
+ value="Ready — upload images and click Convert."
108
+ )
109
+ download_output = gr.File(label="Download ZIP with converted images")
110
+
111
+ convert_btn.click(
112
+ fn=convert_images,
113
+ inputs=file_input,
114
+ outputs=[download_output, status_output],
115
+ show_progress=True
116
+ ).then(
117
+ fn=clear_old_jobs,
118
+ inputs=None,
119
+ outputs=None
120
+ )
121
+
122
+ gr.Markdown("Temporary files are automatically deleted after ~1 hour.")
123
+
124
+ demo.launch()