Skip to content

Instantly share code, notes, and snippets.

@tigerhawkvok
Last active July 5, 2021 04:56
Show Gist options
  • Save tigerhawkvok/2d5ecd4a56235edc06ac8f96984fb5d6 to your computer and use it in GitHub Desktop.
Save tigerhawkvok/2d5ecd4a56235edc06ac8f96984fb5d6 to your computer and use it in GitHub Desktop.
Webify a directory of images
#!python3
"""
When run as a script, opens all .jpg and .png
files in the folder and downsamples them to
maximum 1280 pixels wide and quality level 75
PNG optimization requires OptiPNG to be installed
in your PATH: http://optipng.sourceforge.net/
(GitHub mirror: https://github.com/countingpine/optipng )
@author Philip Kahn <https://github.com/tigerhawkvok/>
@license MIT
@url https://gist.github.com/tigerhawkvok/2d5ecd4a56235edc06ac8f96984fb5d6
"""
import glob
import os
import imghdr
from typing import Union
from skimage.io import imread, imsave
from skimage.transform import rescale
import numpy as np
IGNORE_OPTIMIZE_LIST = frozenset([
"logo.png",
"fps_pfe_4x6.png",
])
def _getImage(filePath) -> Union[np.ndarray, None]:
"""
Tidy file return.
Renames the file if the extension doesn't match
the filetype.
"""
try:
if os.path.basename(filePath) in IGNORE_OPTIMIZE_LIST:
return None
fileExtension = os.path.splitext(filePath)[1][1:]
what = imghdr.what(filePath)
filePathNew = None
if what == "jpeg" and fileExtension.lower() not in ("jpg", "jpeg"):
filePathNew = filePath.replace(f".{fileExtension}", ".jpg")
elif what is not None and fileExtension.lower() != what:
filePathNew = filePath.replace(f".{fileExtension}", f".{what}")
if filePathNew is not None:
# Rename the file with the corrected resolution
os.rename(filePath, filePathNew)
filePath = filePathNew
return imread(filePath).astype(np.uint8)
except Exception: #pylint: disable= broad-except
return None
def downscaleJPGs(relativeDir:str= "./", maxResolution:int= 1280, quality:int= 75):
"""
Opens all .jpg files in a folder and downscale them to
maxResolution
"""
for jpgFile in glob.glob(os.path.join(relativeDir, '*.jpg')):
img = _getImage(jpgFile)
if img is None:
continue
scale = maxResolution / max(img.shape[0], img.shape[1])
if scale >= 1:
print(f"{jpgFile} OK size")
continue
print(f"Checking {jpgFile}")
img = rescale(img, scale, anti_aliasing= True, preserve_range= True, multichannel= True).astype(np.uint8)
try:
imsave(jpgFile, img, quality= quality)
except Exception as e: #pylint: disable= broad-except
print(f">> Failed to convert {jpgFile} of shape {img.shape}: {e}")
def optimizePNGs(relativeDir:str= "./", maxResolution:int= 1280):
"""
Call this function to optimize all .png files in a folder
"""
validPNG = set()
for pngFile in glob.glob(os.path.join(relativeDir, '*.png')):
img = _getImage(pngFile)
if img is None:
continue
scale = maxResolution / max(img.shape[0], img.shape[1])
if scale >= 1:
print(f"{pngFile} OK size")
validPNG.update([pngFile])
continue
print(f"Resizing {pngFile}")
img = rescale(img, scale, anti_aliasing= True, preserve_range= True, multichannel= True).astype(np.uint8)
try:
imsave(pngFile, img)
validPNG.update([pngFile])
except Exception as e: #pylint: disable= broad-except
print(f">> Failed to convert {pngFile} of shape {img.shape}: {e}")
# Now call optiPNG locally to optimize the rescaled images
for pngFile in validPNG:
print(f"Optimizing {pngFile}")
cmd = f"optipng -o5 -v {pngFile}"
os.system(cmd)
if __name__ == "__main__":
TARGET_MAX_RESOLUTION_PX = 1280
downscaleJPGs(maxResolution= TARGET_MAX_RESOLUTION_PX)
optimizePNGs(maxResolution= TARGET_MAX_RESOLUTION_PX)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment