5
5
# https://github.com/dn0z/Batch-Image-Resize
6
6
7
7
import os
8
-
8
+ from PIL import Image
9
9
from tkinter import *
10
10
from tkinter import ttk
11
11
from tkinter import filedialog
@@ -21,8 +21,8 @@ def set_properties_defaults(self):
21
21
self .selected_directory .set ("No directory selected" )
22
22
self .export_properties ["width" ].set ("width px" )
23
23
self .export_properties ["height" ].set ("height px" )
24
- self .export_properties ["type" ].set ("PNG" ) # default export type
25
- self .overwrite_original .set (False ) # default is disabled
24
+ self .export_properties ["type" ].set ("PNG" ) # default export type
25
+ self .overwrite_original .set (False ) # default is disabled
26
26
27
27
def confirm_settings (self ):
28
28
"""
@@ -37,7 +37,7 @@ def confirm_settings(self):
37
37
confirm_msg += "\n Resize images to: " + self .export_properties ["width" ].get ()
38
38
confirm_msg += "x" + self .export_properties ["height" ].get () + " px"
39
39
confirm_msg += "\n Overwrite original: "
40
- if self .overwrite_original :
40
+ if self .overwrite_original . get () :
41
41
confirm_msg += "YES"
42
42
else :
43
43
confirm_msg += "NO"
@@ -46,8 +46,81 @@ def confirm_settings(self):
46
46
47
47
return messagebox .askyesno ("Export confirmation" , confirm_msg )
48
48
49
- def export (self ):
50
- print ("Exporting" )
49
+ def is_image (self , filename ):
50
+ """
51
+ Checks if a filename is an image (png, jpg or jpeg, case insensitive)
52
+
53
+ :param filename: The filename (as a string)
54
+ :return: `True` if the given filename is an image, or `False` if it's not
55
+ """
56
+
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 )] + suffix + "." + file_type .lowercase ()
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 = Image .open (img_path )
89
+ img = img .resize ((width , height ), 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
+ print ("Save to " + os .path .join (path , dest_img_name ))
98
+ # img.save(os.path.join(path, dest_img_name))
99
+
100
+ def init_export (self ):
101
+ """
102
+ Export all the images in the selected directory
103
+
104
+ When `self.init_export()` is called, everything is ready to resize and export images
105
+ This loops through all the files in the given directory and calls `self.export_file()`
106
+ for the actual opening, resizing and saving of the files
107
+ """
108
+
109
+ # final export settings
110
+ directory_path = self .selected_directory .get ()
111
+ width = int (self .export_properties ["width" ].get ())
112
+ height = int (self .export_properties ["height" ].get ())
113
+ export_type = self .export_properties ["type" ].get ()
114
+ overwrite = self .overwrite_original .get ()
115
+
116
+ # loop through the files in the given directory and export any image files
117
+ for path , subdirs , files in os .walk (directory_path ):
118
+ for name in files :
119
+ if self .is_image (name ):
120
+ self .export_file (path , name , width , height , export_type , overwrite )
121
+
122
+ # at this point, we are done with our exports, display a success message
123
+ messagebox .showinfo ("Exports completed" , "All images were exported successfully" )
51
124
52
125
def export_button_handler (self ):
53
126
"""
@@ -68,9 +141,16 @@ def export_button_handler(self):
68
141
"The directory \" " + selected_directory + "\" does not exist" )
69
142
else :
70
143
# Directory exists
71
- if self .confirm_settings ():
72
- # Settings confirmed, we are ready to export
73
- self .export ()
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 ()
74
154
75
155
def browse_for_directory (self ):
76
156
"""
@@ -80,6 +160,19 @@ def browse_for_directory(self):
80
160
81
161
self .selected_directory .set (filedialog .askdirectory ())
82
162
163
+ def toggle_save_as_dropdown (self ):
164
+ """
165
+ Change the state of `self.save_as_dropdown` based on `self.overwrite_original`
166
+
167
+ The dropdown should be enabled when `self.overwrite_original` is set to `False`
168
+ and disabled when `self.overwrite_original` is set to `True`
169
+ """
170
+
171
+ if self .overwrite_original .get ():
172
+ self .save_as_dropdown .configure (state = "disabled" )
173
+ else :
174
+ self .save_as_dropdown .configure (state = "enabled" )
175
+
83
176
def create_widgets (self ):
84
177
"""
85
178
Create the UI elements
@@ -118,19 +211,20 @@ def create_widgets(self):
118
211
save_as_label = Label (main_container , text = "Save as:" , font = font_medium )
119
212
save_as_label .grid (row = 3 , column = 0 , sticky = "e" )
120
213
121
- save_as_dropdown = ttk .OptionMenu (main_container ,
214
+ self . save_as_dropdown = ttk .OptionMenu (main_container ,
122
215
self .export_properties ["type" ],
123
216
self .export_properties ["type" ].get (),
124
217
"PNG" ,
125
218
"JPEG" )
126
- save_as_dropdown .grid (row = 3 , column = 1 , sticky = "we" , padx = 2 )
219
+ self . save_as_dropdown .grid (row = 3 , column = 1 , sticky = "we" , padx = 2 )
127
220
128
221
# Overwrite original
129
222
overwrite_checkbox = ttk .Checkbutton (main_container ,
130
223
text = "Overwrite original" ,
131
224
variable = self .overwrite_original ,
132
225
onvalue = True ,
133
- offvalue = False )
226
+ offvalue = False ,
227
+ command = self .toggle_save_as_dropdown )
134
228
overwrite_checkbox .grid (row = 4 , column = 0 , columnspan = 2 , sticky = "w" )
135
229
136
230
# Export
@@ -150,6 +244,8 @@ def __init__(self, parent=None):
150
244
Frame .__init__ (self , parent )
151
245
152
246
# properties
247
+ self .save_as_dropdown = None
248
+
153
249
self .selected_directory = StringVar (self )
154
250
self .overwrite_original = BooleanVar (self )
155
251
self .export_properties = {
0 commit comments