Skip to content

Instantly share code, notes, and snippets.

@kristofmulier
Created January 21, 2024 10:46
Show Gist options
  • Save kristofmulier/8ab75068b79acc793a7ec36f25cb335f to your computer and use it in GitHub Desktop.
Save kristofmulier/8ab75068b79acc793a7ec36f25cb335f to your computer and use it in GitHub Desktop.
Convert Images to webp
'''
Copyright 2018-2023 Johan Cockx, Matic Kukovec and Kristof Mulier
'''
# NOTE:
# COMMAND TO CONVERT IMAGES IS
# cwebp {input_filename} -o {output_filename}
import os, sys, argparse, subprocess, math
q = "'"
size_db = {}
def show_help() -> None:
'''
Print help info and quit.
'''
print('Provide a folder to be converted.')
def convert_images(directory:str) -> None:
'''
Convert all images in the given directory.
'''
print(f'\nConvert all images in {q}{directory}{q}:')
print(f'{"-" * 61}')
for root, dirs, files in os.walk(directory):
for f in files:
if not f.endswith(('.png', '.jpg', '.jpeg')):
continue
filepath = os.path.join(root, f).replace('\\', '/')
convert(filepath)
continue
continue
print(f'{"-" * 61}')
# Print how much space has been freed
total_input_size = sum(s[0] for k,s in size_db.items())
total_output_size = sum(s[1] for k,s in size_db.items())
difference = total_input_size - total_output_size
print('')
print(f'Total size of original files: {convert_size(total_input_size)}')
print(f'Total size after conversion: {convert_size(total_output_size)}')
print(f'Difference: {convert_size(difference)}')
return
def delete_originals(directory:str) -> None:
'''
Delete the original .png, .jpg and .jpeg images
'''
if not yes_no('Delete original images?'):
return
print(f'{"-" * 42}')
for root, dirs, files in os.walk(directory):
for f in files:
if not f.endswith(('.png', '.jpg', '.jpeg')):
continue
filepath = os.path.join(root, f).replace('\\', '/')
os.remove(filepath)
print(f'| Delete: {f.ljust(30)} |')
continue
continue
print(f'{"-" * 42}')
return
def convert(input_filepath:str) -> None:
'''
Convert the given image and store it with the '.webp' extension.
'''
input_filepath = input_filepath.replace('\\', '/')
input_filename = input_filepath.split('/')[-1]
output_filename = input_filename\
.replace('.png', '.webp')\
.replace('.jpg', '.webp')\
.replace('.jpeg', '.webp')
output_filepath = os.path.join(
os.path.dirname(input_filepath),
output_filename,
).replace('\\', '/')
cmd = f'cwebp {input_filename} -o {output_filename}'
result = subprocess.run(
cmd,
stdin = subprocess.DEVNULL,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE,
cwd = os.path.dirname(input_filepath).replace('\\', '/'),
encoding = 'utf-8',
)
if result.returncode:
print(f'\nERROR: Cannot convert {input_filepath}\n')
sys.stdout.flush()
sys.exit(1)
input_size = os.path.getsize(input_filepath)
output_size = os.path.getsize(output_filepath)
size_db[input_filepath] = (input_size, output_size, input_size - output_size)
input_size_str = convert_size(input_size)
output_size_str = convert_size(output_size)
print(f'| {input_filename.ljust(30)} | {input_size_str.ljust(10)} -> {output_size_str.ljust(10)} |')
return
def convert_size(size_bytes:int) -> str:
'''
Format a size in bytes for pretty printing.
'''
if size_bytes == 0:
return '0B'
size_name = ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB')
i = int(math.floor(math.log(size_bytes, 1024)))
p = math.pow(1024, i)
s = round(size_bytes / p, 2)
return f'{s} {size_name[i]}'
def yes_no(question:str) -> bool:
'''
Ask user a yes/no question
'''
check = str(input(f'{question} (Y/N): ')).lower().strip()
try:
if check[0] == 'y':
return True
elif check[0] == 'n':
return False
else:
print('Invalid Input')
return yes_no(question)
except Exception as error:
print('Please enter valid inputs')
print(error)
return yes_no(question)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description = 'Convert images to .webp format',
add_help = False,
)
parser.add_argument('-h', '--help', action='store_true')
parser.add_argument('-d', '--directory', action='store')
args = parser.parse_args()
if args.help:
show_help()
if args.directory is not None:
convert_images(args.directory)
delete_originals(args.directory)
print('\nQuit image converter tool\n')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment