Python script for removing unused PNG files from the Defold project
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os, sys, hashlib, stat | |
import deftree, configparser | |
PROJECT_FILE = "game.project" | |
def all_files(ending): | |
# Generator to get files | |
for root, folders, files in os.walk(project_root): | |
for f in files: | |
if f.endswith(ending): | |
yield os.path.join(root, f) | |
def get_attribute(root, attribute_name): | |
# To simplify getting all images in an atlas | |
for x in root.iter(): | |
if deftree.is_element(x): | |
get_attribute(x, attribute_name) | |
else: | |
if x.name == attribute_name: | |
yield x | |
def image_in_file(atlas): | |
# Returns all images in an atlas | |
tree = deftree.parse(atlas) | |
root = tree.get_root() | |
images = [] | |
for x in get_attribute(root, "image"): | |
images.append(x) | |
return images | |
def image_in_cubemap(cubemap): | |
# Returns all images in a cubemap | |
tree = deftree.parse(cubemap) | |
root = tree.get_root() | |
images = [] | |
for child in root.iter(): | |
if str(child).endswith(".png\""): | |
images.append(child) | |
return images | |
def unused_png_remover(project_root): | |
output = [] | |
files_with_images = {} | |
config = configparser.ConfigParser() | |
config.read(os.path.join(project_root, PROJECT_FILE)) | |
config_images = [] | |
for key in config: | |
for value in config[key]: | |
if config[key][value].endswith(".png"): | |
config_images.append(config[key][value]) | |
files_with_images[PROJECT_FILE] = config_images | |
for x in all_files(".tilesource"): | |
name = os.path.basename(x) | |
files_with_images[name] = image_in_file(x) | |
for x in all_files(".atlas"): | |
name = os.path.basename(x) | |
files_with_images[name] = image_in_file(x) | |
for x in all_files(".cubemap"): | |
name = os.path.basename(x) | |
files_with_images[name] = image_in_cubemap(x) | |
# Iterate over all images and remove unused | |
for x in all_files(".png"): | |
count = 0 | |
img = "/" + x.replace(project_root, "").replace("\\", "/") | |
for file in files_with_images: | |
if img in files_with_images[file]: | |
count += 1 | |
if count == 0: | |
path = project_root + img | |
output.append({"file": img, "size": os.stat(path)[stat.ST_SIZE]}) | |
os.remove(path) | |
return output | |
def empty_folder_cleaner(project_root): | |
counter = 0 | |
remove_dir = True | |
while remove_dir: | |
remove_dir = False | |
for dir, subdirs, files in os.walk(project_root, topdown=False): | |
if not subdirs and not files: #check whether the directory is now empty after deletions, and if so, remove it | |
print("Folder {} removed".format(dir)) | |
os.rmdir(dir) | |
counter = counter + 1 | |
remove_dir = True | |
return counter | |
def sizeof_fmt(num, suffix): | |
for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']: | |
if abs(num) < 1024.0: | |
return "%3.1f%s%s" % (num, unit, suffix) | |
num /= 1024.0 | |
return "%.1f%s%s" % (num, 'Yi', suffix) | |
if len(sys.argv) > 1: | |
project_root = sys.argv[1] | |
if os.path.exists(project_root): | |
# Adds all atlases and its images to a dictionary | |
output = unused_png_remover(project_root) | |
#empty folders remove | |
count_of_folders = empty_folder_cleaner(project_root) | |
#Print log | |
total_size = 0 | |
for x in output: | |
print("File {} removed. {}".format(x["file"], sizeof_fmt(x["size"], "B"))) | |
total_size = total_size + x["size"] | |
print("{} files and {} folders was removed. {} ".format(len(output), count_of_folders, sizeof_fmt(total_size, "B"))) | |
else: | |
print('Usage: python remove_unused_png.py project_folder') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment