-
-
Save Epicpkmn11/6869a7862e83c76a630337a1ccc44758 to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env python3 | |
from argparse import ArgumentParser | |
import struct | |
from os import path | |
def fontriff(input, width, height, mapPath=None): | |
"""Creates an FRF font for GodMode9 from a PBM image""" | |
if width < 1 or width > 8: | |
raise ValueError("Font width is invalid (Maximum 8, minimum 1, current %d)" % width) | |
if height < 1 or height > 10: | |
raise ValueError("Font height is invalid (Maximum 10, minimum 1, current %d)" % height) | |
# Read PBM | |
with open(input, "rb") as f: | |
pbm = f.read() | |
split = pbm.split(b"\n") | |
if split[0] != b"P4": | |
raise ValueError("Input is not a PBM file") | |
# Skip comments | |
for i in range(1, len(split)): | |
if split[i][0] != ord("#"): | |
imgWidth = int(split[i].split()[0]) | |
imgHeight = int(split[i].split()[1]) | |
imgData = b"\n".join(split[i + 1:]) | |
break | |
count = imgWidth * imgHeight // width // height | |
columns = imgWidth // width | |
fontMap = [] | |
# Prepare map | |
if not mapPath: | |
# If mapping file not specified, check if one with the same name as | |
# the pbm exists and use it if found. | |
inputTxt = input.replace(".pbm", ".txt") | |
if path.exists(inputTxt): | |
mapPath = inputTxt | |
print("Info: Using %s for font mappings" % mapPath) | |
if mapPath: | |
with open(mapPath, "r") as fontMapFile: | |
fontMapTemp = fontMapFile.read().split() | |
if len(fontMapTemp) > count: | |
raise ValueError("Font map has more items than possible in image (%d items in map)" % count) | |
elif len(fontMapTemp) < count: | |
count = len(fontMapTemp) | |
print("Info: Font map has fewer items than possible in image, only using first %d" % count) | |
for item in fontMapTemp: | |
fontMap.append({"mapping": int(item, 16)}) | |
else: | |
print("Warning: Font mapping not found, mapping directly to Unicode codepoints") | |
for i in range(count): | |
fontMap.append({"mapping": i}) | |
# Add unsorted tiles to map | |
for c in range(count): | |
fontMap[c]["bitmap"] = bytearray() | |
for row in range(height): | |
ofs = ((c // columns * height + row) * (imgWidth + ((8 - (imgWidth % 8)) if imgWidth % 8 != 0 else 0)) // 8) | |
bp0 = ((c % columns) * width) >> 3 | |
bm0 = ((c % columns) * width) % 8 | |
byte = (((imgData[ofs + bp0] << bm0) | ((imgData[ofs + bp0 + 1] >> (8 - bm0)) if ofs + bp0 + 1 < len(imgData) else 0)) & (0xFF << (8 - width))) & 0xFF | |
fontMap[c]["bitmap"] += struct.pack("B", byte) | |
# Remove duplicates | |
fontMap = list({x["mapping"]: x for x in fontMap}.values()) | |
if len(fontMap) != count: | |
print("Info: %d duplicate mappings were removed" % (count - len(fontMap))) | |
count = len(fontMap) | |
# Sort map | |
fontMap = sorted(fontMap, key=lambda x: x["mapping"]) | |
# Create file | |
output = bytearray() | |
output += b"RIFF\0\0\0\0" # The size is filled at the end | |
# Metadata | |
output += b"META" | |
output += struct.pack("<LBBH", 4, width, height, count) | |
# Character data | |
output += b"CDAT" | |
sectionSize = count * height | |
padding = 4 - sectionSize % 4 if sectionSize % 4 else 0 | |
output += struct.pack("<L", sectionSize + padding) | |
for item in fontMap: | |
output += item["bitmap"] | |
output += b"\0" * padding | |
# Character map | |
output += b"CMAP" | |
sectionSize = count * 2 | |
padding = 4 - sectionSize % 4 if sectionSize % 4 else 0 | |
output += struct.pack("<L", sectionSize + padding) | |
for item in fontMap: | |
output += struct.pack("<H", item["mapping"]) | |
output += b"\0" * padding | |
# Set final size | |
outSize = len(output) | |
struct.pack_into("<L", output, 4, outSize - 8) | |
return output | |
def main(): | |
parser = ArgumentParser(description=fontriff.__doc__) | |
parser.add_argument("input", type=str, help="PBM image to convert from") | |
parser.add_argument("output", type=str, help="out.to output to") | |
parser.add_argument("width", type=int, help="character width") | |
parser.add_argument("height", type=int, help="character height") | |
parser.add_argument("-m", "--map", metavar="map.txt", type=str, help="character map (whitespace separated Unicode codepoints)") | |
args = parser.parse_args() | |
output = fontriff(args.input, args.width, args.height, args.map) | |
with open(args.output, "wb") as out: | |
out.write(output) | |
print("Info: %s created." % args.output) | |
if __name__ == "__main__": | |
main() |
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
#!/usr/bin/env python3 | |
from argparse import ArgumentParser | |
import json | |
import struct | |
def transriff(input, version): | |
"""Creates a TRF translation for GodMode9 from a translation JSON""" | |
# Read JSON | |
with open(input, "r") as f: | |
strings = json.load(f) | |
if "GM9_LANGUAGE" not in strings: | |
raise ValueError("Input is not a valid JSON file") | |
# Encode strings to UTF-8 bytestrings | |
strings = {item: strings[item].encode("utf-8") + b"\0" for item in strings} | |
# Remove language name from strings | |
lang_name = strings["GM9_LANGUAGE"] | |
del strings["GM9_LANGUAGE"] | |
# Create file | |
output = bytearray() | |
output += b"RIFF\0\0\0\0" # The size is filled at the end | |
# Metadata | |
output += b"META" | |
output += struct.pack("<LLL32s", 40, version, len(strings), lang_name) | |
# String data | |
output += b"SDAT" | |
sectionSize = sum(len(strings[item]) for item in strings) | |
padding = 4 - sectionSize % 4 if sectionSize % 4 else 0 | |
output += struct.pack("<L", sectionSize + padding) | |
output += b"".join(strings.values()) | |
output += b"\0" * padding | |
# String map | |
output += b"SMAP" | |
sectionSize = len(strings) * 2 | |
padding = 4 - sectionSize % 4 if sectionSize % 4 else 0 | |
output += struct.pack("<L", sectionSize + padding) | |
offset = 0 | |
for string in strings.values(): | |
output += struct.pack("<H", offset) | |
offset += len(string) | |
output += b"\0" * padding | |
# Set final size | |
outSize = len(output) | |
struct.pack_into("<L", output, 4, outSize - 8) | |
return output | |
def main(): | |
parser = ArgumentParser(description=transriff.__doc__) | |
parser.add_argument("input", type=str, help="JSON to convert from") | |
parser.add_argument("output", type=str, help="TRF to output to") | |
parser.add_argument("version", type=int, help="translation version, from language.inl") | |
args = parser.parse_args() | |
output = transriff(args.input, args.version) | |
with open(args.output, "wb") as out: | |
out.write(output) | |
print("Info: %s created." % args.output) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment