107 lines
3.6 KiB
Python
107 lines
3.6 KiB
Python
|
#!/usr/bin/python
|
||
|
# Amiga AGI game palette extractor.
|
||
|
# Extracts palette from an Amiga AGI game's executable file.
|
||
|
# Initial version written during summer of 2007 by Buddha^.
|
||
|
# Unoptimized.
|
||
|
import struct, sys, os.path
|
||
|
|
||
|
# Constants
|
||
|
maxComponentValue = 0x0F
|
||
|
colorsPerPalette = 16
|
||
|
componentsPerColor = 3
|
||
|
bytesPerComponent = 2
|
||
|
bytesPerColor = componentsPerColor * bytesPerComponent
|
||
|
paletteComponentCount = colorsPerPalette * componentsPerColor
|
||
|
paletteByteCount = paletteComponentCount * bytesPerComponent
|
||
|
black = tuple([0 for x in range(componentsPerColor)])
|
||
|
white = tuple([maxComponentValue for x in range(componentsPerColor)])
|
||
|
componentPrintFormat = "0x%1X"
|
||
|
|
||
|
def is12BitColor(color):
|
||
|
"""Is color 12-bit (i.e. 4 bits per color component)?"""
|
||
|
return color == filter(lambda component: 0 <= component <= maxComponentValue, color)
|
||
|
|
||
|
def printColor(color, tabulate = True, printLastComma = True, newLine = True):
|
||
|
"""Prints color with optional start tabulation, comma in the end and a newline"""
|
||
|
result = ""
|
||
|
if tabulate:
|
||
|
result = result + "\t"
|
||
|
for component in color[:-1]:
|
||
|
result = result + ((componentPrintFormat + ", ") % component)
|
||
|
result = result + (componentPrintFormat % color[-1])
|
||
|
if printLastComma:
|
||
|
result = result + ","
|
||
|
if newLine:
|
||
|
print result
|
||
|
else:
|
||
|
print result,
|
||
|
|
||
|
def printPalette(palette, arrayName):
|
||
|
"""Prints out palette as a C-style array"""
|
||
|
print "/** A 16-color, 12-bit RGB palette from an Amiga AGI game. */"
|
||
|
print "static const unsigned char " + arrayName + "[] = {"
|
||
|
for color in palette[:-1]:
|
||
|
printColor(color)
|
||
|
printColor(palette[-1], printLastComma = False)
|
||
|
print("};")
|
||
|
|
||
|
def isAmigaPalette(palette):
|
||
|
"""Test if the given palette is an Amiga-style palette"""
|
||
|
# Palette must be of correct size
|
||
|
if len(palette) != colorsPerPalette:
|
||
|
return False
|
||
|
|
||
|
# First palette color must be black, last color white
|
||
|
if palette[0] != black or palette[-1] != white:
|
||
|
return False
|
||
|
|
||
|
# All colors must be 12-bit (i.e. 4 bits per color component)
|
||
|
for color in palette:
|
||
|
if not is12BitColor(color):
|
||
|
return False
|
||
|
|
||
|
# All colors must be unique
|
||
|
if len(set(palette)) != colorsPerPalette:
|
||
|
return False
|
||
|
|
||
|
return True
|
||
|
|
||
|
# The main program starts here
|
||
|
if len(sys.argv) <= 2 or sys.argv[1] == "-h" or sys.argv[1] == "--help":
|
||
|
quit("Usage: " + os.path.basename(sys.argv[0]) + " FILE ARRAYNAME\n" \
|
||
|
" Searches FILE for an Amiga AGI game palette\n" \
|
||
|
" and prints out any found candidates as C-array style arrays with the name ARRAYNAME.");
|
||
|
|
||
|
# Open file and read it into memory
|
||
|
file = open(sys.argv[1], 'rb')
|
||
|
data = file.read()
|
||
|
foundPalettes = []
|
||
|
palette = [black for x in range(colorsPerPalette)]
|
||
|
# Search through the whole file
|
||
|
for searchPosition in range(len(data) - paletteByteCount + 1):
|
||
|
# Parse possible palette from byte data
|
||
|
for colorNum in range(colorsPerPalette):
|
||
|
paletteStart = searchPosition + colorNum * bytesPerColor
|
||
|
paletteEnd = paletteStart + bytesPerColor
|
||
|
# Parse color components as unsigned 16-bit big endian integers
|
||
|
color = struct.unpack('>' + 'H' * componentsPerColor, data[paletteStart:paletteEnd]);
|
||
|
palette[colorNum] = color;
|
||
|
|
||
|
# Save good candidates to a list
|
||
|
if isAmigaPalette(palette):
|
||
|
foundPalettes.append(tuple(palette));
|
||
|
|
||
|
# Close file
|
||
|
file.close()
|
||
|
|
||
|
# Remove duplicates from found palettes list
|
||
|
uniqueFoundPalettes = set(foundPalettes)
|
||
|
|
||
|
# Print out the found unique palettes
|
||
|
if len(uniqueFoundPalettes) > 0:
|
||
|
for palette in uniqueFoundPalettes:
|
||
|
printPalette(palette, sys.argv[2])
|
||
|
else:
|
||
|
print "Didn't find any Amiga AGI game palettes in file " + sys.argv[1]
|
||
|
print "Heuristic isn't perfect though, so caveat emptor"
|