86 lines
3.0 KiB
Python
86 lines
3.0 KiB
Python
|
# Copyright 2018 Kiyoshi Aman
|
||
|
#
|
||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||
|
# purpose with or without fee is hereby granted, provided that the above
|
||
|
# copyright notice and this permission notice appear in all copies.
|
||
|
#
|
||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||
|
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||
|
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||
|
# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||
|
# IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
|
||
|
import json
|
||
|
|
||
|
from PyQt5.QtGui import QPixmap, QColor
|
||
|
|
||
|
class Font:
|
||
|
"""A simple class for managing Smeargle's font data."""
|
||
|
|
||
|
def __init__(self, filename):
|
||
|
"""Creates the font object.
|
||
|
|
||
|
Takes a filename pointing at the JSON metadata for a font.
|
||
|
"""
|
||
|
with open(filename, mode='rb') as f:
|
||
|
self._json = json.load(f)
|
||
|
|
||
|
self._image = QPixmap(self._json['filename'])
|
||
|
self._colors = []
|
||
|
|
||
|
if 'palette' in self._json:
|
||
|
for color in self._json['palette']:
|
||
|
if isinstance(color, (list, tuple)):
|
||
|
self._colors.append(QColor(*color))
|
||
|
elif isinstance(color, str):
|
||
|
red = int(color[0:2], 16)
|
||
|
green = int(color[2:4], 16)
|
||
|
blue = int(color[4:6], 16)
|
||
|
self._colors.append(QColor(red, green, blue).rgb())
|
||
|
else:
|
||
|
raise ValueError('unsupported color format: {}'.format(color))
|
||
|
else:
|
||
|
print("WARNING: No palette was provided with this font. Output palette order cannot be guaranteed.")
|
||
|
tile = self.index(self.table[' ']['index'])
|
||
|
self._colors = [tile.toImage().pixel(0, 0).rgb()]
|
||
|
|
||
|
def index(self, idx):
|
||
|
"""Given an index, returns the character at that location in the font.
|
||
|
|
||
|
Please note that this function assumes that even variable-width fonts
|
||
|
are stored in a fixed-width grid.
|
||
|
"""
|
||
|
tpr = int(self._image.width() / self.width)
|
||
|
row = int(idx / tpr)
|
||
|
column = idx % tpr
|
||
|
|
||
|
x = column * self.width
|
||
|
y = row * self.height
|
||
|
|
||
|
if (x > self._image.width()) or (y > self._image.height()):
|
||
|
raise ValueError('out of bounds: {}'.format(idx))
|
||
|
|
||
|
return self._image.copy(x, y, self.width, self.height).toImage()
|
||
|
|
||
|
@property
|
||
|
def palette(self):
|
||
|
return self._colors
|
||
|
|
||
|
@property
|
||
|
def width(self):
|
||
|
return self._json['width']
|
||
|
|
||
|
@property
|
||
|
def height(self):
|
||
|
return self._json['height']
|
||
|
|
||
|
@property
|
||
|
def table(self):
|
||
|
return self._json['map']
|
||
|
|
||
|
def length(self, text):
|
||
|
"""Calculate the pixel-wise length of the given string."""
|
||
|
return sum(self.table[x]['width'] for x in text)
|