Generate FIGlet fonts of NanoTiny

This commit is contained in:
Isaiah Odhner 2023-05-13 00:05:51 -04:00
parent a1365d1a32
commit 024120bc42
4 changed files with 1049 additions and 13 deletions

309
NanoTiny_v14_2x2.flf Normal file
View File

@ -0,0 +1,309 @@
flf2a$ 3 2 4 -1 2 0 0 0
NanoTiny 2x2
by Isaiah Odhner
@
@
@@
▜▛@
▗▖@
@@
▌▌@
@
@@
▙▙@
▙▙@
@@
▘▝@
▞▚@
@@
▘▞@
▞▗@
@@
▗ @
▜▘@
@@
▌ @
@
@@
▞ @
▚ @
@@
▚ @
▞ @
@@
▚▘@
▘▘@
@@
▟▖@
▝ @
@@
@
▟ @
@@
▄▖@
@
@@
@
▖ @
@@
▞@
▞ @
@@
▞▖@
▚▘@
@@
▜ @
▟▖@
@@
▀▖@
▟▖@
@@
▜▌@
▄▌@
@@
▌▌@
▀▛@
@@
█▘@
▄▘@
@@
▟▘@
▚▘@
@@
▀▌@
▐ @
@@
▐▚@
▚▌@
@@
▞▖@
▝▌@
@@
▘ @
▖ @
@@
▝ @
▟ @
@@
▞ @
▝ @
@@
▀▘@
▀▘@
@@
▚ @
▘ @
@@
▜▌@
▗ @
@@
▞▚@
▘█@
@@
▞▚@
▛▜@
@@
▛▖@
█▞@
@@
▞▘@
▚▖@
@@
▛▚@
▙▞@
@@
█▘@
▙▖@
@@
▛▘@
▛▘@
@@
▞▘@
▚▛@
@@
▌▐@
▛▜@
@@
▜▘@
▟▖@
@@
▝▛@
▚▘@
@@
▌▞@
▛▚@
@@
▌ @
▙▖@
@@
█▟@
▌▐@
@@
▙▐@
▌▜@
@@
▞▚@
▚▞@
@@
▛▚@
▛▘@
@@
▞▚@
▝▚@
@@
▛▚@
▛▚@
@@
▟▘@
▗▛@
@@
▜▘@
▐ @
@@
▌▐@
▚▞@
@@
▌▐@
▙▘@
@@
▌▐@
█▜@
@@
▌▌@
▞▖@
@@
▌▌@
▐ @
@@
▀▛@
▟▄@
@@
▛ @
▙ @
@@
▚ @
▚@
@@
▜ @
▟ @
@@
▞▖@
@
@@
@
▄▄@
@@
▚ @
@
@@
▗▖@
▚▌@
@@
▙ @
▙▘@
@@
▗▖@
▚▖@
@@
▗▌@
▚▌@
@@
▞▖@
▜▖@
@@
▞ @
▛ @
@@
▞▖@
▟▘@
@@
▙ @
▌▌@
@@
▘ @
▌ @
@@
▐ @
▞ @
@@
▌▖@
▛▖@
@@
▌ @
▚ @
@@
▄▖@
▛▐@
@@
▗ @
▌▌@
@@
▗ @
▚▘@
@@
▞▖@
▛ @
@@
▞▖@
▝▌@
@@
▗▖@
▌ @
@@
▞ @
▞ @
@@
▟▖@
▐▖@
@@
▖▗@
▚▞@
@@
▖▖@
▚▘@
@@
▖▗@
▚█@
@@
▖▖@
▞▖@
@@
▚▌@
▄▘@
@@
▀▌@
▟▖@
@@
▗▘@
▜▖@
@@
▌ @
▌ @
@@
▚ @
▟▘@
@@
▞▞@
@
@@
▗▄@
▐▛@
@@
██@
██@
@@
▞▙@
▌▟@
@@
▗▘@
▙▌@
@@
▖ @
@
@@
@
@
@@
▟▞@
▚▘@
@@

513
NanoTiny_v14_4x4.flf Normal file
View File

@ -0,0 +1,513 @@
flf2a$ 5 4 6 -1 2 0 0 0
NanoTiny 4x4
by Isaiah Odhner
@
@
@
@
@@
████@
██ @
@
██ @
@@
█ █ @
█ █ @
@
@
@@
█ █ @
████@
█ █ @
████@
@@
█ █@
@
██ @
█ █@
@@
█ █@
█ @
█ @
█ █@
@@
@
█ @
███ @
█ @
@@
█ @
█ @
@
@
@@
█ @
█ @
█ @
█ @
@@
█ @
█ @
█ @
█ @
@@
█ █ @
█ @
█ █ @
@
@@
█ @
███ @
█ @
@
@@
@
@
█ @
██ @
@@
@
███ @
@
@
@@
@
@
@
█ @
@@
█@
█ @
█ @
█ @
@@
█ @
█ █ @
█ █ @
█ @
@@
██ @
█ @
█ @
███ @
@@
██ @
█ @
█ @
███ @
@@
███ @
██ @
█ @
███ @
@@
█ █ @
█ █ @
████@
█ @
@@
███ @
██ @
█ @
██ @
@@
██ @
██ @
█ █ @
█ @
@@
███ @
█ @
█ @
█ @
@@
██ @
█ █@
█ █ @
██ @
@@
█ @
█ █ @
██ @
█ @
@@
█ @
@
@
█ @
@@
█ @
@
█ @
██ @
@@
█ @
█ @
█ @
@
@@
███ @
@
███ @
@
@@
█ @
█ @
█ @
@
@@
███ @
██ @
@
█ @
@@
██ @
█ █@
█ ██@
██@
@@
██ @
█ █@
████@
█ █@
@@
██ @
█ █ @
██ █@
███ @
@@
██ @
█ @
█ @
██ @
@@
███ @
█ █@
█ █@
███ @
@@
███ @
██ @
█ @
███ @
@@
███ @
█ @
███ @
█ @
@@
██ @
█ @
█ ██@
██ @
@@
█ █@
█ █@
████@
█ █@
@@
███ @
█ @
█ @
███ @
@@
███@
█ @
█ █ @
█ @
@@
█ █@
█ █ @
███ @
█ █@
@@
█ @
█ @
█ @
███ @
@@
██ █@
████@
█ █@
█ █@
@@
█ █@
██ █@
█ ██@
█ █@
@@
██ @
█ █@
█ █@
██ @
@@
███ @
█ █@
███ @
█ @
@@
██ @
█ █@
██ @
█@
@@
███ @
█ █@
███ @
█ █@
@@
██ @
██ @
██@
██ @
@@
███ @
█ @
█ @
█ @
@@
█ █@
█ █@
█ █@
██ @
@@
█ █@
█ █@
█ █ @
██ @
@@
█ █@
█ █@
████@
██ █@
@@
█ █ @
█ █ @
█ @
█ █ @
@@
█ █ @
█ █ @
█ @
█ @
@@
████@
█ @
█ @
████@
@@
██ @
█ @
█ @
██ @
@@
█ @
█ @
█ @
█@
@@
██ @
█ @
█ @
██ @
@@
█ @
█ █ @
@
@
@@
@
@
@
████@
@@
█ @
█ @
@
@
@@
@
██ @
█ █ @
██ @
@@
█ @
██ @
█ █ @
██ @
@@
@
██ @
█ @
██ @
@@
█ @
██ @
█ █ @
██ @
@@
█ @
█ █ @
██ @
██ @
@@
█ @
█ @
██ @
█ @
@@
█ @
█ █ @
██ @
██ @
@@
█ @
██ @
█ █ @
█ █ @
@@
█ @
@
█ @
█ @
@@
█ @
█ @
█ @
█ @
@@
█ @
█ █ @
██ @
█ █ @
@@
█ @
█ @
█ @
█ @
@@
@
███ @
██ █@
█ █@
@@
@
█ @
█ █ @
█ █ @
@@
@
█ @
█ █ @
█ @
@@
█ @
█ █ @
██ @
█ @
@@
█ @
█ █ @
██ @
█ @
@@
@
██ @
█ @
█ @
@@
█ @
█ @
█ @
█ @
@@
█ @
███ @
█ @
██ @
@@
@
█ █@
█ █@
██ @
@@
@
█ █ @
█ █ @
█ @
@@
@
█ █@
█ ██@
███@
@@
@
█ █ @
█ @
█ █ @
@@
█ █ @
██ @
█ @
██ @
@@
███ @
█ @
█ @
███ @
@@
█ @
█ @
██ @
██ @
@@
█ @
█ @
█ @
█ @
@@
█ @
█ @
██ @
██ @
@@
█ █@
█ █ @
@
@
@@
@
███@
███@
██ @
@@
████@
████@
████@
████@
@@
██ @
█ ██@
█ █@
█ ██@
@@
█ @
█ @
█ █ @
███ @
@@
@
█ @
@
@
@@
@
@
@
@
@@
█ █@
███ @
█ █ @
█ @
@@

View File

@ -61,6 +61,7 @@
"setuptools",
"Shft",
"smam",
"Smushing",
"stransi",
"STRINGTABLE",
"textconv",

View File

@ -22,6 +22,181 @@ block_char_lookup = {
0xF: '',
}
def spacePad(num: int) -> str:
return ' ' * num
def blankLines(num: int, width: int) -> str:
lines = [spacePad(width) for _ in range(num)]
return '\n'.join(lines)
class FIGletFontWriter:
charOrder: list[int] = [ii for ii in range(32, 127)] + [196, 214, 220, 228, 246, 252, 223]
def __init__(
self,
fontName: str,
figChars: dict[int, str],
height: int,
baseline: int,
maxLength: int,
commentLines: list[str],
rightToLeft: bool = False,
horizontalLayout: str = 'Universal Smushing',
verticalLayout: str = 'Universal Smushing',
codeTagCount: int = 0,
hardBlank: str = "$",
endMark: str = "@",
):
self.fontName = fontName
self.figChars: dict[int, str] = figChars
self.height = height
self.baseline = baseline
self.maxLength = maxLength
self.commentLines: list[str] = commentLines
self.rightToLeft = rightToLeft
self.codeTagCount = codeTagCount
self.hardBlank = hardBlank
self.endMark = endMark
self.horizontalLayout = horizontalLayout
self.verticalLayout = verticalLayout
self.hRule = [False] * 7
self.vRule = [False] * 7
self.caseInsensitive = False
def getOldLayoutValue(self) -> int:
val = 0
if self.horizontalLayout == 'Full':
return -1
elif self.horizontalLayout == 'Fitted':
return 0
elif self.horizontalLayout == 'Universal Smushing':
return 0
else:
val += 1 if self.hRule[1] else 0
val += 2 if self.hRule[2] else 0
val += 4 if self.hRule[3] else 0
val += 8 if self.hRule[4] else 0
val += 16 if self.hRule[5] else 0
val += 32 if self.hRule[6] else 0
return val
def getFullLayoutValue(self) -> int:
val = 0
# horizontal rules
if self.horizontalLayout == 'Full':
val += 0
elif self.horizontalLayout == 'Fitted':
val += 64
elif self.horizontalLayout == 'Universal Smushing':
val += 128
else:
val += 128
val += 1 if self.hRule[1] else 0
val += 2 if self.hRule[2] else 0
val += 4 if self.hRule[3] else 0
val += 8 if self.hRule[4] else 0
val += 16 if self.hRule[5] else 0
val += 32 if self.hRule[6] else 0
# vertical rules
if self.verticalLayout == 'Full':
val += 0
elif self.verticalLayout == 'Fitted':
val += 8192
elif self.verticalLayout == 'Universal Smushing':
val += 16384
else:
val += 16384
val += 256 if self.vRule[1] else 0
val += 512 if self.vRule[2] else 0
val += 1024 if self.vRule[3] else 0
val += 2048 if self.vRule[4] else 0
val += 4096 if self.vRule[5] else 0
return val
def generateFigFontHeader(self) -> str:
header: list[str] = []
baseline = self.baseline
if not baseline:
baseline = self.height
baseline = int(baseline)
if baseline <= 0 or baseline > self.height:
baseline = self.height
header.append('flf2a' + self.hardBlank)
header.append(str(self.height))
header.append(str(baseline))
header.append(str(self.maxLength))
header.append(str(self.getOldLayoutValue()))
header.append(str(len(self.commentLines)))
header.append("1" if self.rightToLeft else "0")
header.append(str(self.getFullLayoutValue()))
header.append(str(self.codeTagCount))
return ' '.join(header)
def fixFigChars(self):
height = 0
charWidth: dict[int, int] = {}
maxWidth = 0
# Fix case insensitivity
if self.caseInsensitive is True:
for ii in range(97, 123):
self.figChars[ii] = self.figChars[ii - 32]
# Calculate max height and ensure consistent width for each character
for idx in self.figChars:
if idx == -1:
continue # ignore comment header
figChar = self.figChars[idx].replace('\r\n', '\n').split('\n')
height = max(height, len(figChar))
charWidth[idx] = 0
for line in figChar:
charWidth[idx] = max(charWidth[idx], len(line))
for i in range(len(figChar)):
if len(figChar[i]) < charWidth[idx]:
figChar[i] += spacePad(charWidth[idx] - len(figChar[i]))
maxWidth = max(maxWidth, charWidth[idx])
self.figChars[idx] = '\n'.join(figChar)
# Fix any height issues
for idx in self.figChars:
if idx == -1:
continue # ignore comment header
figChar = self.figChars[idx].replace('\r\n', '\n').split('\n')
if len(figChar) < height:
self.figChars[idx] = '\n'.join(figChar) + '\n' + blankLines(height - len(figChar), charWidth[idx])
self.height = height
self.maxLength = maxWidth + 2
def createFigFileData(self) -> str:
output = ''
self.fixFigChars()
output = self.generateFigFontHeader() + '\n'
output += "\n".join(self.commentLines) + '\n'
for char in self.charOrder:
figChar = self.figChars.get(char)
if figChar is None:
raise Exception(f"Character {char} missing from figChars")
output += (self.endMark + '\n').join(figChar.split('\n'))
output += self.endMark + self.endMark + '\n'
return output
def extract_textures(image_path: str):
# Open the image
image = Image.open(image_path)
@ -38,8 +213,9 @@ def extract_textures(image_path: str):
# Create a new image to store the extracted textures
extracted_image = Image.new('RGB', (num_textures_x * texture_width, num_textures_y * texture_height))
extracted_text_half = ""
extracted_text_full = ""
half_size_meta_glyphs = {}
full_size_meta_glyphs = {}
# Extract textures
for row in range(num_textures_y):
@ -60,7 +236,12 @@ def extract_textures(image_path: str):
# Paste the texture onto the extracted image
extracted_image.paste(texture, (paste_x, paste_y))
# Extract as text
# Calculate the ordinal of the character
ordinal = row * num_textures_x + col
ordinal -= 2
# Extract as half-size FIGlet font
extracted_text_half = ""
for y in range(0, texture_height, 2):
for x in range(0, texture_width, 2):
# Get the four pixels that make up a character
@ -79,9 +260,11 @@ def extract_textures(image_path: str):
# Add a newline after each row
extracted_text_half += '\n'
# extracted_text += '(end of character ' + str(row * num_textures_x + col) + ')\n'
# Extract as text 2
half_size_meta_glyphs[ordinal] = extracted_text_half
# Extract as full-size FIGlet font
extracted_text_full = ""
for y in range(texture_height):
for x in range(texture_width):
# Get the pixel
@ -96,22 +279,52 @@ def extract_textures(image_path: str):
# Add a newline after each row
extracted_text_full += '\n'
full_size_meta_glyphs[ordinal] = extracted_text_full
half_size_font = FIGletFontWriter(
fontName="NanoTiny 2x2",
figChars=half_size_meta_glyphs,
height=2,
baseline=2,
maxLength=2,
commentLines=[
"NanoTiny 2x2",
"by Isaiah Odhner",
],
horizontalLayout="Full",
verticalLayout="Full",
)
full_size_font = FIGletFontWriter(
fontName="NanoTiny 4x4",
figChars=full_size_meta_glyphs,
height=4,
baseline=4,
maxLength=4,
commentLines=[
"NanoTiny 4x4",
"by Isaiah Odhner",
],
horizontalLayout="Full",
verticalLayout="Full",
)
return extracted_image, extracted_text_half, extracted_text_full
return extracted_image, half_size_font.createFigFileData(), full_size_font.createFigFileData()
base_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))
samples_folder = os.path.join(base_folder, 'samples')
image_path = os.path.join(samples_folder, 'NanoTiny_v14.png')
output_path = os.path.join(samples_folder, 'NanoTiny_v14_no_border.png')
half_size_text_output_path = os.path.join(base_folder, 'NanoTiny_v14_2x2.txt')
full_size_text_output_path = os.path.join(base_folder, 'NanoTiny_v14_4x4.txt')
half_size_flf_output_path = os.path.join(base_folder, 'NanoTiny_v14_2x2.flf')
full_size_flf_output_path = os.path.join(base_folder, 'NanoTiny_v14_4x4.flf')
extracted_image, extracted_text_half, extracted_text_full = extract_textures(image_path)
extracted_image.save(output_path)
print(f'Wrote extracted textures to {output_path}')
with open(full_size_text_output_path, 'w') as f:
with open(full_size_flf_output_path, 'w') as f:
f.write(extracted_text_full)
print(f'Wrote extracted textures to {full_size_text_output_path}')
with open(half_size_text_output_path, 'w') as f:
print(f'Wrote FIGlet font {full_size_flf_output_path}')
with open(half_size_flf_output_path, 'w') as f:
f.write(extracted_text_half)
print(f'Wrote extracted textures to {half_size_text_output_path}')
print(f'Wrote FIGlet font {half_size_flf_output_path}')