Skip to content

Commit 4703796

Browse files
fix: Prevent overwriting existing backups
The `save_image_with_backup` function now checks if a backup file already exists before moving the original image. This prevents accidental data loss when running the correction multiple times.
1 parent e794bb8 commit 4703796

File tree

1 file changed

+164
-0
lines changed

1 file changed

+164
-0
lines changed

kohya_gui/kontext_manual_caption_gui.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import gradio as gr
22
from easygui import boolbox
3+
from PIL import Image
34
from .common_gui import get_folder_path, scriptdir, list_dirs
45
from math import ceil
56
import os
@@ -248,6 +249,25 @@ def error_message(msg):
248249
"No shared images found between the target and control directories."
249250
)
250251

252+
mismatched_files = []
253+
for image_file in shared_files:
254+
target_image_path = os.path.join(target_images_dir, image_file)
255+
control_image_path = os.path.join(control_images_dir, image_file)
256+
257+
try:
258+
with Image.open(target_image_path) as target_img, Image.open(control_image_path) as control_img:
259+
target_aspect_ratio = target_img.width / target_img.height
260+
control_aspect_ratio = control_img.width / control_img.height
261+
262+
if abs(target_aspect_ratio - control_aspect_ratio) > 1e-2:
263+
mismatched_files.append(image_file)
264+
log.warning(f"Aspect ratio mismatch for {image_file}: Target AR is {target_aspect_ratio:.4f}, Control AR is {control_aspect_ratio:.4f}")
265+
except Exception as e:
266+
log.error(f"Could not load or process image {image_file}. Error: {e}")
267+
268+
if mismatched_files:
269+
gr.Warning(f"Found {len(mismatched_files)} images with aspect ratio mismatches. Use the 'Apply Correction' button to fix them.")
270+
251271
total_images = len(shared_files)
252272
max_pages = ceil(total_images / IMAGES_TO_SHOW)
253273

@@ -275,6 +295,132 @@ def error_message(msg):
275295
]
276296

277297

298+
def crop_image(image, target_aspect_ratio):
299+
width, height = image.size
300+
current_aspect_ratio = width / height
301+
302+
if current_aspect_ratio > target_aspect_ratio:
303+
# Crop width
304+
new_width = int(target_aspect_ratio * height)
305+
left = (width - new_width) / 2
306+
top = 0
307+
right = left + new_width
308+
bottom = height
309+
else:
310+
# Crop height
311+
new_height = int(width / target_aspect_ratio)
312+
left = 0
313+
top = (height - new_height) / 2
314+
right = width
315+
bottom = top + new_height
316+
317+
return image.crop((left, top, right, bottom))
318+
319+
320+
def pad_image(image, target_aspect_ratio, color="white"):
321+
width, height = image.size
322+
current_aspect_ratio = width / height
323+
324+
if current_aspect_ratio > target_aspect_ratio:
325+
# Pad height
326+
new_height = int(width / target_aspect_ratio)
327+
padded_image = Image.new(image.mode, (width, new_height), color)
328+
padded_image.paste(image, (0, int((new_height - height) / 2)))
329+
else:
330+
# Pad width
331+
new_width = int(height * target_aspect_ratio)
332+
padded_image = Image.new(image.mode, (new_width, height), color)
333+
padded_image.paste(image, (int((new_width - width) / 2), 0))
334+
335+
return padded_image
336+
337+
338+
def save_image_with_backup(image_path, image_to_save):
339+
if not os.path.exists(image_path):
340+
log.error(f"Image path does not exist: {image_path}")
341+
return
342+
343+
try:
344+
directory = os.path.dirname(image_path)
345+
original_dir = os.path.join(directory, "original")
346+
347+
if not os.path.exists(original_dir):
348+
os.makedirs(original_dir)
349+
350+
base_filename = os.path.basename(image_path)
351+
backup_path = os.path.join(original_dir, base_filename)
352+
353+
if not os.path.exists(backup_path):
354+
os.rename(image_path, backup_path)
355+
log.info(f"Backed up original image to {backup_path}")
356+
else:
357+
log.info(f"Backup already exists for {base_filename}, skipping backup.")
358+
359+
image_to_save.save(image_path)
360+
log.info(f"Saved modified image to {image_path}")
361+
362+
except Exception as e:
363+
log.error(f"Error saving image with backup: {e}")
364+
365+
366+
def apply_correction(
367+
image_files,
368+
target_images_dir,
369+
control_images_dir,
370+
correction_method,
371+
save_padded,
372+
):
373+
if not image_files:
374+
gr.Warning("No images loaded.")
375+
return gr.update()
376+
377+
if correction_method == "None":
378+
gr.Info("No correction method selected.")
379+
return gr.update()
380+
381+
corrected_files = 0
382+
for image_file in image_files:
383+
target_image_path = os.path.join(target_images_dir, image_file)
384+
control_image_path = os.path.join(control_images_dir, image_file)
385+
386+
try:
387+
with Image.open(target_image_path) as target_img, Image.open(
388+
control_image_path
389+
) as control_img:
390+
target_aspect_ratio = target_img.width / target_img.height
391+
control_aspect_ratio = control_img.width / control_img.height
392+
393+
if abs(target_aspect_ratio - control_aspect_ratio) > 1e-2:
394+
if target_aspect_ratio > control_aspect_ratio:
395+
# Target is wider, so we correct it
396+
image_to_correct = target_img
397+
path_to_save = target_image_path
398+
correct_aspect_ratio = control_aspect_ratio
399+
else:
400+
# Control is wider, so we correct it
401+
image_to_correct = control_img
402+
path_to_save = control_image_path
403+
correct_aspect_ratio = target_aspect_ratio
404+
405+
if correction_method == "Crop":
406+
modified_image = crop_image(image_to_correct, correct_aspect_ratio)
407+
elif correction_method == "Pad":
408+
modified_image = pad_image(image_to_correct, correct_aspect_ratio)
409+
else:
410+
continue # Should not happen
411+
412+
if save_padded:
413+
save_image_with_backup(path_to_save, modified_image)
414+
415+
corrected_files += 1
416+
417+
except Exception as e:
418+
log.error(f"Could not process or save image {image_file}. Error: {e}")
419+
420+
gr.Info(f"Corrected {corrected_files} images with aspect ratio mismatches.")
421+
return gr.update()
422+
423+
278424
def update_images(
279425
image_files, # REFACTOR: Receive the list of files from gr.State
280426
target_images_dir,
@@ -382,6 +528,24 @@ def render_pagination_with_logic(page, max_page):
382528

383529
load_images_button = gr.Button("Load Images", variant="primary")
384530

531+
with gr.Row():
532+
aspect_ratio_correction = gr.Dropdown(["None", "Crop", "Pad"], label="Aspect Ratio Correction", value="None")
533+
save_padded_images = gr.Checkbox(label="Save Padded Images", value=False)
534+
535+
apply_correction_button = gr.Button("Apply Correction")
536+
537+
apply_correction_button.click(
538+
apply_correction,
539+
inputs=[
540+
image_files_state,
541+
loaded_images_dir,
542+
loaded_control_images_dir,
543+
aspect_ratio_correction,
544+
save_padded_images,
545+
],
546+
outputs=info_box,
547+
)
548+
385549
target_images_dir.change(update_dir_list, inputs=target_images_dir, outputs=target_images_dir, show_progress=False)
386550
control_images_dir.change(
387551
lambda path, current_target: (

0 commit comments

Comments
 (0)