Zeph27 commited on
Commit
768c8db
·
1 Parent(s): 3f3fff8

res for each web

Browse files
Files changed (5) hide show
  1. app-v2.py +560 -0
  2. app.py +176 -102
  3. app_old.py +0 -307
  4. processed_images/1000116610.jpg +0 -0
  5. processed_images/process_log.json +30 -0
app-v2.py ADDED
@@ -0,0 +1,560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import zipfile
3
+ import shutil
4
+ import time
5
+ from PIL import Image, ImageDraw
6
+ import io
7
+ from rembg import remove
8
+ import gradio as gr
9
+ from concurrent.futures import ThreadPoolExecutor
10
+ from transformers import pipeline
11
+ import numpy as np
12
+ import json
13
+ import os
14
+
15
+ def remove_background_rembg(input_path):
16
+ print(f"Removing background using rembg for image: {input_path}")
17
+ with open(input_path, 'rb') as i:
18
+ input_image = i.read()
19
+ output_image = remove(input_image)
20
+ img = Image.open(io.BytesIO(output_image)).convert("RGBA")
21
+ return img
22
+
23
+ def remove_background_bria(input_path):
24
+ print(f"Removing background using bria for image: {input_path}")
25
+ pipe = pipeline("image-segmentation", model="briaai/RMBG-1.4", trust_remote_code=True, device=0)
26
+ pillow_image = pipe(input_path)
27
+ return pillow_image
28
+
29
+ def get_bounding_box_with_threshold(image, threshold):
30
+ # Convert image to numpy array
31
+ img_array = np.array(image)
32
+
33
+ # Get alpha channel
34
+ alpha = img_array[:,:,3]
35
+
36
+ # Find rows and columns where alpha > threshold
37
+ rows = np.any(alpha > threshold, axis=1)
38
+ cols = np.any(alpha > threshold, axis=0)
39
+
40
+ # Find the bounding box
41
+ top, bottom = np.where(rows)[0][[0, -1]]
42
+ left, right = np.where(cols)[0][[0, -1]]
43
+
44
+ if left < right and top < bottom:
45
+ return (left, top, right, bottom)
46
+ else:
47
+ return None
48
+
49
+ def position_logic(image_path, use_threshold=True):
50
+ image = Image.open(image_path)
51
+ image = image.convert("RGBA")
52
+
53
+ # Get the bounding box of the non-blank area with threshold
54
+ if use_threshold:
55
+ bbox = get_bounding_box_with_threshold(image, threshold=10)
56
+ else:
57
+ bbox = image.getbbox()
58
+ log = []
59
+
60
+ if bbox:
61
+ # Check 1 pixel around the image for non-transparent pixels
62
+ width, height = image.size
63
+ cropped_sides = []
64
+
65
+ # Define tolerance for transparency
66
+ tolerance = 30 # Adjust this value as needed
67
+
68
+ # Check top edge
69
+ if any(image.getpixel((x, 0))[3] > tolerance for x in range(width)):
70
+ cropped_sides.append("top")
71
+
72
+ # Check bottom edge
73
+ if any(image.getpixel((x, height-1))[3] > tolerance for x in range(width)):
74
+ cropped_sides.append("bottom")
75
+
76
+ # Check left edge
77
+ if any(image.getpixel((0, y))[3] > tolerance for y in range(height)):
78
+ cropped_sides.append("left")
79
+
80
+ # Check right edge
81
+ if any(image.getpixel((width-1, y))[3] > tolerance for y in range(height)):
82
+ cropped_sides.append("right")
83
+
84
+ if cropped_sides:
85
+ info_message = f"Info for {os.path.basename(image_path)}: The following sides of the image may contain cropped objects: {', '.join(cropped_sides)}"
86
+ print(info_message)
87
+ log.append({"info": info_message})
88
+ else:
89
+ info_message = f"Info for {os.path.basename(image_path)}: The image is not cropped."
90
+ print(info_message)
91
+ log.append({"info": info_message})
92
+
93
+ # Crop the image to the bounding box
94
+ image = image.crop(bbox)
95
+ log.append({"action": "crop", "bbox": [str(bbox[0]), str(bbox[1]), str(bbox[2]), str(bbox[3])]})
96
+
97
+ # Calculate the new size to expand the image
98
+ padding = 125
99
+ target_size = 1080
100
+ aspect_ratio = image.width / image.height
101
+
102
+ if len(cropped_sides) == 4:
103
+ # If the image is cropped on all sides, center crop it to fit the canvas
104
+ if aspect_ratio > 1: # Landscape
105
+ new_height = target_size
106
+ new_width = int(new_height * aspect_ratio)
107
+ left = (new_width - target_size) // 2
108
+ image = image.resize((new_width, new_height), Image.LANCZOS)
109
+ image = image.crop((left, 0, left + target_size, target_size))
110
+ else: # Portrait or square
111
+ new_width = target_size
112
+ new_height = int(new_width / aspect_ratio)
113
+ top = (new_height - target_size) // 2
114
+ image = image.resize((new_width, new_height), Image.LANCZOS)
115
+ image = image.crop((0, top, target_size, top + target_size))
116
+ log.append({"action": "center_crop_resize", "new_size": f"{target_size}x{target_size}"})
117
+ x, y = 0, 0
118
+ elif not cropped_sides:
119
+ # If the image is not cropped, expand it from center until it touches the padding
120
+ new_height = 1080 - 2 * padding # Ensure it touches top and bottom padding
121
+ new_width = int(new_height * aspect_ratio)
122
+
123
+ if new_width > 1080 - 2 * padding:
124
+ # If width exceeds available space, adjust based on width
125
+ new_width = 1080 - 2 * padding
126
+ new_height = int(new_width / aspect_ratio)
127
+
128
+ # Resize the image
129
+ image = image.resize((new_width, new_height), Image.LANCZOS)
130
+ log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
131
+
132
+ x = (1080 - new_width) // 2
133
+ y = 1080 - new_height - padding
134
+ else:
135
+ # New logic for handling cropped top and left, or top and right
136
+ if set(cropped_sides) == {"top", "left"} or set(cropped_sides) == {"top", "right"}:
137
+ new_height = target_size - padding # Ensure bottom padding
138
+ new_width = int(new_height * aspect_ratio)
139
+
140
+ # If new width exceeds canvas width, adjust based on width
141
+ if new_width > target_size:
142
+ new_width = target_size
143
+ new_height = int(new_width / aspect_ratio)
144
+
145
+ # Resize the image
146
+ image = image.resize((new_width, new_height), Image.LANCZOS)
147
+ log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
148
+
149
+ # Set position
150
+ if "left" in cropped_sides:
151
+ x = 0
152
+ else: # right in cropped_sides
153
+ x = target_size - new_width
154
+ y = 0
155
+
156
+ # If the resized image is taller than the canvas minus padding, crop from the bottom
157
+ if new_height > target_size - padding:
158
+ crop_bottom = new_height - (target_size - padding)
159
+ image = image.crop((0, 0, new_width, new_height - crop_bottom))
160
+ new_height = target_size - padding
161
+ log.append({"action": "crop_vertical", "bottom_pixels_removed": str(crop_bottom)})
162
+
163
+ log.append({"action": "position", "x": str(x), "y": str(y)})
164
+ elif set(cropped_sides) == {"bottom", "left"} or set(cropped_sides) == {"bottom", "right"}:
165
+ # Handle bottom & left or bottom & right cropped images
166
+ new_height = target_size - padding # Ensure top padding
167
+ new_width = int(new_height * aspect_ratio)
168
+
169
+ # If new width exceeds canvas width, adjust based on width
170
+ if new_width > target_size - padding:
171
+ new_width = target_size - padding
172
+ new_height = int(new_width / aspect_ratio)
173
+
174
+ # Resize the image without cropping or stretching
175
+ image = image.resize((new_width, new_height), Image.LANCZOS)
176
+ log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
177
+
178
+ # Set position
179
+ if "left" in cropped_sides:
180
+ x = 0
181
+ else: # right in cropped_sides
182
+ x = target_size - new_width
183
+ y = target_size - new_height
184
+
185
+ log.append({"action": "position", "x": str(x), "y": str(y)})
186
+ elif set(cropped_sides) == {"bottom", "left", "right"}:
187
+ # Expand the image from the center
188
+ new_width = target_size
189
+ new_height = int(new_width / aspect_ratio)
190
+
191
+ if new_height < target_size:
192
+ new_height = target_size
193
+ new_width = int(new_height * aspect_ratio)
194
+
195
+ image = image.resize((new_width, new_height), Image.LANCZOS)
196
+
197
+ # Crop to fit the canvas
198
+ left = (new_width - target_size) // 2
199
+ top = 0
200
+ image = image.crop((left, top, left + target_size, top + target_size))
201
+
202
+ log.append({"action": "expand_and_crop", "new_size": f"{target_size}x{target_size}"})
203
+ x, y = 0, 0
204
+ elif cropped_sides == ["top"]:
205
+ # New logic for handling only top-cropped images
206
+ if image.width > image.height:
207
+ new_width = target_size
208
+ new_height = int(target_size / aspect_ratio)
209
+ else:
210
+ new_height = target_size - padding # Ensure bottom padding
211
+ new_width = int(new_height * aspect_ratio)
212
+
213
+ # Resize the image
214
+ image = image.resize((new_width, new_height), Image.LANCZOS)
215
+ log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
216
+
217
+ x = (1080 - new_width) // 2
218
+ y = 0 # Align to top
219
+
220
+ # Apply padding only to non-cropped sides
221
+ x = max(padding, min(x, 1080 - new_width - padding))
222
+ elif cropped_sides in [["right"], ["left"]]:
223
+ # New logic for handling only right-cropped or left-cropped images
224
+ if image.width > image.height:
225
+ new_width = target_size - padding # Ensure padding on non-cropped side
226
+ new_height = int(new_width / aspect_ratio)
227
+ else:
228
+ new_height = target_size - (2 * padding) # Ensure top and bottom padding
229
+ new_width = int(new_height * aspect_ratio)
230
+
231
+ # Resize the image
232
+ image = image.resize((new_width, new_height), Image.LANCZOS)
233
+ log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
234
+
235
+ if cropped_sides == ["right"]:
236
+ x = 1080 - new_width # Align to right
237
+ else: # cropped_sides == ["left"]
238
+ x = 0 # Align to left
239
+ y = 1080 - new_height - padding # Respect bottom padding
240
+
241
+ # Ensure top padding is respected
242
+ if y < padding:
243
+ y = padding
244
+
245
+ log.append({"action": "position", "x": str(x), "y": str(y)})
246
+ elif set(cropped_sides) == {"left", "right"}:
247
+ # Logic for handling images cropped on both left and right sides
248
+ new_width = 1080 # Expand to full width of canvas
249
+
250
+ # Calculate the aspect ratio of the original image
251
+ aspect_ratio = image.width / image.height
252
+
253
+ # Calculate the new height while maintaining aspect ratio
254
+ new_height = int(new_width / aspect_ratio)
255
+
256
+ # Resize the image
257
+ image = image.resize((new_width, new_height), Image.LANCZOS)
258
+ log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
259
+
260
+ # Set horizontal position (always 0 as it spans full width)
261
+ x = 0
262
+
263
+ # Calculate vertical position to respect bottom padding
264
+ y = 1080 - new_height - padding
265
+
266
+ # If the resized image is taller than the canvas, crop from the top only
267
+ if new_height > 1080 - padding:
268
+ crop_top = new_height - (1080 - padding)
269
+ image = image.crop((0, crop_top, new_width, new_height))
270
+ new_height = 1080 - padding
271
+ y = 0
272
+ log.append({"action": "crop_vertical", "top_pixels_removed": str(crop_top)})
273
+ else:
274
+ # Align the image to the bottom with padding
275
+ y = 1080 - new_height - padding
276
+
277
+ log.append({"action": "position", "x": str(x), "y": str(y)})
278
+ elif cropped_sides == ["bottom"]:
279
+ # Logic for handling images cropped on the bottom side
280
+ # Calculate the aspect ratio of the original image
281
+ aspect_ratio = image.width / image.height
282
+
283
+ if aspect_ratio < 1: # Portrait orientation
284
+ new_height = 1080 - padding # Full height with top padding
285
+ new_width = int(new_height * aspect_ratio)
286
+
287
+ # If the new width exceeds the canvas width, adjust it
288
+ if new_width > 1080:
289
+ new_width = 1080
290
+ new_height = int(new_width / aspect_ratio)
291
+ else: # Landscape orientation
292
+ new_width = 1080 - (2 * padding)
293
+ new_height = int(new_width / aspect_ratio)
294
+
295
+ # If the new height exceeds the canvas height, adjust it
296
+ if new_height > 1080:
297
+ new_height = 1080
298
+ new_width = int(new_height * aspect_ratio)
299
+
300
+ # Resize the image
301
+ image = image.resize((new_width, new_height), Image.LANCZOS)
302
+ log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
303
+
304
+ # Set horizontal position (centered)
305
+ x = (1080 - new_width) // 2
306
+
307
+ # Set vertical position (touching bottom edge for all cases)
308
+ y = 1080 - new_height
309
+
310
+ log.append({"action": "position", "x": str(x), "y": str(y)})
311
+ else:
312
+ # Use the original resizing logic for other partially cropped images
313
+ if image.width > image.height:
314
+ new_width = target_size
315
+ new_height = int(target_size / aspect_ratio)
316
+ else:
317
+ new_height = target_size
318
+ new_width = int(target_size * aspect_ratio)
319
+
320
+ # Resize the image
321
+ image = image.resize((new_width, new_height), Image.LANCZOS)
322
+ log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
323
+
324
+ # Center horizontally for all images
325
+ x = (1080 - new_width) // 2
326
+ y = 1080 - new_height - padding
327
+
328
+ # Adjust positions for cropped sides
329
+ if "top" in cropped_sides:
330
+ y = 0
331
+ elif "bottom" in cropped_sides:
332
+ y = 1080 - new_height
333
+ if "left" in cropped_sides:
334
+ x = 0
335
+ elif "right" in cropped_sides:
336
+ x = 1080 - new_width
337
+
338
+ # Apply padding only to non-cropped sides, but keep horizontal centering
339
+ if "left" not in cropped_sides and "right" not in cropped_sides:
340
+ x = (1080 - new_width) // 2 # Always center horizontally
341
+ if "top" not in cropped_sides and "bottom" not in cropped_sides:
342
+ y = max(padding, min(y, 1080 - new_height - padding))
343
+
344
+ return log, image, x, y
345
+
346
+ def process_single_image(image_path, output_folder, bg_method, output_format, bg_choice, custom_color, watermark_path=None):
347
+ add_padding_line = False
348
+ padding = 125
349
+
350
+ filename = os.path.basename(image_path)
351
+ try:
352
+ print(f"Processing image: {filename}")
353
+ if bg_method == 'rembg':
354
+ image_with_no_bg = remove_background_rembg(image_path)
355
+ elif bg_method == 'bria':
356
+ image_with_no_bg = remove_background_bria(image_path)
357
+
358
+ temp_image_path = os.path.join(output_folder, f"temp_{filename}")
359
+ image_with_no_bg.save(temp_image_path, format='PNG')
360
+
361
+ log, new_image, x, y = position_logic(temp_image_path)
362
+
363
+ # Create a new 1080x1080 canvas with the appropriate background
364
+ if bg_choice == 'white':
365
+ canvas = Image.new("RGBA", (1080, 1080), "WHITE")
366
+ elif bg_choice == 'custom':
367
+ canvas = Image.new("RGBA", (1080, 1080), custom_color)
368
+ else: # transparent
369
+ canvas = Image.new("RGBA", (1080, 1080), (0, 0, 0, 0))
370
+
371
+ # Paste the resized image onto the canvas
372
+ canvas.paste(new_image, (x, y), new_image)
373
+ log.append({"action": "paste", "position": [str(x), str(y)]})
374
+
375
+ # Add visible black line for padding when background is not transparent
376
+ if add_padding_line:
377
+ draw = ImageDraw.Draw(canvas)
378
+ draw.rectangle([padding, padding, 1080 - padding, 1080 - padding], outline="black", width=5)
379
+ log.append({"action": "add_padding_line"})
380
+
381
+ output_ext = 'jpg' if output_format == 'JPG' else 'png'
382
+ output_filename = f"{os.path.splitext(filename)[0]}.{output_ext}"
383
+ output_path = os.path.join(output_folder, output_filename)
384
+
385
+ # Apply watermark only if the filename ends with "_01" and watermark_path is provided
386
+ if os.path.splitext(filename)[0].endswith("_01") and watermark_path:
387
+ watermark = Image.open(watermark_path).convert("RGBA")
388
+ canvas.paste(watermark, (0, 0), watermark)
389
+ log.append({"action": "add_watermark"})
390
+
391
+ if output_format == 'JPG':
392
+ canvas.convert('RGB').save(output_path, format='JPEG')
393
+ else:
394
+ canvas.save(output_path, format='PNG')
395
+
396
+ os.remove(temp_image_path)
397
+
398
+ print(f"Processed image path: {output_path}")
399
+ return [(output_path, image_path)], log
400
+
401
+ except Exception as e:
402
+ print(f"Error processing {filename}: {e}")
403
+ return None, None
404
+
405
+ def process_images(input_files, bg_method='rembg', watermark_path=None, output_format='PNG', bg_choice='transparent', custom_color="#ffffff", num_workers=4, progress=gr.Progress()):
406
+ start_time = time.time()
407
+
408
+ output_folder = "processed_images"
409
+ if os.path.exists(output_folder):
410
+ shutil.rmtree(output_folder)
411
+ os.makedirs(output_folder)
412
+
413
+ processed_images = []
414
+ original_images = []
415
+ all_logs = []
416
+
417
+ if isinstance(input_files, str) and input_files.lower().endswith(('.zip', '.rar')):
418
+ # Handle zip file
419
+ input_folder = "temp_input"
420
+ if os.path.exists(input_folder):
421
+ shutil.rmtree(input_folder)
422
+ os.makedirs(input_folder)
423
+
424
+ try:
425
+ with zipfile.ZipFile(input_files, 'r') as zip_ref:
426
+ zip_ref.extractall(input_folder)
427
+ except zipfile.BadZipFile as e:
428
+ print(f"Error extracting zip file: {e}")
429
+ return [], None, 0
430
+
431
+ image_files = [os.path.join(input_folder, f) for f in os.listdir(input_folder) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.webp'))]
432
+ elif isinstance(input_files, list):
433
+ # Handle multiple files
434
+ image_files = input_files
435
+ else:
436
+ # Handle single file
437
+ image_files = [input_files]
438
+
439
+ total_images = len(image_files)
440
+ print(f"Total images to process: {total_images}")
441
+
442
+ avg_processing_time = 0
443
+ with ThreadPoolExecutor(max_workers=num_workers) as executor:
444
+ future_to_image = {executor.submit(process_single_image, image_path, output_folder, bg_method, output_format, bg_choice, custom_color, watermark_path): image_path for image_path in image_files}
445
+ for idx, future in enumerate(future_to_image):
446
+ try:
447
+ start_time_image = time.time()
448
+ result, log = future.result()
449
+ end_time_image = time.time()
450
+ image_processing_time = end_time_image - start_time_image
451
+
452
+ # Update average processing time
453
+ avg_processing_time = (avg_processing_time * idx + image_processing_time) / (idx + 1)
454
+
455
+ if result:
456
+ processed_images.extend(result)
457
+ original_images.append(future_to_image[future])
458
+ all_logs.append({os.path.basename(future_to_image[future]): log})
459
+
460
+ # Estimate remaining time
461
+ remaining_images = total_images - (idx + 1)
462
+ estimated_remaining_time = remaining_images * avg_processing_time
463
+
464
+ progress((idx + 1) / total_images, f"{idx + 1}/{total_images} images processed. Estimated time remaining: {estimated_remaining_time:.2f} seconds")
465
+ except Exception as e:
466
+ print(f"Error processing image {future_to_image[future]}: {e}")
467
+
468
+ output_zip_path = "processed_images.zip"
469
+ with zipfile.ZipFile(output_zip_path, 'w') as zipf:
470
+ for file, _ in processed_images:
471
+ zipf.write(file, os.path.basename(file))
472
+
473
+ # Write the comprehensive log for all images
474
+ with open(os.path.join(output_folder, 'process_log.json'), 'w') as log_file:
475
+ json.dump(all_logs, log_file, indent=4)
476
+ print("Comprehensive log saved to", os.path.join(output_folder, 'process_log.json'))
477
+
478
+ end_time = time.time()
479
+ processing_time = end_time - start_time
480
+ print(f"Processing time: {processing_time} seconds")
481
+
482
+ return original_images, processed_images, output_zip_path, processing_time
483
+
484
+ def gradio_interface(input_files, bg_method, watermark, output_format, bg_choice, custom_color, num_workers):
485
+ progress = gr.Progress()
486
+ watermark_path = watermark.name if watermark else None
487
+
488
+ # Check input_files, is it single image, list image, or zip/rar
489
+ if isinstance(input_files, str) and input_files.lower().endswith(('.zip', '.rar')):
490
+ return process_images(input_files, bg_method, watermark_path, output_format, bg_choice, custom_color, num_workers, progress)
491
+ elif isinstance(input_files, list):
492
+ return process_images(input_files, bg_method, watermark_path, output_format, bg_choice, custom_color, num_workers, progress)
493
+ else:
494
+ return process_images(input_files.name, bg_method, watermark_path, output_format, bg_choice, custom_color, num_workers, progress)
495
+
496
+ def show_color_picker(bg_choice):
497
+ if bg_choice == 'custom':
498
+ return gr.update(visible=True)
499
+ return gr.update(visible=False)
500
+
501
+ def update_compare(evt: gr.SelectData):
502
+ if isinstance(evt.value, dict) and 'caption' in evt.value:
503
+ input_path = evt.value['caption']
504
+ output_path = evt.value['image']['path']
505
+ input_path = input_path.split("Input: ")[-1]
506
+
507
+ # Open the original and processed images
508
+ original_img = Image.open(input_path)
509
+ processed_img = Image.open(output_path)
510
+
511
+ # Calculate the aspect ratios
512
+ original_ratio = f"{original_img.width}x{original_img.height}"
513
+ processed_ratio = f"{processed_img.width}x{processed_img.height}"
514
+
515
+ return gr.update(value=input_path), gr.update(value=output_path), gr.update(value=original_ratio), gr.update(value=processed_ratio)
516
+ else:
517
+ print("No caption found in selection")
518
+ return gr.update(value=None), gr.update(value=None), gr.update(value=None), gr.update(value=None)
519
+
520
+ def process(input_files, bg_method, watermark, output_format, bg_choice, custom_color, num_workers):
521
+ _, processed_images, zip_path, time_taken = gradio_interface(input_files, bg_method, watermark, output_format, bg_choice, custom_color, num_workers)
522
+ processed_images_with_captions = [(img, f"Input: {caption}") for img, caption in processed_images]
523
+ return processed_images_with_captions, zip_path, f"{time_taken:.2f} seconds"
524
+
525
+ with gr.Blocks() as iface:
526
+ gr.Markdown("# Image Background Removal and Resizing with Optional Watermark")
527
+ gr.Markdown("Choose to upload multiple images or a ZIP/RAR file, select the crop mode, optionally upload a watermark image, and choose the output format.")
528
+
529
+ with gr.Row():
530
+ input_files = gr.File(label="Upload Image or ZIP/RAR file", file_types=[".zip", ".rar", "image"], interactive=True)
531
+ watermark = gr.File(label="Upload Watermark Image (Optional)", file_types=[".png"])
532
+
533
+ with gr.Row():
534
+ output_format = gr.Radio(choices=["PNG", "JPG"], label="Output Format", value="JPG")
535
+ num_workers = gr.Slider(minimum=1, maximum=16, step=1, label="Number of Workers", value=5)
536
+
537
+ with gr.Row():
538
+ bg_method = gr.Radio(choices=["bria", "rembg"], label="Background Removal Method", value="bria")
539
+ bg_choice = gr.Radio(choices=["transparent", "white", "custom"], label="Background Choice", value="white")
540
+ custom_color = gr.ColorPicker(label="Custom Background Color", value="#ffffff", visible=False)
541
+
542
+ process_button = gr.Button("Process Images")
543
+
544
+ with gr.Row():
545
+ gallery_processed = gr.Gallery(label="Processed Images")
546
+ with gr.Row():
547
+ image_original = gr.Image(label="Original Images", interactive=False)
548
+ image_processed = gr.Image(label="Processed Images", interactive=False)
549
+ with gr.Row():
550
+ original_ratio = gr.Textbox(label="Original Ratio")
551
+ processed_ratio = gr.Textbox(label="Processed Ratio")
552
+ with gr.Row():
553
+ output_zip = gr.File(label="Download Processed Images as ZIP")
554
+ processing_time = gr.Textbox(label="Processing Time (seconds)")
555
+
556
+ bg_choice.change(show_color_picker, inputs=bg_choice, outputs=custom_color)
557
+ process_button.click(process, inputs=[input_files, bg_method, watermark, output_format, bg_choice, custom_color, num_workers], outputs=[gallery_processed, output_zip, processing_time])
558
+ gallery_processed.select(update_compare, outputs=[image_original, image_processed, original_ratio, processed_ratio])
559
+
560
+ iface.launch()
app.py CHANGED
@@ -46,7 +46,7 @@ def get_bounding_box_with_threshold(image, threshold):
46
  else:
47
  return None
48
 
49
- def position_logic(image_path, use_threshold=True):
50
  image = Image.open(image_path)
51
  image = image.convert("RGBA")
52
 
@@ -63,7 +63,7 @@ def position_logic(image_path, use_threshold=True):
63
  cropped_sides = []
64
 
65
  # Define tolerance for transparency
66
- tolerance = 10 # Adjust this value as needed
67
 
68
  # Check top edge
69
  if any(image.getpixel((x, 0))[3] > tolerance for x in range(width)):
@@ -95,51 +95,50 @@ def position_logic(image_path, use_threshold=True):
95
  log.append({"action": "crop", "bbox": [str(bbox[0]), str(bbox[1]), str(bbox[2]), str(bbox[3])]})
96
 
97
  # Calculate the new size to expand the image
98
- padding = 125
99
- target_size = 1080
100
  aspect_ratio = image.width / image.height
101
 
102
  if len(cropped_sides) == 4:
103
  # If the image is cropped on all sides, center crop it to fit the canvas
104
  if aspect_ratio > 1: # Landscape
105
- new_height = target_size
106
  new_width = int(new_height * aspect_ratio)
107
- left = (new_width - target_size) // 2
108
  image = image.resize((new_width, new_height), Image.LANCZOS)
109
- image = image.crop((left, 0, left + target_size, target_size))
110
  else: # Portrait or square
111
- new_width = target_size
112
  new_height = int(new_width / aspect_ratio)
113
- top = (new_height - target_size) // 2
114
  image = image.resize((new_width, new_height), Image.LANCZOS)
115
- image = image.crop((0, top, target_size, top + target_size))
116
- log.append({"action": "center_crop_resize", "new_size": f"{target_size}x{target_size}"})
117
  x, y = 0, 0
118
  elif not cropped_sides:
119
  # If the image is not cropped, expand it from center until it touches the padding
120
- new_height = 1080 - 2 * padding # Ensure it touches top and bottom padding
121
  new_width = int(new_height * aspect_ratio)
122
 
123
- if new_width > 1080 - 2 * padding:
124
  # If width exceeds available space, adjust based on width
125
- new_width = 1080 - 2 * padding
126
  new_height = int(new_width / aspect_ratio)
127
 
128
  # Resize the image
129
  image = image.resize((new_width, new_height), Image.LANCZOS)
130
  log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
131
 
132
- x = (1080 - new_width) // 2
133
- y = 1080 - new_height - padding
134
  else:
135
  # New logic for handling cropped top and left, or top and right
136
  if set(cropped_sides) == {"top", "left"} or set(cropped_sides) == {"top", "right"}:
137
- new_height = target_size - padding # Ensure bottom padding
138
  new_width = int(new_height * aspect_ratio)
139
 
140
  # If new width exceeds canvas width, adjust based on width
141
- if new_width > target_size:
142
- new_width = target_size
143
  new_height = int(new_width / aspect_ratio)
144
 
145
  # Resize the image
@@ -150,60 +149,82 @@ def position_logic(image_path, use_threshold=True):
150
  if "left" in cropped_sides:
151
  x = 0
152
  else: # right in cropped_sides
153
- x = target_size - new_width
154
  y = 0
155
 
156
  # If the resized image is taller than the canvas minus padding, crop from the bottom
157
- if new_height > target_size - padding:
158
- crop_bottom = new_height - (target_size - padding)
159
  image = image.crop((0, 0, new_width, new_height - crop_bottom))
160
- new_height = target_size - padding
161
  log.append({"action": "crop_vertical", "bottom_pixels_removed": str(crop_bottom)})
162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  log.append({"action": "position", "x": str(x), "y": str(y)})
164
  elif set(cropped_sides) == {"bottom", "left", "right"}:
165
  # Expand the image from the center
166
- new_width = target_size
167
  new_height = int(new_width / aspect_ratio)
168
 
169
- if new_height < target_size:
170
- new_height = target_size
171
  new_width = int(new_height * aspect_ratio)
172
 
173
  image = image.resize((new_width, new_height), Image.LANCZOS)
174
 
175
  # Crop to fit the canvas
176
- left = (new_width - target_size) // 2
177
  top = 0
178
- image = image.crop((left, top, left + target_size, top + target_size))
179
 
180
- log.append({"action": "expand_and_crop", "new_size": f"{target_size}x{target_size}"})
181
  x, y = 0, 0
182
  elif cropped_sides == ["top"]:
183
  # New logic for handling only top-cropped images
184
  if image.width > image.height:
185
- new_width = target_size
186
- new_height = int(target_size / aspect_ratio)
187
  else:
188
- new_height = target_size - padding # Ensure bottom padding
189
  new_width = int(new_height * aspect_ratio)
190
 
191
  # Resize the image
192
  image = image.resize((new_width, new_height), Image.LANCZOS)
193
  log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
194
 
195
- x = (1080 - new_width) // 2
196
  y = 0 # Align to top
197
 
198
  # Apply padding only to non-cropped sides
199
- x = max(padding, min(x, 1080 - new_width - padding))
200
  elif cropped_sides in [["right"], ["left"]]:
201
  # New logic for handling only right-cropped or left-cropped images
202
  if image.width > image.height:
203
- new_width = target_size - padding # Ensure padding on non-cropped side
204
  new_height = int(new_width / aspect_ratio)
205
  else:
206
- new_height = target_size - padding # Ensure bottom padding
207
  new_width = int(new_height * aspect_ratio)
208
 
209
  # Resize the image
@@ -211,13 +232,19 @@ def position_logic(image_path, use_threshold=True):
211
  log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
212
 
213
  if cropped_sides == ["right"]:
214
- x = 1080 - new_width # Align to right
215
  else: # cropped_sides == ["left"]
216
- x = 0 # Align to left without padding
217
- y = 1080 - new_height - padding # Respect bottom padding
 
 
 
 
 
 
218
  elif set(cropped_sides) == {"left", "right"}:
219
  # Logic for handling images cropped on both left and right sides
220
- new_width = 1080 # Expand to full width of canvas
221
 
222
  # Calculate the aspect ratio of the original image
223
  aspect_ratio = image.width / image.height
@@ -233,58 +260,110 @@ def position_logic(image_path, use_threshold=True):
233
  x = 0
234
 
235
  # Calculate vertical position to respect bottom padding
236
- y = 1080 - new_height - padding
237
 
238
  # If the resized image is taller than the canvas, crop from the top only
239
- if new_height > 1080 - padding:
240
- crop_top = new_height - (1080 - padding)
241
  image = image.crop((0, crop_top, new_width, new_height))
242
- new_height = 1080 - padding
243
  y = 0
244
  log.append({"action": "crop_vertical", "top_pixels_removed": str(crop_top)})
245
  else:
246
  # Align the image to the bottom with padding
247
- y = 1080 - new_height - padding
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
  log.append({"action": "position", "x": str(x), "y": str(y)})
250
  else:
251
  # Use the original resizing logic for other partially cropped images
252
  if image.width > image.height:
253
- new_width = target_size
254
- new_height = int(target_size / aspect_ratio)
255
  else:
256
- new_height = target_size
257
- new_width = int(target_size * aspect_ratio)
258
 
259
  # Resize the image
260
  image = image.resize((new_width, new_height), Image.LANCZOS)
261
  log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
262
 
263
  # Center horizontally for all images
264
- x = (1080 - new_width) // 2
265
- y = 1080 - new_height - padding
266
 
267
  # Adjust positions for cropped sides
268
  if "top" in cropped_sides:
269
  y = 0
270
  elif "bottom" in cropped_sides:
271
- y = 1080 - new_height
272
  if "left" in cropped_sides:
273
  x = 0
274
  elif "right" in cropped_sides:
275
- x = 1080 - new_width
276
 
277
  # Apply padding only to non-cropped sides, but keep horizontal centering
278
  if "left" not in cropped_sides and "right" not in cropped_sides:
279
- x = (1080 - new_width) // 2 # Always center horizontally
280
  if "top" not in cropped_sides and "bottom" not in cropped_sides:
281
- y = max(padding, min(y, 1080 - new_height - padding))
282
 
283
  return log, image, x, y
284
 
285
- def process_single_image(image_path, output_folder, bg_method, output_format, bg_choice, custom_color, watermark_path=None):
286
  add_padding_line = False
287
- padding = 125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
 
289
  filename = os.path.basename(image_path)
290
  try:
@@ -297,15 +376,15 @@ def process_single_image(image_path, output_folder, bg_method, output_format, bg
297
  temp_image_path = os.path.join(output_folder, f"temp_{filename}")
298
  image_with_no_bg.save(temp_image_path, format='PNG')
299
 
300
- log, new_image, x, y = position_logic(temp_image_path)
301
 
302
- # Create a new 1080x1080 canvas with the appropriate background
303
  if bg_choice == 'white':
304
- canvas = Image.new("RGBA", (1080, 1080), "WHITE")
305
  elif bg_choice == 'custom':
306
- canvas = Image.new("RGBA", (1080, 1080), custom_color)
307
  else: # transparent
308
- canvas = Image.new("RGBA", (1080, 1080), (0, 0, 0, 0))
309
 
310
  # Paste the resized image onto the canvas
311
  canvas.paste(new_image, (x, y), new_image)
@@ -314,53 +393,44 @@ def process_single_image(image_path, output_folder, bg_method, output_format, bg
314
  # Add visible black line for padding when background is not transparent
315
  if add_padding_line:
316
  draw = ImageDraw.Draw(canvas)
317
- draw.rectangle([padding, padding, 1080 - padding, 1080 - padding], outline="black", width=5)
318
  log.append({"action": "add_padding_line"})
319
 
320
- images_paths = []
321
-
322
  output_ext = 'jpg' if output_format == 'JPG' else 'png'
323
- output_path_without_watermark = os.path.join(output_folder, f"without_watermark_{os.path.splitext(filename)[0]}.{output_ext}")
324
- if output_format == 'JPG':
325
- canvas.convert('RGB').save(output_path_without_watermark, format='JPEG')
326
- else:
327
- canvas.save(output_path_without_watermark, format='PNG')
328
- images_paths.append((output_path_without_watermark, image_path))
329
 
330
- if watermark_path:
 
331
  watermark = Image.open(watermark_path).convert("RGBA")
332
- canvas_with_watermark = canvas.copy()
333
- canvas_with_watermark.paste(watermark, (0, 0), watermark)
334
- output_path_with_watermark = os.path.join(output_folder, f"with_watermark_{os.path.splitext(filename)[0]}.{output_ext}")
335
- if output_format == 'JPG':
336
- canvas_with_watermark.convert('RGB').save(output_path_with_watermark, format='JPEG')
337
- else:
338
- canvas_with_watermark.save(output_path_with_watermark, format='PNG')
339
- images_paths.append((output_path_with_watermark, image_path))
340
 
341
- os.remove(temp_image_path)
 
 
 
342
 
343
- with open(os.path.join(output_folder, 'process_log.json'), 'w') as log_file:
344
- json.dump(log, log_file, indent=4)
345
- print("Log saved to", os.path.join(output_folder, 'process_log.json'))
346
 
347
- print(f"Processed image paths: {images_paths}")
348
- return images_paths
349
 
350
  except Exception as e:
351
  print(f"Error processing {filename}: {e}")
352
- return None
353
 
354
- def process_images(input_files, bg_method='rembg', watermark_path=None, output_format='PNG', bg_choice='transparent', custom_color="#ffffff", num_workers=4, progress=gr.Progress()):
355
  start_time = time.time()
356
 
357
- output_folder = "temp_output"
358
  if os.path.exists(output_folder):
359
  shutil.rmtree(output_folder)
360
  os.makedirs(output_folder)
361
 
362
  processed_images = []
363
  original_images = []
 
364
 
365
  if isinstance(input_files, str) and input_files.lower().endswith(('.zip', '.rar')):
366
  # Handle zip file
@@ -389,11 +459,11 @@ def process_images(input_files, bg_method='rembg', watermark_path=None, output_f
389
 
390
  avg_processing_time = 0
391
  with ThreadPoolExecutor(max_workers=num_workers) as executor:
392
- future_to_image = {executor.submit(process_single_image, image_path, output_folder, bg_method, output_format, bg_choice, custom_color, watermark_path): image_path for image_path in image_files}
393
  for idx, future in enumerate(future_to_image):
394
  try:
395
  start_time_image = time.time()
396
- result = future.result()
397
  end_time_image = time.time()
398
  image_processing_time = end_time_image - start_time_image
399
 
@@ -403,6 +473,7 @@ def process_images(input_files, bg_method='rembg', watermark_path=None, output_f
403
  if result:
404
  processed_images.extend(result)
405
  original_images.append(future_to_image[future])
 
406
 
407
  # Estimate remaining time
408
  remaining_images = total_images - (idx + 1)
@@ -415,10 +486,12 @@ def process_images(input_files, bg_method='rembg', watermark_path=None, output_f
415
  output_zip_path = "processed_images.zip"
416
  with zipfile.ZipFile(output_zip_path, 'w') as zipf:
417
  for file, _ in processed_images:
418
- if "with_watermark" in file:
419
- zipf.write(file, os.path.join("with_watermark", os.path.basename(file)))
420
- else:
421
- zipf.write(file, os.path.join("without_watermark", os.path.basename(file)))
 
 
422
 
423
  end_time = time.time()
424
  processing_time = end_time - start_time
@@ -426,17 +499,17 @@ def process_images(input_files, bg_method='rembg', watermark_path=None, output_f
426
 
427
  return original_images, processed_images, output_zip_path, processing_time
428
 
429
- def gradio_interface(input_files, bg_method, watermark, output_format, bg_choice, custom_color, num_workers):
430
  progress = gr.Progress()
431
  watermark_path = watermark.name if watermark else None
432
 
433
  # Check input_files, is it single image, list image, or zip/rar
434
  if isinstance(input_files, str) and input_files.lower().endswith(('.zip', '.rar')):
435
- return process_images(input_files, bg_method, watermark_path, output_format, bg_choice, custom_color, num_workers, progress)
436
  elif isinstance(input_files, list):
437
- return process_images(input_files, bg_method, watermark_path, output_format, bg_choice, custom_color, num_workers, progress)
438
  else:
439
- return process_images(input_files.name, bg_method, watermark_path, output_format, bg_choice, custom_color, num_workers, progress)
440
 
441
  def show_color_picker(bg_choice):
442
  if bg_choice == 'custom':
@@ -462,8 +535,8 @@ def update_compare(evt: gr.SelectData):
462
  print("No caption found in selection")
463
  return gr.update(value=None), gr.update(value=None), gr.update(value=None), gr.update(value=None)
464
 
465
- def process(input_files, bg_method, watermark, output_format, bg_choice, custom_color, num_workers):
466
- _, processed_images, zip_path, time_taken = gradio_interface(input_files, bg_method, watermark, output_format, bg_choice, custom_color, num_workers)
467
  processed_images_with_captions = [(img, f"Input: {caption}") for img, caption in processed_images]
468
  return processed_images_with_captions, zip_path, f"{time_taken:.2f} seconds"
469
 
@@ -476,6 +549,7 @@ with gr.Blocks() as iface:
476
  watermark = gr.File(label="Upload Watermark Image (Optional)", file_types=[".png"])
477
 
478
  with gr.Row():
 
479
  output_format = gr.Radio(choices=["PNG", "JPG"], label="Output Format", value="JPG")
480
  num_workers = gr.Slider(minimum=1, maximum=16, step=1, label="Number of Workers", value=5)
481
 
@@ -499,7 +573,7 @@ with gr.Blocks() as iface:
499
  processing_time = gr.Textbox(label="Processing Time (seconds)")
500
 
501
  bg_choice.change(show_color_picker, inputs=bg_choice, outputs=custom_color)
502
- process_button.click(process, inputs=[input_files, bg_method, watermark, output_format, bg_choice, custom_color, num_workers], outputs=[gallery_processed, output_zip, processing_time])
503
  gallery_processed.select(update_compare, outputs=[image_original, image_processed, original_ratio, processed_ratio])
504
 
505
  iface.launch()
 
46
  else:
47
  return None
48
 
49
+ def position_logic(image_path, canvas_size, padding_top, padding_right, padding_bottom, padding_left, use_threshold=True):
50
  image = Image.open(image_path)
51
  image = image.convert("RGBA")
52
 
 
63
  cropped_sides = []
64
 
65
  # Define tolerance for transparency
66
+ tolerance = 30 # Adjust this value as needed
67
 
68
  # Check top edge
69
  if any(image.getpixel((x, 0))[3] > tolerance for x in range(width)):
 
95
  log.append({"action": "crop", "bbox": [str(bbox[0]), str(bbox[1]), str(bbox[2]), str(bbox[3])]})
96
 
97
  # Calculate the new size to expand the image
98
+ target_width, target_height = canvas_size
 
99
  aspect_ratio = image.width / image.height
100
 
101
  if len(cropped_sides) == 4:
102
  # If the image is cropped on all sides, center crop it to fit the canvas
103
  if aspect_ratio > 1: # Landscape
104
+ new_height = target_height
105
  new_width = int(new_height * aspect_ratio)
106
+ left = (new_width - target_width) // 2
107
  image = image.resize((new_width, new_height), Image.LANCZOS)
108
+ image = image.crop((left, 0, left + target_width, target_height))
109
  else: # Portrait or square
110
+ new_width = target_width
111
  new_height = int(new_width / aspect_ratio)
112
+ top = (new_height - target_height) // 2
113
  image = image.resize((new_width, new_height), Image.LANCZOS)
114
+ image = image.crop((0, top, target_width, top + target_height))
115
+ log.append({"action": "center_crop_resize", "new_size": f"{target_width}x{target_height}"})
116
  x, y = 0, 0
117
  elif not cropped_sides:
118
  # If the image is not cropped, expand it from center until it touches the padding
119
+ new_height = target_height - padding_top - padding_bottom
120
  new_width = int(new_height * aspect_ratio)
121
 
122
+ if new_width > target_width - padding_left - padding_right:
123
  # If width exceeds available space, adjust based on width
124
+ new_width = target_width - padding_left - padding_right
125
  new_height = int(new_width / aspect_ratio)
126
 
127
  # Resize the image
128
  image = image.resize((new_width, new_height), Image.LANCZOS)
129
  log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
130
 
131
+ x = (target_width - new_width) // 2
132
+ y = target_height - new_height - padding_bottom
133
  else:
134
  # New logic for handling cropped top and left, or top and right
135
  if set(cropped_sides) == {"top", "left"} or set(cropped_sides) == {"top", "right"}:
136
+ new_height = target_height - padding_bottom
137
  new_width = int(new_height * aspect_ratio)
138
 
139
  # If new width exceeds canvas width, adjust based on width
140
+ if new_width > target_width:
141
+ new_width = target_width
142
  new_height = int(new_width / aspect_ratio)
143
 
144
  # Resize the image
 
149
  if "left" in cropped_sides:
150
  x = 0
151
  else: # right in cropped_sides
152
+ x = target_width - new_width
153
  y = 0
154
 
155
  # If the resized image is taller than the canvas minus padding, crop from the bottom
156
+ if new_height > target_height - padding_bottom:
157
+ crop_bottom = new_height - (target_height - padding_bottom)
158
  image = image.crop((0, 0, new_width, new_height - crop_bottom))
159
+ new_height = target_height - padding_bottom
160
  log.append({"action": "crop_vertical", "bottom_pixels_removed": str(crop_bottom)})
161
 
162
+ log.append({"action": "position", "x": str(x), "y": str(y)})
163
+ elif set(cropped_sides) == {"bottom", "left"} or set(cropped_sides) == {"bottom", "right"}:
164
+ # Handle bottom & left or bottom & right cropped images
165
+ new_height = target_height - padding_top
166
+ new_width = int(new_height * aspect_ratio)
167
+
168
+ # If new width exceeds canvas width, adjust based on width
169
+ if new_width > target_width - padding_left - padding_right:
170
+ new_width = target_width - padding_left - padding_right
171
+ new_height = int(new_width / aspect_ratio)
172
+
173
+ # Resize the image without cropping or stretching
174
+ image = image.resize((new_width, new_height), Image.LANCZOS)
175
+ log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
176
+
177
+ # Set position
178
+ if "left" in cropped_sides:
179
+ x = 0
180
+ else: # right in cropped_sides
181
+ x = target_width - new_width
182
+ y = target_height - new_height
183
+
184
  log.append({"action": "position", "x": str(x), "y": str(y)})
185
  elif set(cropped_sides) == {"bottom", "left", "right"}:
186
  # Expand the image from the center
187
+ new_width = target_width
188
  new_height = int(new_width / aspect_ratio)
189
 
190
+ if new_height < target_height:
191
+ new_height = target_height
192
  new_width = int(new_height * aspect_ratio)
193
 
194
  image = image.resize((new_width, new_height), Image.LANCZOS)
195
 
196
  # Crop to fit the canvas
197
+ left = (new_width - target_width) // 2
198
  top = 0
199
+ image = image.crop((left, top, left + target_width, top + target_height))
200
 
201
+ log.append({"action": "expand_and_crop", "new_size": f"{target_width}x{target_height}"})
202
  x, y = 0, 0
203
  elif cropped_sides == ["top"]:
204
  # New logic for handling only top-cropped images
205
  if image.width > image.height:
206
+ new_width = target_width
207
+ new_height = int(target_width / aspect_ratio)
208
  else:
209
+ new_height = target_height - padding_bottom
210
  new_width = int(new_height * aspect_ratio)
211
 
212
  # Resize the image
213
  image = image.resize((new_width, new_height), Image.LANCZOS)
214
  log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
215
 
216
+ x = (target_width - new_width) // 2
217
  y = 0 # Align to top
218
 
219
  # Apply padding only to non-cropped sides
220
+ x = max(padding_left, min(x, target_width - new_width - padding_right))
221
  elif cropped_sides in [["right"], ["left"]]:
222
  # New logic for handling only right-cropped or left-cropped images
223
  if image.width > image.height:
224
+ new_width = target_width - max(padding_left, padding_right)
225
  new_height = int(new_width / aspect_ratio)
226
  else:
227
+ new_height = target_height - padding_top - padding_bottom
228
  new_width = int(new_height * aspect_ratio)
229
 
230
  # Resize the image
 
232
  log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
233
 
234
  if cropped_sides == ["right"]:
235
+ x = target_width - new_width # Align to right
236
  else: # cropped_sides == ["left"]
237
+ x = 0 # Align to left
238
+ y = target_height - new_height - padding_bottom # Respect bottom padding
239
+
240
+ # Ensure top padding is respected
241
+ if y < padding_top:
242
+ y = padding_top
243
+
244
+ log.append({"action": "position", "x": str(x), "y": str(y)})
245
  elif set(cropped_sides) == {"left", "right"}:
246
  # Logic for handling images cropped on both left and right sides
247
+ new_width = target_width # Expand to full width of canvas
248
 
249
  # Calculate the aspect ratio of the original image
250
  aspect_ratio = image.width / image.height
 
260
  x = 0
261
 
262
  # Calculate vertical position to respect bottom padding
263
+ y = target_height - new_height - padding_bottom
264
 
265
  # If the resized image is taller than the canvas, crop from the top only
266
+ if new_height > target_height - padding_bottom:
267
+ crop_top = new_height - (target_height - padding_bottom)
268
  image = image.crop((0, crop_top, new_width, new_height))
269
+ new_height = target_height - padding_bottom
270
  y = 0
271
  log.append({"action": "crop_vertical", "top_pixels_removed": str(crop_top)})
272
  else:
273
  # Align the image to the bottom with padding
274
+ y = target_height - new_height - padding_bottom
275
+
276
+ log.append({"action": "position", "x": str(x), "y": str(y)})
277
+ elif cropped_sides == ["bottom"]:
278
+ # Logic for handling images cropped on the bottom side
279
+ # Calculate the aspect ratio of the original image
280
+ aspect_ratio = image.width / image.height
281
+
282
+ if aspect_ratio < 1: # Portrait orientation
283
+ new_height = target_height - padding_top # Full height with top padding
284
+ new_width = int(new_height * aspect_ratio)
285
+
286
+ # If the new width exceeds the canvas width, adjust it
287
+ if new_width > target_width:
288
+ new_width = target_width
289
+ new_height = int(new_width / aspect_ratio)
290
+ else: # Landscape orientation
291
+ new_width = target_width - padding_left - padding_right
292
+ new_height = int(new_width / aspect_ratio)
293
+
294
+ # If the new height exceeds the canvas height, adjust it
295
+ if new_height > target_height:
296
+ new_height = target_height
297
+ new_width = int(new_height * aspect_ratio)
298
+
299
+ # Resize the image
300
+ image = image.resize((new_width, new_height), Image.LANCZOS)
301
+ log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
302
+
303
+ # Set horizontal position (centered)
304
+ x = (target_width - new_width) // 2
305
+
306
+ # Set vertical position (touching bottom edge for all cases)
307
+ y = target_height - new_height
308
 
309
  log.append({"action": "position", "x": str(x), "y": str(y)})
310
  else:
311
  # Use the original resizing logic for other partially cropped images
312
  if image.width > image.height:
313
+ new_width = target_width
314
+ new_height = int(target_width / aspect_ratio)
315
  else:
316
+ new_height = target_height
317
+ new_width = int(target_height * aspect_ratio)
318
 
319
  # Resize the image
320
  image = image.resize((new_width, new_height), Image.LANCZOS)
321
  log.append({"action": "resize", "new_width": str(new_width), "new_height": str(new_height)})
322
 
323
  # Center horizontally for all images
324
+ x = (target_width - new_width) // 2
325
+ y = target_height - new_height - padding_bottom
326
 
327
  # Adjust positions for cropped sides
328
  if "top" in cropped_sides:
329
  y = 0
330
  elif "bottom" in cropped_sides:
331
+ y = target_height - new_height
332
  if "left" in cropped_sides:
333
  x = 0
334
  elif "right" in cropped_sides:
335
+ x = target_width - new_width
336
 
337
  # Apply padding only to non-cropped sides, but keep horizontal centering
338
  if "left" not in cropped_sides and "right" not in cropped_sides:
339
+ x = (target_width - new_width) // 2 # Always center horizontally
340
  if "top" not in cropped_sides and "bottom" not in cropped_sides:
341
+ y = max(padding_top, min(y, target_height - new_height - padding_bottom))
342
 
343
  return log, image, x, y
344
 
345
+ def process_single_image(image_path, output_folder, bg_method, canvas_size_name, output_format, bg_choice, custom_color, watermark_path=None):
346
  add_padding_line = False
347
+
348
+ if canvas_size_name == 'Rox':
349
+ canvas_size = (1080, 1080)
350
+ padding_top = 112
351
+ padding_right = 125
352
+ padding_bottom = 116
353
+ padding_left = 125
354
+ elif canvas_size_name == 'Columbia':
355
+ canvas_size = (730, 610)
356
+ padding_top = 30
357
+ padding_right = 105
358
+ padding_bottom = 35
359
+ padding_left = 105
360
+ elif canvas_size_name == 'Zalora':
361
+ canvas_size = (763, 1100)
362
+ padding_top = 50
363
+ padding_right = 50
364
+ padding_bottom = 200
365
+ padding_left = 50
366
+
367
 
368
  filename = os.path.basename(image_path)
369
  try:
 
376
  temp_image_path = os.path.join(output_folder, f"temp_{filename}")
377
  image_with_no_bg.save(temp_image_path, format='PNG')
378
 
379
+ log, new_image, x, y = position_logic(temp_image_path, canvas_size, padding_top, padding_right, padding_bottom, padding_left)
380
 
381
+ # Create a new canvas with the appropriate background
382
  if bg_choice == 'white':
383
+ canvas = Image.new("RGBA", canvas_size, "WHITE")
384
  elif bg_choice == 'custom':
385
+ canvas = Image.new("RGBA", canvas_size, custom_color)
386
  else: # transparent
387
+ canvas = Image.new("RGBA", canvas_size, (0, 0, 0, 0))
388
 
389
  # Paste the resized image onto the canvas
390
  canvas.paste(new_image, (x, y), new_image)
 
393
  # Add visible black line for padding when background is not transparent
394
  if add_padding_line:
395
  draw = ImageDraw.Draw(canvas)
396
+ draw.rectangle([padding_left, padding_top, canvas_size[0] - padding_right, canvas_size[1] - padding_bottom], outline="black", width=5)
397
  log.append({"action": "add_padding_line"})
398
 
 
 
399
  output_ext = 'jpg' if output_format == 'JPG' else 'png'
400
+ output_filename = f"{os.path.splitext(filename)[0]}.{output_ext}"
401
+ output_path = os.path.join(output_folder, output_filename)
 
 
 
 
402
 
403
+ # Apply watermark only if the filename ends with "_01" and watermark_path is provided
404
+ if os.path.splitext(filename)[0].endswith("_01") and watermark_path:
405
  watermark = Image.open(watermark_path).convert("RGBA")
406
+ canvas.paste(watermark, (0, 0), watermark)
407
+ log.append({"action": "add_watermark"})
 
 
 
 
 
 
408
 
409
+ if output_format == 'JPG':
410
+ canvas.convert('RGB').save(output_path, format='JPEG')
411
+ else:
412
+ canvas.save(output_path, format='PNG')
413
 
414
+ os.remove(temp_image_path)
 
 
415
 
416
+ print(f"Processed image path: {output_path}")
417
+ return [(output_path, image_path)], log
418
 
419
  except Exception as e:
420
  print(f"Error processing {filename}: {e}")
421
+ return None, None
422
 
423
+ def process_images(input_files, bg_method='rembg', watermark_path=None, canvas_size='Rox', output_format='PNG', bg_choice='transparent', custom_color="#ffffff", num_workers=4, progress=gr.Progress()):
424
  start_time = time.time()
425
 
426
+ output_folder = "processed_images"
427
  if os.path.exists(output_folder):
428
  shutil.rmtree(output_folder)
429
  os.makedirs(output_folder)
430
 
431
  processed_images = []
432
  original_images = []
433
+ all_logs = []
434
 
435
  if isinstance(input_files, str) and input_files.lower().endswith(('.zip', '.rar')):
436
  # Handle zip file
 
459
 
460
  avg_processing_time = 0
461
  with ThreadPoolExecutor(max_workers=num_workers) as executor:
462
+ future_to_image = {executor.submit(process_single_image, image_path, output_folder, bg_method, canvas_size, output_format, bg_choice, custom_color, watermark_path): image_path for image_path in image_files}
463
  for idx, future in enumerate(future_to_image):
464
  try:
465
  start_time_image = time.time()
466
+ result, log = future.result()
467
  end_time_image = time.time()
468
  image_processing_time = end_time_image - start_time_image
469
 
 
473
  if result:
474
  processed_images.extend(result)
475
  original_images.append(future_to_image[future])
476
+ all_logs.append({os.path.basename(future_to_image[future]): log})
477
 
478
  # Estimate remaining time
479
  remaining_images = total_images - (idx + 1)
 
486
  output_zip_path = "processed_images.zip"
487
  with zipfile.ZipFile(output_zip_path, 'w') as zipf:
488
  for file, _ in processed_images:
489
+ zipf.write(file, os.path.basename(file))
490
+
491
+ # Write the comprehensive log for all images
492
+ with open(os.path.join(output_folder, 'process_log.json'), 'w') as log_file:
493
+ json.dump(all_logs, log_file, indent=4)
494
+ print("Comprehensive log saved to", os.path.join(output_folder, 'process_log.json'))
495
 
496
  end_time = time.time()
497
  processing_time = end_time - start_time
 
499
 
500
  return original_images, processed_images, output_zip_path, processing_time
501
 
502
+ def gradio_interface(input_files, bg_method, watermark, canvas_size, output_format, bg_choice, custom_color, num_workers):
503
  progress = gr.Progress()
504
  watermark_path = watermark.name if watermark else None
505
 
506
  # Check input_files, is it single image, list image, or zip/rar
507
  if isinstance(input_files, str) and input_files.lower().endswith(('.zip', '.rar')):
508
+ return process_images(input_files, bg_method, watermark_path, canvas_size, output_format, bg_choice, custom_color, num_workers, progress)
509
  elif isinstance(input_files, list):
510
+ return process_images(input_files, bg_method, watermark_path, canvas_size, output_format, bg_choice, custom_color, num_workers, progress)
511
  else:
512
+ return process_images(input_files.name, bg_method, watermark_path, canvas_size, output_format, bg_choice, custom_color, num_workers, progress)
513
 
514
  def show_color_picker(bg_choice):
515
  if bg_choice == 'custom':
 
535
  print("No caption found in selection")
536
  return gr.update(value=None), gr.update(value=None), gr.update(value=None), gr.update(value=None)
537
 
538
+ def process(input_files, bg_method, watermark, canvas_size, output_format, bg_choice, custom_color, num_workers):
539
+ _, processed_images, zip_path, time_taken = gradio_interface(input_files, bg_method, watermark, canvas_size, output_format, bg_choice, custom_color, num_workers)
540
  processed_images_with_captions = [(img, f"Input: {caption}") for img, caption in processed_images]
541
  return processed_images_with_captions, zip_path, f"{time_taken:.2f} seconds"
542
 
 
549
  watermark = gr.File(label="Upload Watermark Image (Optional)", file_types=[".png"])
550
 
551
  with gr.Row():
552
+ canvas_size = gr.Radio(choices=["Rox", "Columbia", "Zalora"], label="Canvas Size", value="Rox")
553
  output_format = gr.Radio(choices=["PNG", "JPG"], label="Output Format", value="JPG")
554
  num_workers = gr.Slider(minimum=1, maximum=16, step=1, label="Number of Workers", value=5)
555
 
 
573
  processing_time = gr.Textbox(label="Processing Time (seconds)")
574
 
575
  bg_choice.change(show_color_picker, inputs=bg_choice, outputs=custom_color)
576
+ process_button.click(process, inputs=[input_files, bg_method, watermark, canvas_size, output_format, bg_choice, custom_color, num_workers], outputs=[gallery_processed, output_zip, processing_time])
577
  gallery_processed.select(update_compare, outputs=[image_original, image_processed, original_ratio, processed_ratio])
578
 
579
  iface.launch()
app_old.py DELETED
@@ -1,307 +0,0 @@
1
- import os
2
- import zipfile
3
- import shutil
4
- import time
5
- from PIL import Image
6
- import io
7
- from rembg import remove
8
- import gradio as gr
9
- from concurrent.futures import ThreadPoolExecutor
10
- from transformers import pipeline
11
-
12
- def colors_within_tolerance(color1, color2, tolerance):
13
- return all(abs(c1 - c2) <= tolerance for c1, c2 in zip(color1, color2))
14
-
15
- def check_border_colors(image_path, tolerance):
16
- image = Image.open(image_path)
17
- pixels = image.load()
18
-
19
- width, height = image.size
20
-
21
- left_border_color = pixels[0, 0]
22
- right_border_color = pixels[width - 1, 0]
23
-
24
- for y in range(height):
25
- if not colors_within_tolerance(pixels[0, y], left_border_color, tolerance):
26
- return False
27
- if not colors_within_tolerance(pixels[width - 1, y], right_border_color, tolerance):
28
- return False
29
-
30
- return True
31
-
32
- def resize_and_crop_image(image_path, target_size=(1080, 1080), crop_mode='center'):
33
- print(f"Resizing and cropping image: {image_path}")
34
- with Image.open(image_path) as img:
35
- width, height = img.size
36
- print(f"Original image size: {width}x{height}")
37
-
38
- scaling_factor = max(target_size[0] / width, target_size[1] / height)
39
-
40
- new_size = (int(width * scaling_factor), int(height * scaling_factor))
41
- resized_img = img.resize(new_size, Image.LANCZOS)
42
- print(f"Resized image size: {new_size}")
43
-
44
- if crop_mode == 'center':
45
- left = (resized_img.width - target_size[0]) / 2
46
- top = (resized_img.height - target_size[1]) / 2
47
- elif crop_mode == 'top':
48
- left = (resized_img.width - target_size[0]) / 2
49
- top = 0
50
- elif crop_mode == 'bottom':
51
- left = (resized_img.width - target_size[0]) / 2
52
- top = resized_img.height - target_size[1]
53
- elif crop_mode == 'left':
54
- left = 0
55
- top = (resized_img.height - target_size[1]) / 2
56
- elif crop_mode == 'right':
57
- left = resized_img.width - target_size[0]
58
- top = (resized_img.height - target_size[1]) / 2
59
-
60
- right = left + target_size[0]
61
- bottom = top + target_size[1]
62
-
63
- cropped_img = resized_img.crop((left, top, right, bottom))
64
- print(f"Cropped image size: {cropped_img.size}")
65
-
66
- return cropped_img
67
-
68
- def remove_background_rembg(input_path):
69
- print(f"Removing background using rembg for image: {input_path}")
70
- with open(input_path, 'rb') as i:
71
- input_image = i.read()
72
- output_image = remove(input_image)
73
- img = Image.open(io.BytesIO(output_image)).convert("RGBA")
74
- return img
75
-
76
- def remove_background_bria(input_path):
77
- print(f"Removing background using bria for image: {input_path}")
78
- pipe = pipeline("image-segmentation", model="briaai/RMBG-1.4", trust_remote_code=True, device=0)
79
- pillow_image = pipe(input_path)
80
- return pillow_image
81
-
82
- def process_single_image(image_path, output_folder, crop_mode, bg_method, output_format, bg_choice, custom_color, watermark_path=None):
83
- filename = os.path.basename(image_path)
84
- try:
85
- print(f"Processing image: {filename}")
86
- if bg_method == 'rembg':
87
- image_with_no_bg = remove_background_rembg(image_path)
88
- elif bg_method == 'bria':
89
- image_with_no_bg = remove_background_bria(image_path)
90
-
91
- temp_image_path = os.path.join(output_folder, f"temp_{filename}")
92
- image_with_no_bg.save(temp_image_path, format='PNG')
93
-
94
- if check_border_colors(temp_image_path, tolerance=50):
95
- print(f"Border colors are the same for image: {filename}")
96
- if bg_choice == 'transparent':
97
- new_image = Image.new("RGBA", (1080, 1080), (255, 255, 255, 0))
98
- else:
99
- new_image = Image.new("RGBA", (1080, 1080), custom_color)
100
-
101
- width, height = image_with_no_bg.size
102
- scaling_factor = min(1080 / width, 1080 / height)
103
- new_size = (int(width * scaling_factor), int(height * scaling_factor))
104
- resized_img = image_with_no_bg.resize(new_size, Image.LANCZOS)
105
- print(f"Resized image size: {new_size}")
106
- new_image.paste(resized_img, ((1080 - resized_img.width) // 2, (1080 - resized_img.height) // 2))
107
- else:
108
- print(f"Border colors are different for image: {filename}")
109
- new_image = resize_and_crop_image(temp_image_path, crop_mode=crop_mode)
110
-
111
- if bg_choice == 'white':
112
- new_image = new_image.convert("RGBA")
113
- white_bg = Image.new("RGBA", new_image.size, "WHITE")
114
- new_image = Image.alpha_composite(white_bg, new_image)
115
- elif bg_choice == 'custom':
116
- new_image = new_image.convert("RGBA")
117
- custom_bg = Image.new("RGBA", new_image.size, custom_color)
118
- new_image = Image.alpha_composite(custom_bg, new_image)
119
-
120
- images_paths = []
121
-
122
- output_ext = 'jpg' if output_format == 'JPG' else 'png'
123
- output_path_without_watermark = os.path.join(output_folder, f"without_watermark_{os.path.splitext(filename)[0]}.{output_ext}")
124
- if output_format == 'JPG':
125
- new_image.convert('RGB').save(output_path_without_watermark, format='JPEG')
126
- else:
127
- new_image.save(output_path_without_watermark, format='PNG')
128
- images_paths.append((output_path_without_watermark, image_path))
129
-
130
- if watermark_path:
131
- watermark = Image.open(watermark_path).convert("RGBA")
132
- new_image_with_watermark = new_image.copy()
133
- new_image_with_watermark.paste(watermark, (0, 0), watermark)
134
- output_path_with_watermark = os.path.join(output_folder, f"with_watermark_{os.path.splitext(filename)[0]}.{output_ext}")
135
- if output_format == 'JPG':
136
- new_image_with_watermark.convert('RGB').save(output_path_with_watermark, format='JPEG')
137
- else:
138
- new_image_with_watermark.save(output_path_with_watermark, format='PNG')
139
- images_paths.append((output_path_with_watermark, image_path))
140
-
141
- os.remove(temp_image_path)
142
-
143
- print(f"Processed image paths: {images_paths}")
144
- return images_paths
145
-
146
- except Exception as e:
147
- print(f"Error processing {filename}: {e}")
148
- return None
149
-
150
- def process_images(input_files, crop_mode='center', bg_method='rembg', watermark_path=None, output_format='PNG', bg_choice='transparent', custom_color="#ffffff", num_workers=4, progress=gr.Progress()):
151
- start_time = time.time()
152
-
153
- output_folder = "temp_output"
154
- if os.path.exists(output_folder):
155
- shutil.rmtree(output_folder)
156
- os.makedirs(output_folder)
157
-
158
- processed_images = []
159
- original_images = []
160
-
161
- if isinstance(input_files, str) and input_files.lower().endswith(('.zip', '.rar')):
162
- input_folder = "temp_input"
163
- if os.path.exists(input_folder):
164
- shutil.rmtree(input_folder)
165
- os.makedirs(input_folder)
166
-
167
- try:
168
- with zipfile.ZipFile(input_files, 'r') as zip_ref:
169
- zip_ref.extractall(input_folder)
170
- except zipfile.BadZipFile as e:
171
- print(f"Error extracting zip file: {e}")
172
- return [], None, 0
173
-
174
- image_files = [os.path.join(input_folder, f) for f in os.listdir(input_folder) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.webp'))]
175
- else:
176
- image_files = [f.name for f in input_files]
177
-
178
- total_images = len(image_files)
179
- print(f"Total images to process: {total_images}")
180
-
181
- avg_processing_time = 0
182
- with ThreadPoolExecutor(max_workers=num_workers) as executor:
183
- future_to_image = {executor.submit(process_single_image, image_path, output_folder, crop_mode, bg_method, output_format, bg_choice, custom_color, watermark_path): image_path for image_path in image_files}
184
- for idx, future in enumerate(future_to_image):
185
- try:
186
- start_time_image = time.time()
187
- result = future.result()
188
- end_time_image = time.time()
189
- image_processing_time = end_time_image - start_time_image
190
-
191
- # Update average processing time
192
- avg_processing_time = (avg_processing_time * idx + image_processing_time) / (idx + 1)
193
-
194
- if result:
195
- processed_images.extend(result)
196
- original_images.append(future_to_image[future])
197
-
198
- # Estimate remaining time
199
- remaining_images = total_images - (idx + 1)
200
- estimated_remaining_time = remaining_images * avg_processing_time
201
-
202
- progress((idx + 1) / total_images, f"{idx + 1}/{total_images} images processed. Estimated time remaining: {estimated_remaining_time:.2f} seconds")
203
- except Exception as e:
204
- print(f"Error processing image {future_to_image[future]}: {e}")
205
-
206
- output_zip_path = "processed_images.zip"
207
- with zipfile.ZipFile(output_zip_path, 'w') as zipf:
208
- for file, _ in processed_images:
209
- if "with_watermark" in file:
210
- zipf.write(file, os.path.join("with_watermark", os.path.basename(file)))
211
- else:
212
- zipf.write(file, os.path.join("without_watermark", os.path.basename(file)))
213
-
214
- end_time = time.time()
215
- processing_time = end_time - start_time
216
- print(f"Processing time: {processing_time} seconds")
217
-
218
- return original_images, processed_images, output_zip_path, processing_time
219
-
220
- def gradio_interface(input_type, input_files, crop_mode, bg_method, watermark, output_format, bg_choice, custom_color, num_workers):
221
- progress = gr.Progress()
222
- watermark_path = watermark.name if watermark else None
223
-
224
- if input_type == "zip_rar":
225
- return process_images(input_files.name, crop_mode, bg_method, watermark_path, output_format, bg_choice, custom_color, num_workers, progress)
226
- else:
227
- return process_images(input_files, crop_mode, bg_method, watermark_path, output_format, bg_choice, custom_color, num_workers, progress)
228
-
229
- def show_color_picker(bg_choice):
230
- if bg_choice == 'custom':
231
- return gr.update(visible=True)
232
- return gr.update(visible=False)
233
-
234
- def update_slider(evt: gr.SelectData):
235
- if isinstance(evt.value, dict) and 'caption' in evt.value:
236
- input_path = evt.value['caption']
237
- output_path = evt.value['image']['path']
238
- input_path = input_path.split("Input: ")[-1]
239
-
240
- # Open the original and processed images
241
- original_img = Image.open(input_path)
242
- processed_img = Image.open(output_path)
243
-
244
- # Calculate the aspect ratios
245
- original_ratio = f"{original_img.width}x{original_img.height}"
246
- processed_ratio = f"{processed_img.width}x{processed_img.height}"
247
-
248
- return gr.update(value=input_path), gr.update(value=output_path), gr.update(value=original_ratio), gr.update(value=processed_ratio)
249
- else:
250
- print("No caption found in selection")
251
- return gr.update(value=None), gr.update(value=None), gr.update(value=None), gr.update(value=None)
252
-
253
- def process(input_type, input_files, crop_mode, bg_method, watermark, output_format, bg_choice, custom_color, num_workers):
254
- _, processed_images, zip_path, time_taken = gradio_interface(input_type, input_files, crop_mode, bg_method, watermark, output_format, bg_choice, custom_color, num_workers)
255
- processed_images_with_captions = [(img, f"Input: {caption}") for img, caption in processed_images]
256
- return processed_images_with_captions, zip_path, f"{time_taken:.2f} seconds"
257
-
258
- def update_input_type(choice):
259
- if choice == "zip_rar":
260
- return gr.update(visible=True), gr.update(visible=False)
261
- else:
262
- return gr.update(visible=False), gr.update(visible=True)
263
-
264
- with gr.Blocks() as iface:
265
- gr.Markdown("# Image Background Removal and Resizing with Optional Watermark")
266
- gr.Markdown("Choose to upload multiple images or a ZIP/RAR file, select the crop mode, optionally upload a watermark image, and choose the output format.")
267
-
268
- input_type = gr.Radio(choices=["multiple_images", "zip_rar"], label="Input Type", value="multiple_images")
269
-
270
- with gr.Row():
271
- zip_file = gr.File(label="Upload ZIP/RAR file of images", file_types=[".zip", ".rar"], visible=False)
272
- multiple_images = gr.File(label="Upload multiple images", file_types=["image"], file_count="multiple")
273
-
274
- watermark = gr.File(label="Upload Watermark Image (Optional)", file_types=[".png"])
275
-
276
- with gr.Row():
277
- crop_mode = gr.Radio(choices=["center", "top", "bottom", "left", "right"], label="Crop Mode", value="center")
278
- output_format = gr.Radio(choices=["PNG", "JPG"], label="Output Format", value="JPG")
279
- num_workers = gr.Slider(minimum=1, maximum=16, step=1, label="Number of Workers", value=5)
280
-
281
- with gr.Row():
282
- bg_method = gr.Radio(choices=["bria", "rembg"], label="Background Removal Method", value="bria")
283
- bg_choice = gr.Radio(choices=["transparent", "white", "custom"], label="Background Choice", value="white")
284
- custom_color = gr.ColorPicker(label="Custom Background Color", value="#ffffff", visible=False)
285
-
286
- with gr.Row():
287
- gallery_processed = gr.Gallery(label="Processed Images")
288
- with gr.Row():
289
- image_original = gr.Image(label="Original Images", interactive=False)
290
- image_processed = gr.Image(label="Processed Images", interactive=False)
291
- with gr.Row():
292
- original_ratio = gr.Textbox(label="Original Ratio")
293
- processed_ratio = gr.Textbox(label="Processed Ratio")
294
- with gr.Row():
295
- output_zip = gr.File(label="Download Processed Images as ZIP")
296
- processing_time = gr.Textbox(label="Processing Time (seconds)")
297
-
298
- input_type.change(update_input_type, inputs=input_type, outputs=[zip_file, multiple_images])
299
-
300
- bg_choice.change(show_color_picker, inputs=bg_choice, outputs=custom_color)
301
-
302
- process_button = gr.Button("Process Images")
303
- process_button.click(process, inputs=[input_type, multiple_images, crop_mode, bg_method, watermark, output_format, bg_choice, custom_color, num_workers], outputs=[gallery_processed, output_zip, processing_time])
304
-
305
- gallery_processed.select(update_slider, outputs=[image_original, image_processed, original_ratio, processed_ratio])
306
-
307
- iface.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
processed_images/1000116610.jpg ADDED
processed_images/process_log.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "1000116610.jpg": [
4
+ {
5
+ "info": "Info for temp_1000116610.jpg: The following sides of the image may contain cropped objects: top, bottom"
6
+ },
7
+ {
8
+ "action": "crop",
9
+ "bbox": [
10
+ "60",
11
+ "0",
12
+ "639",
13
+ "799"
14
+ ]
15
+ },
16
+ {
17
+ "action": "resize",
18
+ "new_width": "797",
19
+ "new_height": "1100"
20
+ },
21
+ {
22
+ "action": "paste",
23
+ "position": [
24
+ "-17",
25
+ "0"
26
+ ]
27
+ }
28
+ ]
29
+ }
30
+ ]