Skip to content

Commit b1690f7

Browse files
author
dn0z
committed
Improved valid settings check, moved editing logic to imgedit module
1 parent e7e672f commit b1690f7

File tree

2 files changed

+156
-95
lines changed

2 files changed

+156
-95
lines changed

bir.py

Lines changed: 70 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,30 @@
44
# Copyright (c) 2016 dn0z
55
# https://github.com/dn0z/Batch-Image-Resize
66

7+
import imgedit
78
import os
8-
import PIL.Image
9+
10+
from enum import Enum
911
from tkinter import *
1012
from tkinter import ttk
1113
from tkinter import filedialog
1214
from tkinter import messagebox
1315

1416

17+
class SettingsStatus(Enum):
18+
"""
19+
An enumeration of the settings statuses
20+
"""
21+
22+
# valid settings
23+
valid_settings = 1
24+
25+
# invalid settings
26+
directory_not_selected = 2
27+
directory_does_not_exist = 3
28+
invalid_dimensions = 4
29+
30+
1531
class Application(Frame):
1632
def set_properties_defaults(self):
1733
"""
@@ -46,111 +62,70 @@ def confirm_settings(self):
4662

4763
return messagebox.askyesno("Export confirmation", confirm_msg)
4864

49-
def is_image(self, filename):
65+
def get_settings_status(self):
5066
"""
51-
Checks if a filename is an image (png, jpg or jpeg, case insensitive)
67+
Check if our settings are valid (directory exists, width and height are digits etc)
5268
53-
:param filename: The filename (as a string)
54-
:return: `True` if the given filename is an image, or `False` if it's not
69+
:return: The settings status as an enumeration member of the
70+
`SettingsStatus` enumeration (e.g. `SettingsStatus.valid_settings`)
5571
"""
5672

57-
file = filename.lower()
58-
return file.endswith(".png") or file.endswith(".jpg") or file.endswith(".jpeg")
59-
60-
def get_filename_with_type(self, filename, file_type, suffix=""):
61-
"""
62-
Get a filename and return it with the given suffix and the correct file extension for the given type
63-
64-
:param filename: The filename (e.g. "image_file.jpg")
65-
:param file_type: The file type (e.g. "PNG")
66-
:param suffix: An optional string to place between the name and the extension of the file (default is "")
67-
:return: the filename with the correct extension for the given type (e.g. "image_file.png")
68-
"""
69-
70-
extension = filename.split(".")[-1]
71-
return filename[:-(len(extension) + 1)] + suffix + "." + file_type.lower()
72-
73-
def export_file(self, path, name, width, height, export_type, overwrite):
74-
"""
75-
Open, resize and save an image with the given properties
76-
77-
:param path: The path to the directory where the image is located (without the image filename)
78-
:param name: The filename of the image we want to export
79-
:param width: The new width we want to resize to
80-
:param height: The new height we want to resize to
81-
:param export_type: The file type we want to save to (we ignore it if `overwrite` is `True`)
82-
:param overwrite: Whether we want to overwrite the original files or not
83-
"""
84-
85-
img_path = os.path.join(path, name)
86-
87-
# open the given image and resize it
88-
img = PIL.Image.open(img_path)
89-
img = img.resize((width, height), PIL.Image.ANTIALIAS)
90-
91-
# set the destination image file we want to save
92-
dest_img_name = self.get_filename_with_type(name, export_type, "_resized")
93-
if overwrite:
94-
dest_img_name = name
95-
96-
# save the resized/converted image
97-
img.save(os.path.join(path, dest_img_name))
98-
99-
def init_export(self):
100-
"""
101-
Export all the images in the selected directory
73+
selected_directory = self.selected_directory.get()
10274

103-
When `self.init_export()` is called, everything is ready to resize and export images
104-
This loops through all the files in the given directory and calls `self.export_file()`
105-
for the actual opening, resizing and saving of the files
106-
"""
75+
# Check if a directory is selected
76+
if selected_directory == "No directory selected":
77+
return SettingsStatus.directory_not_selected
10778

108-
# final export settings
109-
directory_path = self.selected_directory.get()
110-
width = int(self.export_properties["width"].get())
111-
height = int(self.export_properties["height"].get())
112-
export_type = self.export_properties["type"].get()
113-
overwrite = self.overwrite_original.get()
79+
# Check if the selected directory exists
80+
if not os.path.isdir(selected_directory):
81+
return SettingsStatus.directory_does_not_exist
11482

115-
# loop through the files in the given directory and export any image files
116-
for path, subdirs, files in os.walk(directory_path):
117-
for name in files:
118-
if self.is_image(name):
119-
# TODO: Add a new window with a progress bar while exporting images
120-
self.export_file(path, name, width, height, export_type, overwrite)
83+
# Check if width and height are digits
84+
if (not self.export_properties["width"].get().isdigit()) or \
85+
(not self.export_properties["height"].get().isdigit()):
86+
return SettingsStatus.invalid_dimensions
12187

122-
# at this point, we are done with our exports, display a success message
123-
messagebox.showinfo("Exports completed", "All images were exported successfully")
88+
return SettingsStatus.valid_settings
12489

12590
def export_button_handler(self):
12691
"""
12792
The handler of the Export button
12893
"""
12994

130-
selected_directory = self.selected_directory.get()
131-
132-
# Check if we are ready to export
133-
if selected_directory == "No directory selected":
134-
# No directory selected
135-
messagebox.showerror("Invalid directory", "You have to select a directory first")
95+
settings_status = self.get_settings_status()
96+
97+
if settings_status is not SettingsStatus.valid_settings:
98+
# Invalid settings, display an error message
99+
error_messages = {
100+
SettingsStatus.directory_not_selected: [
101+
"Invalid directory",
102+
"You have to select a directory first"
103+
],
104+
SettingsStatus.directory_does_not_exist: [
105+
"Invalid directory",
106+
"The directory \"" + self.selected_directory.get() + "\" does not exist"
107+
],
108+
SettingsStatus.invalid_dimensions: [
109+
"Invalid dimensions",
110+
"Width and height must be integers"
111+
],
112+
}
113+
messagebox.showerror(*error_messages[settings_status])
136114
else:
137-
# Directory selected
138-
if not os.path.isdir(selected_directory):
139-
# Directory does not exist
140-
messagebox.showerror("Invalid directory",
141-
"The directory \"" + selected_directory + "\" does not exist")
142-
else:
143-
# Directory exists
144-
if (not self.export_properties["width"].get().isdigit()) or \
145-
(not self.export_properties["height"].get().isdigit()):
146-
# Dimensions are not digits
147-
messagebox.showerror("Invalid dimensions",
148-
"Width and height must be integers")
149-
else:
150-
# Dimensions are digits
151-
if self.confirm_settings():
152-
# Settings confirmed, we are ready to export
153-
self.init_export()
115+
# Valid settings, confirm settings with the user and export
116+
if self.confirm_settings():
117+
result = imgedit.export_all_in_dir(
118+
self.selected_directory.get(),
119+
int(self.export_properties["width"].get()),
120+
int(self.export_properties["height"].get()),
121+
self.export_properties["type"].get(),
122+
self.overwrite_original.get()
123+
)
124+
125+
if result:
126+
# at this point, we are done with our exports, display a success message
127+
messagebox.showinfo("Exports completed",
128+
"All images were exported successfully")
154129

155130
def browse_for_directory(self):
156131
"""
@@ -212,10 +187,10 @@ def create_widgets(self):
212187
save_as_label.grid(row=3, column=0, sticky="e")
213188

214189
self.save_as_dropdown = ttk.OptionMenu(main_container,
215-
self.export_properties["type"],
216-
self.export_properties["type"].get(),
217-
"PNG",
218-
"JPEG")
190+
self.export_properties["type"],
191+
self.export_properties["type"].get(),
192+
"PNG",
193+
"JPEG")
219194
self.save_as_dropdown.grid(row=3, column=1, sticky="we", padx=2)
220195

221196
# Overwrite original

imgedit.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#! /usr/bin/env python
2+
3+
# Batch Image Resize - imgedit module
4+
# Copyright (c) 2016 dn0z
5+
# https://github.com/dn0z/Batch-Image-Resize
6+
7+
import os
8+
import PIL.Image
9+
10+
11+
def is_image(filename):
12+
"""
13+
Checks if a filename is an image (png, jpg or jpeg, case insensitive)
14+
15+
:param filename: The filename (as a string)
16+
:return: `True` if the given filename is an image, or `False` if it's not
17+
"""
18+
19+
file = filename.lower()
20+
return file.endswith(".png") or file.endswith(".jpg") or file.endswith(".jpeg")
21+
22+
23+
def get_filename_with_type(filename, file_type, suffix=""):
24+
"""
25+
Get a filename and return it with the given suffix and the correct file extension for the given type
26+
27+
:param filename: The filename (e.g. "image_file.jpg")
28+
:param file_type: The file type (e.g. "PNG")
29+
:param suffix: An optional string to place between the name and the extension of the file (default is "")
30+
:return: the filename with the correct extension for the given type (e.g. "image_file.png")
31+
"""
32+
33+
extension = filename.split(".")[-1]
34+
return filename[:-(len(extension) + 1)] + suffix + "." + file_type.lower()
35+
36+
37+
def export_file(path, name, width, height, export_type, overwrite):
38+
"""
39+
Open, resize and save an image with the given properties
40+
41+
:param path: The path to the directory where the image is located (without the image filename)
42+
:param name: The filename of the image we want to export
43+
:param width: The new width we want to resize to
44+
:param height: The new height we want to resize to
45+
:param export_type: The file type we want to save to (we ignore it if `overwrite` is `True`)
46+
:param overwrite: Whether we want to overwrite the original files or not
47+
"""
48+
49+
img_path = os.path.join(path, name)
50+
51+
# open the given image and resize it
52+
img = PIL.Image.open(img_path)
53+
img = img.resize((width, height), PIL.Image.ANTIALIAS)
54+
55+
# set the destination image file we want to save
56+
dest_img_name = get_filename_with_type(name, export_type, "_resize")
57+
if overwrite:
58+
dest_img_name = name
59+
60+
# save the resized/converted image
61+
img.save(os.path.join(path, dest_img_name))
62+
63+
64+
def export_all_in_dir(selected_dir, width, height, export_type, overwrite):
65+
"""
66+
Export all the images in the selected directory
67+
68+
When `self.init_export()` is called, everything is ready to resize and export images
69+
This loops through all the files in the given directory and calls `self.export_file()`
70+
for the actual opening, resizing and saving of the files
71+
72+
:param selected_dir: The path to the directory containing all the images to resize
73+
:param width: The new width we want to resize to
74+
:param height: The new height we want to resize to
75+
:param export_type: The file type we want to save to (we ignore it if `overwrite` is `True`)
76+
:param overwrite: Whether we want to overwrite the original files or not
77+
:return: `True` if all images were exported successfully or `False` if there was an error
78+
"""
79+
80+
for path, subdirs, files in os.walk(selected_dir):
81+
for name in files:
82+
if is_image(name):
83+
# TODO: Add a new window with a progress bar while exporting images
84+
export_file(path, name, width, height, export_type, overwrite)
85+
86+
return True

0 commit comments

Comments
 (0)