expected multiple file output but only last one is saved

17 views Asked by At

so I made this Python GUI program that started with a very simple function: using askfiledialog to input one image, enter the target size in MB, resize the image, output in askfiledialog again. I decided to expand the program so that it will accept multiple input and using if-else statement to determine whether the input files is single or multiple; if the input is multiple, instead of using askfiledialog, it will default to save all the resized images in the original file path and the file names will be original file name + "_(target size)"

after running it i found that only the last image is resized and saved successfully. I have used AI to help diagnose the issue but it keeps chasing its own tail and told me it has changed the code but in fact was just repeating the code i input to it.

this is the complete code of the program:

import os
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image
import io
from itertools import zip_longest


class ImageResizer:
    def __init__(self, master):
        self.master = master
        master.title("Image Resizer")
        self.mode = None
        self.label = tk.Label(master, text="Select an image to resize")
        self.label.pack()

        self.select_button = tk.Button(master, text="Select Image", command=self.select_image)
        self.select_button.pack()

        self.size_entry = tk.Entry(master)
        self.size_entry.pack()
        self.size_entry.insert(0, "Enter target size in MB")
        self.size_entry.bind("<FocusIn>", self.clear_text)
        self.size_entry.bind("<FocusOut>", self.reset_text)

        self.maintain_pixels_var = tk.IntVar()
        self.maintain_pixels_cb = tk.Checkbutton(master, text="Maintain original pixels",
                                                 variable=self.maintain_pixels_var)
        self.maintain_pixels_cb.pack()
        self.maintain_orientation_var = tk.IntVar()
        self.maintain_orientation_cb = tk.Checkbutton(master, text="Maintain original orientation",
                                                      variable=self.maintain_orientation_var)
        self.maintain_orientation_cb.pack()

        self.save_button = tk.Button(master, text="Save resized image", command=self.save_image, state="disabled")
        self.save_button.pack()

        self.file_path = None
        self.image = None
        self.format = None
        self.width = None
        self.height = None
        self.file_paths = None  # Store the list of file paths
        self.images = None  # Store the list of images
        self.formats = None  # Store the list of formats
        self.widths = None
        self.heights = None

    def select_image(self):
        self.file_path = filedialog.askopenfilename(filetypes=(("jpeg files", "*.jpg"), ("png files", "*.png")),multiple=True)
        self.file_paths = self.master.tk.splitlist(self.file_path)


        num_images = len(self.file_paths)
        if num_images > 1:
            images = []
            formats = []
            widths = []
            heights = []
            for file_path in self.file_paths:
                try:
                    image = Image.open(file_path)
                    format = image.format
                    width = image.width
                    height = image.height
                    images.append(image)
                    formats.append(format)
                    widths.append(width)
                    heights.append(height)
                    self.images = images
                    self.formats = formats
                    self.heights = heights
                    self.widths = widths
                except:
                    print(f"Invalid file path: {file_path}")


            self.images = images
            self.formats = formats
            self.heights = heights
            self.widths = widths
            self.label['text'] = f"Selected {num_images} images"
            self.save_button['state'] = "normal"
            print("Heights:", heights)
            print("Widths:", widths)
            messagebox.showinfo("Heights and Widths", f"Heights: {heights}\nWidths: {widths}")
        else:
            self.file_path = self.file_paths[0]
            self.image = Image.open(self.file_path)
            self.format = self.image.format
            self.label['text'] = f"Selected {self.file_path} \nSize: {os.path.getsize(self.file_path)/1e6:.2f}MB \nDimensions: {self.image.size}"
            # Determine if image is landscape or portrait
            if self.image.width > self.image.height:
                self.label['text'] += "\nOrientation: Landscape"
            else:
                self.label['text'] += "\nOrientation: Portrait"
            self.save_button['state'] = "normal"

    def save_image(self):
        size_str = self.size_entry.get()
        save_paths = []
        if self.images:

            for i, (image, format, height, width, file_path) in enumerate(
                    zip_longest(self.images, self.formats, self.heights, self.widths, self.file_paths)):
                ratio = (float(size_str) * 1e6 / os.path.getsize(file_path)) ** 0.5
            new_size = (int(height * ratio), int(width * ratio))

            if self.maintain_orientation_var.get() and new_size[0] > image.width:
                        new_size = (image.width, image.height)
            else:

               resized_image = image.resize(new_size, Image.LANCZOS) if not self.maintain_pixels_var.get() else image

            save_path = image.filename
            save_path += f"{i}"
            save_path = os.path.splitext(file_path)[0] + f"_{size_str}" + os.path.splitext(file_path)[1]
            save_paths.append(save_path)

            for i, save_path in enumerate(save_paths):
                # get the resized image at the corresponding index
                resized_img = self.images[i]
                # save the resized image to the new file with the save path
                resized_img.save(save_path)
                # print the save path to the console
                print(f"Saved image {i} to {save_path}")
                messagebox.showinfo("Success", f"Saved {len(self.images)} resized images")
        else:
            target_size = float(size_str) * 1e6  # convert to bytes


        # get the ratio of the change in size
            ratio = (target_size / os.path.getsize(self.file_path)) ** 0.5

            new_size = (int(self.image.width * ratio), int(self.image.height * ratio))
            if self.maintain_orientation_var.get() and new_size[0] < new_size[1]:  # If image is meant to be landscape
                new_size = (new_size[1], new_size[0])

            resized_image = self.image.resize(new_size, Image.LANCZOS) if not self.maintain_pixels_var.get() else self.image

            save_path = filedialog.asksaveasfilename(defaultextension=".jpg", filetypes=(("jpeg files", "*.jpg"), ("png files", "*.png")))

            quality = 95
            while True:
                with io.BytesIO() as temp_file:
                    resized_image.save(temp_file, format=self.format, optimize=True, quality=quality)
                    if temp_file.tell() <= target_size or quality <= 10:
                        break
                    quality -= 5  # reduce quality by 5

            resized_image.save(save_path, format=self.format, optimize=True, quality=quality)

            messagebox.showinfo("Success", f"Image saved to {save_path}")

    def clear_text(self, event):
        if self.size_entry.get() == 'Enter target size in MB':
            self.size_entry.delete(0, 'end')

    def reset_text(self, event):
        if not self.size_entry.get():
            self.size_entry.insert(0, 'Enter target size in MB')

root = tk.Tk()
my_gui = ImageResizer(root)
root.mainloop()
0

There are 0 answers