loon4tic

housekeeper

Oct 14th, 2021
694
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. """
  2. Author: Ryan Walters
  3.  
  4. This program resizes images to power of 2 for use in game engines.
  5.  
  6. Original Repository URL: https://github.com/RyanAWalters/PowerOf2ImageResizer
  7.  
  8. Modified 9/20/21 by Loonatic
  9.  
  10. This modified version was built for managing and optimizing Toontown resources, including content packs.
  11. """
  12.  
  13. from __future__ import print_function
  14. from PIL import Image
  15.  
  16.  
  17. sizes = [4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048]  # po2 sizes
  18. # Don't include 2 since panda doesn't like that res
  19. # Nothing should EVER be considered to be higher than 2048 in res for Toontown.
  20.  
  21. def get_closest(y):
  22.     """ Return the closest power of 2 in either direction"""
  23.     return min(sizes, key=lambda x: abs(x - y))
  24.  
  25. def checkpo2(im):
  26.     name = im.filename
  27.     width, height = im.size
  28.     new_dimX = get_closest(width)
  29.     new_dimY = get_closest(height)
  30.     if width == new_dimX and height == new_dimY:
  31.         return False
  32.     if not width == new_dimX:
  33.         print("Warning: {} resizing width from {} to --> {}".format(name, width, new_dimX))
  34.     if not height == new_dimY:
  35.         print("Warning: {} resizing height from {} to --> {}".format(name, height, new_dimY))
  36.     return True
  37.  
  38. def po2(im):
  39.     """
  40.    Return a resized image that is a power of 2, modified to ignore
  41.    a need of a threshold, also converts wrt each dimension (ex: 1024x512)
  42.    """
  43.     width, height = im.size
  44.     new_dimX = get_closest(width)
  45.     new_dimY = get_closest(height)
  46.     return im.resize((new_dimX, new_dimY))
  47.  
  48. # https://pillow.readthedocs.io/en/stable/handbook/concepts.html#concept-modes
  49.  
  50. def checkColorMode(im):
  51.     cmode = im.mode
  52.     name = im.filename
  53.     if not cmode == 'RGB' and not cmode == 'RGBA':
  54.         print("Info: File {} from {} is not RGB/RGBA color mode".format(name, cmode))
  55.         #im = im.convert('RGB')
  56.  
  57. def checkICCProfile(im):
  58.     # https://stackoverflow.com/questions/31865743/pil-pillow-decode-icc-profile-information
  59.     # https://pillow.readthedocs.io/en/stable/reference/ImageCms.html#PIL.ImageCms.CmsProfile
  60.     name = im.filename
  61.     icc = im.info.get('icc_profile')
  62.     if icc is not None:
  63.         print("Warning: {} has icc data, will be removed".format(name))
  64.         return True
  65.     return False
  66.  
  67. class Housekeep():
  68.     def __init__(self, files, opt, dryrun=False):
  69.         """
  70.        Driver code
  71.        Compression ranges from 0 to 9, 0 = no compression and 9 is max,
  72.        PIL's default is 6
  73.  
  74.        files = List of files (collected from runHousekeeper)
  75.        opt = Optimize, if enabled will take a long time to finish
  76.        dryrun = If true will only print files that will be affected
  77.        """
  78.         compression = 9
  79.         try:
  80.             for file in files:
  81.                 try:
  82.                     im = Image.open(file)
  83.                     ft = im.format.upper()
  84.  
  85.                     #checkColorMode(im)
  86.                     if ft == "JPEG" or ft == "JPG": # JPGs dont have ICC profiles
  87.                         if not checkpo2(im):
  88.                             continue
  89.                         if not dryrun:
  90.                             po2(im).save(file, quality=100, subsampling=0)
  91.                     elif ft == "PNG":
  92.                             if opt: # Gonna run through them all anyway
  93.                                 po2(im).save(file, icc_profile=None, compress_level=compression, format='PNG', optimize=True)
  94.                             else:
  95.                                 if not checkICCProfile(im) or checkpo2(im):
  96.                                     continue
  97.                                 if not dryrun:
  98.                                     po2(im).save(file, icc_profile=None, compress_level=compression, format='PNG')
  99.                     else:
  100.                         po2(im).save(file)
  101.                 except IOError:
  102.                     print("IO ERROR: Is file an image? -> ", file)
  103.         except MemoryError:
  104.             print("Error: out of memory.")
  105.  
  106.  
RAW Paste Data