#!/usr/bin/env python3 # SPDX-License-Identifier: BSD-3-Clause # # deutex-pngs - Use deutex to process the PNGs in order to standardize them. # # Often there are PNG files that are not in the preferred format (that are not # indexed, or that are indexed with something other than PLAYPAL, that have # chunks that are not supported, etc.). For example, gAMA and similar color # correction chunks only cause the PNG to look different in image editors than # they do in game engines, which is bad. It's also for the palette to have # invalid colors, or to be missing colors, which makes the PNG hard to work # with. The solution is to use deutex to extract the WADs produced by the build, # and apply the PNGs exctracted to the build. # # This programs strives to be safe by only applying PNGs to the build when the # PNG already exists in the build since otherwise the relationship between the # extracted PNG and the build PNG is not clear. If -a, --all is specified then # the PNG will be be copied regardless. # When multiple WADs are passed to the script the each WAD effectively # overwrites the previous ones, so the preferred WAD should be passed last. # Normally this script is invoked by "make": # make fix-deutex-pngs # Imports import argparse import os import shutil import sys import tempfile import time # Globals. Alphabetical. # Command line arguments. args = {} # A count of unexpected errors. These are errors other than what this script # intends to check for, such as the file not being readable. These errors # suggest that something is fundamentally wrong, and that the results should # not be trusted. unexpected_count = 0 # Parse the command line arguments and store the result in 'args'. def parse_args(): global args parser = argparse.ArgumentParser( description="Use deutex to process the PNGs in order to standardize them.", formatter_class=argparse.ArgumentDefaultsHelpFormatter) # The following is sorted by long argument. parser.add_argument( "-a", "--all", action="store_true", help="Copy all PNGs, not just the ones that already exist in the build.") parser.add_argument( "-d", "--doom2", default="bootstrap", help="The '-doom2' deutex argument.") parser.add_argument( "wads", metavar="WAD", nargs="+", help="WAD files to apply. The preferred WAD should be last.") args = parser.parse_args() return args # Main enty point. def main(): parse_args() process_wads() summarize() # Process a WAD file. def process_wad(wad_path): global unexpected_count wad_dir = os.path.dirname(wad_path) wad_name = os.path.basename(wad_path).split(".")[0] print() print("Processing WAD", wad_path) pngs_copied = 0 with tempfile.TemporaryDirectory(prefix=wad_name + "-") as tmp_dir: print('created temporary directory', tmp_dir) ec = os.system("deutex -doom2 " + args.doom2 + " -dir " + tmp_dir + " -x " + wad_path) if ec: print("deutex failed with exit code", ec, "for WAD", wad_path, file=sys.stderr) unexpected_count += 1 return # Successful deutex from this point forward. before = time.time() for dirpath, dirnames, filenames in os.walk(tmp_dir): for png_base in filenames: if not png_base.lower().endswith(".png"): continue png_source_path = os.path.join(dirpath, png_base) png_relative = os.path.relpath(png_source_path, tmp_dir) if args.all or os.path.exists(png_relative): shutil.copyfile(png_source_path, png_relative) pngs_copied += 1 print("Processed WAD", wad_path, "copied", pngs_copied, "PNG files.") # Process multiple WAD files. def process_wads(): for wad_path in args.wads: process_wad(wad_path) # Summarize what happened, and then exit with the appropriate exit code. def summarize(): print() print("Processed", len(args.wads), "WAD files.") if unexpected_count: print("There were", unexpected_count, "unexpected errors - see above. " + "The output produced should not be trusted.", file=sys.stderr) sys.exit(1) # So that this script may be accessed as a module. if __name__ == "__main__": main()