Skip to content

Instantly share code, notes, and snippets.

@monkishtypist
Last active March 31, 2022 18:25
Show Gist options
  • Save monkishtypist/7eefacee3c3a3935d9928dd0181bb866 to your computer and use it in GitHub Desktop.
Save monkishtypist/7eefacee3c3a3935d9928dd0181bb866 to your computer and use it in GitHub Desktop.
Image Compression and Resize with Python3 and Pillow
from PIL import Image
import getopt
import os
import shutil
import sys
def process_images(argv):
arg_help = "{0} -i <input_folder> -o <output_folder> -a -c -d <delimiter> -f -s".format(argv[0])
# Args
# -i, --input <input_folder> change the imput folder
# -o, --output <output_folder> change the output/destination folder
# -a, --append <delimiter> append image width to output file names
# -n, --clean clean the destination folder before processing
# -f, --flatten flatten the output destination folder structure (no sub-directories)
# -s, --sizes generate source set sizes
input_folder = "./images/" # image files source
output_folder = "./compressed_images/" # image files output
append = False # append image width to output file names
clean = False # clean up output folder before starting
delimiter = "__" # delimits output file naming convention {file name}{delimiter}{resized image width}{file extension}
flatten = False # flatten output folders
sizes = False # create source set sizes
# Image handling
compress_quality = 75 # JPEG compression quality
compress_level = 7 # PNG compression level
optimize = True # run image optimization on save
output_widths = [2880, 1440, 768] # widths at which the files are resized down to
file_types = ['.jpg', '.png'] # supported image file types for compression and resizing
try:
opts, args = getopt.gnu_getopt(argv[1:], "hi:o:acd:fs", ["help", "input=", "output=", "append", "clean", "delimiter=", "flatten", "sizes"])
except:
print(arg_help)
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
print(arg_help) # print the help message
sys.exit(2)
elif opt in ("-i", "--input"):
input_folder = os.path.join(arg, "")
elif opt in ("-o", "--output"):
output_folder = os.path.join(arg, "")
elif opt in ("-a", "--append"):
append = True
elif opt in ("-c", "--clean"):
clean = True
elif opt in ("-d", "--delimit"):
delimiter = str(arg)
elif opt in ("-f", "--flatten"):
flatten = True
elif opt in ("-s", "--sizes"):
sizes = True
# Clean up output directory/files
if clean :
try :
shutil.rmtree(output_folder)
except FileNotFoundError :
print("'%s' directory not found" % output_folder)
pass
else :
print("Successfully removed the directory '%s'" % output_folder)
# (Re)Create our output location
try :
os.makedirs(output_folder)
except OSError:
print("Creation of the directory '%s' failed" % output_folder)
else :
print("Successfully created the directory '%s'" % output_folder)
# Do the work
for root, dirs, files in os.walk(input_folder, topdown = True) :
# Maintain folder structure or flatten?
if not flatten :
for dir in dirs :
full_dir = os.path.join(output_folder, dir)
try :
os.makedirs(full_dir)
except OSError:
print("Creation of the directory '%s' failed" % full_dir)
else :
print("Successfully created the directory '%s'" % full_dir)
# Process files
for file in files :
name, ext = os.path.splitext(file)
if ext not in file_types :
print("Skipped file %s, extension not valid" % file)
else :
with Image.open(os.path.join(root, file)) as im :
original_width = int(im.size[0])
original_height = int(im.size[1])
max_output_height = original_width * 2
# Maintain folder structure or flatten?
if flatten :
output_destination = output_folder
else :
output_destination = root.replace(input_folder, output_folder)
# Generate output file name
if append :
output_file = name + delimiter + str(original_width) + ext
else :
output_file = file
# Generate compressed copy of original image
try :
im.save(os.path.join(output_destination, output_file), im.format, optimize=optimize, quality=compress_quality, compress_level=compress_level)
except OSError :
print("There was an error saving %s" % output_file)
else :
print("Image %s successfully saved" % output_file)
# Generate resized images for source sets
if sizes :
for output_width in output_widths:
if output_width < original_width :
output_file = name + delimiter + str(output_width) + ext # resized image file names are always appended
im.thumbnail((output_width, max_output_height)) # We use .thumbnail() because it preserves aspect ratio
try :
im.save(os.path.join(output_destination, output_file), im.format, optimize=optimize, quality=compress_quality, compress_level=compress_level)
except OSError :
print("There was an error saving %s" % output_file)
else :
print("Image %s successfully saved" % output_file)
if __name__ == "__main__":
process_images(sys.argv)
# Do this:
# Make sure you have Python3 and Pillow installed
# Put all your JPG and PNG images into the <input_folder>
# You can change compression quality with compress_quality variable [for JPEG] and the compress_level variable [for PNG]
# Run script with python3: `python3 imageprocess.py`
# Reference materials:
# https://pillow.readthedocs.io/en/stable/reference/Image.html
# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment