dschandra commited on
Commit
1d618a9
Β·
verified Β·
1 Parent(s): 23203dd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +102 -29
app.py CHANGED
@@ -2,57 +2,130 @@ import io
2
  from PIL import Image
3
  import gradio as gr
4
 
5
- def compress_image(file, target_value, unit):
6
- if file is None:
7
- return None, "Please upload an image"
 
 
 
8
 
9
- img = Image.open(file)
10
- original_bytes_io = io.BytesIO()
11
- img.save(original_bytes_io, format="PNG")
12
- original_size = original_bytes_io.tell()
13
 
14
- target_bytes = target_value * 1024 if unit == "KB" else target_value * 1024 * 1024
 
15
 
16
- def compress(img, target_bytes):
17
- for q in range(95, 74, -2):
 
18
  buf = io.BytesIO()
19
- img.convert("RGB").save(buf, format="JPEG", quality=q, optimize=True)
20
  if buf.tell() <= target_bytes:
21
  buf.seek(0)
22
- return buf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  buf.seek(0)
24
- return buf
 
 
 
25
 
26
- if target_bytes >= original_size:
27
- return img, f"Already under target size ({original_size/1024:.1f} KB)"
 
 
 
 
 
28
 
29
- compressed_buf = compress(img, target_bytes)
30
- compressed_img = Image.open(compressed_buf)
 
31
 
32
- saved = original_size - compressed_buf.getbuffer().nbytes
33
- pct = (saved / original_size) * 100
34
 
35
- msg = f"Original: {original_size/1024:.1f} KB | Compressed: {compressed_buf.getbuffer().nbytes/1024:.1f} KB | Saved: {pct:.1f}%"
36
 
37
- return compressed_img, msg
 
 
 
 
 
 
38
 
 
 
 
 
 
 
 
 
 
 
39
 
40
- with gr.Blocks() as demo:
41
- gr.Markdown("# πŸ—œοΈ ImagePress (Hugging Face Version)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
  with gr.Row():
44
  input_img = gr.Image(type="filepath", label="Upload Image")
45
- output_img = gr.Image(label="Compressed Image")
46
 
47
- target = gr.Number(value=200, label="Target Size")
48
- unit = gr.Radio(["KB", "MB"], value="KB", label="Unit")
 
49
 
50
- btn = gr.Button("⚑ Compress")
51
 
52
- result = gr.Textbox()
53
 
54
  btn.click(
55
- compress_image,
56
  inputs=[input_img, target, unit],
57
  outputs=[output_img, result]
58
  )
 
2
  from PIL import Image
3
  import gradio as gr
4
 
5
+ ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "webp"}
6
+
7
+ def get_file_size_label(size_bytes):
8
+ if size_bytes < 1024 * 1024:
9
+ return f"{size_bytes / 1024:.1f} KB"
10
+ return f"{size_bytes / (1024 * 1024):.2f} MB"
11
 
 
 
 
 
12
 
13
+ def compress_to_target(img, fmt, target_bytes):
14
+ buf = io.BytesIO()
15
 
16
+ # ---- PNG handling ----
17
+ if fmt == "PNG":
18
+ for level in range(1, 10):
19
  buf = io.BytesIO()
20
+ img.save(buf, format="PNG", optimize=True, compress_level=level)
21
  if buf.tell() <= target_bytes:
22
  buf.seek(0)
23
+ return buf, "PNG"
24
+
25
+ # fallback to WEBP lossless
26
+ buf = io.BytesIO()
27
+ img.save(buf, format="WEBP", lossless=True, quality=100)
28
+ if buf.tell() <= target_bytes:
29
+ buf.seek(0)
30
+ return buf, "WEBP"
31
+
32
+ for q in range(95, 79, -5):
33
+ buf = io.BytesIO()
34
+ img.save(buf, format="WEBP", quality=q, method=6)
35
+ if buf.tell() <= target_bytes:
36
+ buf.seek(0)
37
+ return buf, "WEBP"
38
+
39
  buf.seek(0)
40
+ return buf, "WEBP"
41
+
42
+ # ---- JPEG / WEBP ----
43
+ save_fmt = "JPEG" if fmt in ("JPEG", "JPG") else "WEBP"
44
 
45
+ for q in range(95, 74, -2):
46
+ buf = io.BytesIO()
47
+ if save_fmt == "JPEG":
48
+ img.save(buf, format="JPEG", quality=q, optimize=True,
49
+ subsampling=0 if q >= 85 else 2)
50
+ else:
51
+ img.save(buf, format="WEBP", quality=q, method=6)
52
 
53
+ if buf.tell() <= target_bytes:
54
+ buf.seek(0)
55
+ return buf, save_fmt
56
 
57
+ buf.seek(0)
58
+ return buf, save_fmt
59
 
 
60
 
61
+ def process_image(file, target_value, unit):
62
+ if file is None:
63
+ return None, "❌ Please upload an image"
64
+
65
+ try:
66
+ img = Image.open(file)
67
+ fmt = img.format or "JPEG"
68
 
69
+ # normalize image mode
70
+ if img.mode in ("RGBA", "LA", "P"):
71
+ if fmt == "JPEG":
72
+ background = Image.new("RGB", img.size, (255, 255, 255))
73
+ if img.mode == "P":
74
+ img = img.convert("RGBA")
75
+ background.paste(img, mask=img.split()[-1] if img.mode in ("RGBA", "LA") else None)
76
+ img = background
77
+ elif img.mode not in ("RGB", "L"):
78
+ img = img.convert("RGB")
79
 
80
+ # original size
81
+ original_buf = io.BytesIO()
82
+ img.save(original_buf, format="PNG")
83
+ original_size = original_buf.tell()
84
+
85
+ target_bytes = int(target_value * 1024) if unit == "KB" else int(target_value * 1024 * 1024)
86
+
87
+ # already small
88
+ if target_bytes >= original_size:
89
+ return img, f"βœ… Already optimized: {get_file_size_label(original_size)}"
90
+
91
+ # compress
92
+ compressed_buf, out_fmt = compress_to_target(img, fmt, target_bytes)
93
+ compressed_size = compressed_buf.getbuffer().nbytes
94
+
95
+ saved = max(0, original_size - compressed_size)
96
+ pct = (saved / original_size) * 100
97
+
98
+ result_msg = (
99
+ f"πŸ“¦ Original: {get_file_size_label(original_size)}\n"
100
+ f"πŸ—œοΈ Compressed: {get_file_size_label(compressed_size)}\n"
101
+ f"πŸ’Ύ Saved: {pct:.1f}%"
102
+ )
103
+
104
+ return Image.open(compressed_buf), result_msg
105
+
106
+ except Exception as e:
107
+ return None, f"❌ Error: {str(e)}"
108
+
109
+
110
+ # ---- UI ----
111
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
112
+ gr.Markdown("# πŸ—œοΈ ImagePress β€” Smart Compressor")
113
+ gr.Markdown("Compress images to target size **without visible quality loss**")
114
 
115
  with gr.Row():
116
  input_img = gr.Image(type="filepath", label="Upload Image")
117
+ output_img = gr.Image(label="Compressed Output")
118
 
119
+ with gr.Row():
120
+ target = gr.Number(value=200, label="Target Size")
121
+ unit = gr.Radio(["KB", "MB"], value="KB", label="Unit")
122
 
123
+ btn = gr.Button("⚑ Compress Image")
124
 
125
+ result = gr.Textbox(label="Result")
126
 
127
  btn.click(
128
+ fn=process_image,
129
  inputs=[input_img, target, unit],
130
  outputs=[output_img, result]
131
  )