mirror of
https://github.com/cainan-c/TaikoPythonTools.git
synced 2024-12-18 01:55:53 +01:00
93 lines
4.1 KiB
Python
93 lines
4.1 KiB
Python
|
import os
|
||
|
import argparse
|
||
|
from PIL import Image, ImageFont, ImageDraw
|
||
|
import xml.etree.ElementTree as ET
|
||
|
|
||
|
def ttf_to_texture_and_xml(ttf_path, output_image_path, output_xml_path, font_size=48, image_width=4096, image_height=512, padding=1, extra_padding=1, y_padding=2, char_range='ascii'):
|
||
|
# Create a new image with transparent background
|
||
|
image = Image.new("RGBA", (image_width, image_height), (255, 255, 255, 0))
|
||
|
draw = ImageDraw.Draw(image)
|
||
|
|
||
|
# Load the font
|
||
|
font = ImageFont.truetype(ttf_path, font_size)
|
||
|
|
||
|
# Initialize XML structure
|
||
|
root_element = ET.Element("root")
|
||
|
font_element = ET.SubElement(root_element, "font", texWidth=str(image_width), texHeight=str(image_height),
|
||
|
fontSize=str(font_size), fontPoint=str(font_size), fixedHalfWidth="32", glyphNum="0")
|
||
|
|
||
|
# Draw each character and add to XML
|
||
|
x = padding + extra_padding
|
||
|
y = padding + extra_padding + y_padding
|
||
|
char_count = 0
|
||
|
tallest_char_height = 0 # To store the height of the tallest character
|
||
|
|
||
|
start = 0
|
||
|
end = 256 if char_range == 'ascii' else 65536
|
||
|
|
||
|
for i in range(start, end): # Unicode range
|
||
|
char = chr(i)
|
||
|
try:
|
||
|
bbox = draw.textbbox((0, 0), char, font=font)
|
||
|
except Exception:
|
||
|
continue
|
||
|
width = bbox[2] - bbox[0]
|
||
|
height = bbox[3] - bbox[1]
|
||
|
tallest_char_height = max(tallest_char_height, height) # Update tallest character height
|
||
|
|
||
|
# Check if the character fits in the current row, otherwise move to next row
|
||
|
if x + width + padding + extra_padding > image_width:
|
||
|
x = padding + extra_padding
|
||
|
y += tallest_char_height + 2 * (padding + extra_padding) # Use tallest char height
|
||
|
tallest_char_height = 0 # Reset tallest char height for new row
|
||
|
|
||
|
# Check if the character fits in the current column, otherwise skip
|
||
|
if y + tallest_char_height + padding + extra_padding > image_height:
|
||
|
break
|
||
|
|
||
|
draw.text((x, y), char, font=font, fill="white")
|
||
|
|
||
|
glyph_element = ET.SubElement(font_element, "glyph",
|
||
|
index=str(i),
|
||
|
type="1",
|
||
|
offsetU=str(x),
|
||
|
offsetV=str(y),
|
||
|
width=str(width),
|
||
|
height=str(tallest_char_height)) # Use tallest char height
|
||
|
x += width + 2 * (padding + extra_padding)
|
||
|
char_count += 1
|
||
|
|
||
|
# Update glyphNum in XML
|
||
|
font_element.set("glyphNum", str(char_count))
|
||
|
|
||
|
# Save the image
|
||
|
image.save(output_image_path)
|
||
|
|
||
|
# Save the XML with specific formatting
|
||
|
tree = ET.ElementTree(root_element)
|
||
|
tree.write(output_xml_path, encoding="utf-8", xml_declaration=True)
|
||
|
|
||
|
# Format the XML file to match the provided structure
|
||
|
import xml.dom.minidom
|
||
|
xml_str = xml.dom.minidom.parseString(ET.tostring(root_element)).toprettyxml(indent=" ")
|
||
|
with open(output_xml_path, "w", encoding="utf-8") as f:
|
||
|
f.write(xml_str.replace('<?xml version="1.0" ?>', '').strip())
|
||
|
|
||
|
def main():
|
||
|
parser = argparse.ArgumentParser(description="Convert TTF font to texture and XML")
|
||
|
parser.add_argument("ttf_path", type=str, help="Path to the TTF font file")
|
||
|
parser.add_argument("font_size", type=int, help="Font size")
|
||
|
parser.add_argument("image_width", type=int, help="Width of the texture image")
|
||
|
parser.add_argument("image_height", type=int, help="Height of the texture image")
|
||
|
parser.add_argument("char_range", choices=['ascii', 'unicode'], default='ascii', help="Character range")
|
||
|
parser.add_argument("output_name", type=str, help="Output name (e.g., en_64)")
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
output_image_path = os.path.join("out", f"{args.output_name}.png")
|
||
|
output_xml_path = os.path.join("out", f"{args.output_name}.xml")
|
||
|
|
||
|
ttf_to_texture_and_xml(args.ttf_path, output_image_path, output_xml_path, args.font_size, args.image_width, args.image_height, char_range=args.char_range)
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|