Use PEP 8 naming conventions for fontbuilder2
This commit is contained in:
parent
4a049c5f3a
commit
19e7d14506
@ -32,8 +32,8 @@ in particular, let us know and we can try to clarify it.
|
||||
|
||||
fontbuilder2
|
||||
MIT
|
||||
unspecified (FontLoader.py)
|
||||
IBM CPL (Packer.py)
|
||||
unspecified (font_loader.py)
|
||||
IBM CPL (packer.py)
|
||||
|
||||
i18n
|
||||
GPL version 2 (or later)
|
||||
|
@ -2,12 +2,12 @@
|
||||
# list of decimal codepoints (from U+0001 to U+FFFF) for which that font
|
||||
# contains some glyph data.
|
||||
|
||||
import FontLoader
|
||||
import font_loader
|
||||
|
||||
|
||||
def dump_font(ttf):
|
||||
(face, indexes) = FontLoader.create_cairo_font_face_for_file(
|
||||
f"../../../binaries/data/tools/fontbuilder/fonts/{ttf}", 0, FontLoader.FT_LOAD_DEFAULT
|
||||
(face, indexes) = font_loader.create_cairo_font_face_for_file(
|
||||
f"../../../binaries/data/tools/fontbuilder/fonts/{ttf}", 0, font_loader.FT_LOAD_DEFAULT
|
||||
)
|
||||
|
||||
mappings = [(c, indexes(chr(c))) for c in range(1, 65535)]
|
||||
|
@ -3,8 +3,8 @@
|
||||
import math
|
||||
|
||||
import cairo
|
||||
import FontLoader
|
||||
import Packer
|
||||
import font_loader
|
||||
import packer
|
||||
|
||||
|
||||
# Representation of a rendered glyph
|
||||
@ -50,8 +50,8 @@ class Glyph:
|
||||
self.w = bb[2] - bb[0]
|
||||
self.h = bb[3] - bb[1]
|
||||
|
||||
def pack(self, packer):
|
||||
self.pos = packer.Pack(self.w, self.h)
|
||||
def pack(self, packer_instance):
|
||||
self.pos = packer_instance.pack(self.w, self.h)
|
||||
|
||||
def render(self, ctx):
|
||||
if ctx.get_font_face() != self.face:
|
||||
@ -95,41 +95,41 @@ def setup_context(width, height, renderstyle):
|
||||
return ctx, surface
|
||||
|
||||
|
||||
def generate_font(outname, ttfNames, loadopts, size, renderstyle, dsizes):
|
||||
faceList = []
|
||||
indexList = []
|
||||
for i in range(len(ttfNames)):
|
||||
(face, indices) = FontLoader.create_cairo_font_face_for_file(
|
||||
f"../../../binaries/data/tools/fontbuilder/fonts/{ttfNames[i]}", 0, loadopts
|
||||
def generate_font(outname, ttf_names, loadopts, size, renderstyle, dsizes):
|
||||
face_list = []
|
||||
index_list = []
|
||||
for i in range(len(ttf_names)):
|
||||
(face, indices) = font_loader.create_cairo_font_face_for_file(
|
||||
f"../../../binaries/data/tools/fontbuilder/fonts/{ttf_names[i]}", 0, loadopts
|
||||
)
|
||||
faceList.append(face)
|
||||
if ttfNames[i] not in dsizes:
|
||||
dsizes[ttfNames[i]] = 0
|
||||
indexList.append(indices)
|
||||
face_list.append(face)
|
||||
if ttf_names[i] not in dsizes:
|
||||
dsizes[ttf_names[i]] = 0
|
||||
index_list.append(indices)
|
||||
|
||||
(ctx, _) = setup_context(1, 1, renderstyle)
|
||||
|
||||
# TODO: this gets the line height from the default font
|
||||
# while entire texts can be in the fallback font
|
||||
ctx.set_font_face(faceList[0])
|
||||
ctx.set_font_size(size + dsizes[ttfNames[0]])
|
||||
ctx.set_font_face(face_list[0])
|
||||
ctx.set_font_size(size + dsizes[ttf_names[0]])
|
||||
(_, _, linespacing, _, _) = ctx.font_extents()
|
||||
|
||||
# Estimate the 'average' height of text, for vertical center alignment
|
||||
charheight = round(ctx.glyph_extents([(indexList[0]("I"), 0.0, 0.0)])[3])
|
||||
charheight = round(ctx.glyph_extents([(index_list[0]("I"), 0.0, 0.0)])[3])
|
||||
|
||||
# Translate all the characters into glyphs
|
||||
# (This is inefficient if multiple characters have the same glyph)
|
||||
glyphs = []
|
||||
# for c in chars:
|
||||
for c in range(0x20, 0xFFFE):
|
||||
for i in range(len(indexList)):
|
||||
idx = indexList[i](chr(c))
|
||||
for i in range(len(index_list)):
|
||||
idx = index_list[i](chr(c))
|
||||
if c == 0xFFFD and idx == 0: # use "?" if the missing-glyph glyph is missing
|
||||
idx = indexList[i]("?")
|
||||
idx = index_list[i]("?")
|
||||
if idx:
|
||||
glyphs.append(
|
||||
Glyph(ctx, renderstyle, chr(c), idx, faceList[i], size + dsizes[ttfNames[i]])
|
||||
Glyph(ctx, renderstyle, chr(c), idx, face_list[i], size + dsizes[ttf_names[i]])
|
||||
)
|
||||
break
|
||||
|
||||
@ -149,10 +149,10 @@ def generate_font(outname, ttfNames, loadopts, size, renderstyle, dsizes):
|
||||
try:
|
||||
# Using the dump pacher usually creates bigger textures, but runs faster
|
||||
# In practice the size difference is so small it always ends up in the same size
|
||||
packer = Packer.DumbRectanglePacker(w, h)
|
||||
packer_instance = packer.DumbRectanglePacker(w, h)
|
||||
for g in glyphs:
|
||||
g.pack(packer)
|
||||
except Packer.OutOfSpaceError:
|
||||
g.pack(packer_instance)
|
||||
except packer.OutOfSpaceError:
|
||||
continue
|
||||
|
||||
ctx, surface = setup_context(w, h, renderstyle)
|
||||
@ -199,12 +199,12 @@ stroked2 = {"colour": True, "stroke": [((0, 0, 0, 1), 2.0)], "fill": [(1, 1, 1,
|
||||
stroked3 = {"colour": True, "stroke": [((0, 0, 0, 1), 2.5)], "fill": [(1, 1, 1, 1), (1, 1, 1, 1)]}
|
||||
|
||||
# For extra glyph support, add your preferred font to the font array
|
||||
Sans = (["LinBiolinum_Rah.ttf", "FreeSans.ttf"], FontLoader.FT_LOAD_DEFAULT)
|
||||
Sans_Bold = (["LinBiolinum_RBah.ttf", "FreeSansBold.ttf"], FontLoader.FT_LOAD_DEFAULT)
|
||||
Sans_Italic = (["LinBiolinum_RIah.ttf", "FreeSansOblique.ttf"], FontLoader.FT_LOAD_DEFAULT)
|
||||
SansMono = (["DejaVuSansMono.ttf", "FreeMono.ttf"], FontLoader.FT_LOAD_DEFAULT)
|
||||
Serif = (["texgyrepagella-regular.otf", "FreeSerif.ttf"], FontLoader.FT_LOAD_NO_HINTING)
|
||||
Serif_Bold = (["texgyrepagella-bold.otf", "FreeSerifBold.ttf"], FontLoader.FT_LOAD_NO_HINTING)
|
||||
Sans = (["LinBiolinum_Rah.ttf", "FreeSans.ttf"], font_loader.FT_LOAD_DEFAULT)
|
||||
Sans_Bold = (["LinBiolinum_RBah.ttf", "FreeSansBold.ttf"], font_loader.FT_LOAD_DEFAULT)
|
||||
Sans_Italic = (["LinBiolinum_RIah.ttf", "FreeSansOblique.ttf"], font_loader.FT_LOAD_DEFAULT)
|
||||
SansMono = (["DejaVuSansMono.ttf", "FreeMono.ttf"], font_loader.FT_LOAD_DEFAULT)
|
||||
Serif = (["texgyrepagella-regular.otf", "FreeSerif.ttf"], font_loader.FT_LOAD_NO_HINTING)
|
||||
Serif_Bold = (["texgyrepagella-bold.otf", "FreeSerifBold.ttf"], font_loader.FT_LOAD_NO_HINTING)
|
||||
|
||||
# Define the size differences used to render different fallback fonts
|
||||
# I.e. when adding a fallback font has smaller glyphs than the original, you can bump it
|
||||
|
@ -44,16 +44,16 @@ class RectanglePacker:
|
||||
http://www.csc.liv.ac.uk/~epa/surveyhtml.html
|
||||
"""
|
||||
|
||||
def __init__(self, packingAreaWidth, packingAreaHeight):
|
||||
def __init__(self, packing_area_width, packing_area_height):
|
||||
"""Initialize a new rectangle packer.
|
||||
|
||||
packingAreaWidth: Maximum width of the packing area
|
||||
packingAreaHeight: Maximum height of the packing area
|
||||
"""
|
||||
self.packingAreaWidth = packingAreaWidth
|
||||
self.packingAreaHeight = packingAreaHeight
|
||||
self.packingAreaWidth = packing_area_width
|
||||
self.packingAreaHeight = packing_area_height
|
||||
|
||||
def Pack(self, rectangleWidth, rectangleHeight):
|
||||
def pack(self, rectangle_width, rectangle_height):
|
||||
"""Allocate space for a rectangle in the packing area.
|
||||
|
||||
rectangleWidth: Width of the rectangle to allocate
|
||||
@ -61,14 +61,14 @@ class RectanglePacker:
|
||||
|
||||
Returns the location at which the rectangle has been placed
|
||||
"""
|
||||
point = self.TryPack(rectangleWidth, rectangleHeight)
|
||||
point = self.try_pack(rectangle_width, rectangle_height)
|
||||
|
||||
if not point:
|
||||
raise OutOfSpaceError("Rectangle does not fit in packing area")
|
||||
|
||||
return point
|
||||
|
||||
def TryPack(self, rectangleWidth, rectangleHeight):
|
||||
def try_pack(self, rectangle_width, rectangle_height):
|
||||
"""Try to allocate space for a rectangle in the packing area.
|
||||
|
||||
rectangleWidth: Width of the rectangle to allocate
|
||||
@ -81,23 +81,23 @@ class RectanglePacker:
|
||||
|
||||
|
||||
class DumbRectanglePacker(RectanglePacker):
|
||||
def __init__(self, packingAreaWidth, packingAreaHeight):
|
||||
RectanglePacker.__init__(self, packingAreaWidth, packingAreaHeight)
|
||||
def __init__(self, packing_area_width, packing_area_height):
|
||||
RectanglePacker.__init__(self, packing_area_width, packing_area_height)
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.rowh = 0
|
||||
|
||||
def TryPack(self, rectangleWidth, rectangleHeight):
|
||||
if self.x + rectangleWidth >= self.packingAreaWidth:
|
||||
def try_pack(self, rectangle_width, rectangle_height):
|
||||
if self.x + rectangle_width >= self.packingAreaWidth:
|
||||
self.x = 0
|
||||
self.y += self.rowh
|
||||
self.rowh = 0
|
||||
if self.y + rectangleHeight >= self.packingAreaHeight:
|
||||
if self.y + rectangle_height >= self.packingAreaHeight:
|
||||
return None
|
||||
|
||||
r = Point(self.x, self.y)
|
||||
self.x += rectangleWidth
|
||||
self.rowh = max(self.rowh, rectangleHeight)
|
||||
self.x += rectangle_width
|
||||
self.rowh = max(self.rowh, rectangle_height)
|
||||
return r
|
||||
|
||||
|
||||
@ -118,21 +118,21 @@ class CygonRectanglePacker(RectanglePacker):
|
||||
analyzed to find the position where the rectangle would achieve the lowest
|
||||
"""
|
||||
|
||||
def __init__(self, packingAreaWidth, packingAreaHeight):
|
||||
def __init__(self, packing_area_width, packing_area_height):
|
||||
"""Initialize a new rectangle packer.
|
||||
|
||||
packingAreaWidth: Maximum width of the packing area
|
||||
packingAreaHeight: Maximum height of the packing area
|
||||
"""
|
||||
RectanglePacker.__init__(self, packingAreaWidth, packingAreaHeight)
|
||||
RectanglePacker.__init__(self, packing_area_width, packing_area_height)
|
||||
|
||||
# Stores the height silhouette of the rectangles
|
||||
self.heightSlices = []
|
||||
self.height_slices = []
|
||||
|
||||
# At the beginning, the packing area is a single slice of height 0
|
||||
self.heightSlices.append(Point(0, 0))
|
||||
self.height_slices.append(Point(0, 0))
|
||||
|
||||
def TryPack(self, rectangleWidth, rectangleHeight):
|
||||
def try_pack(self, rectangle_width, rectangle_height):
|
||||
"""Try to allocate space for a rectangle in the packing area.
|
||||
|
||||
rectangleWidth: Width of the rectangle to allocate
|
||||
@ -145,20 +145,20 @@ class CygonRectanglePacker(RectanglePacker):
|
||||
|
||||
# If the rectangle is larger than the packing area in any dimension,
|
||||
# it will never fit!
|
||||
if rectangleWidth > self.packingAreaWidth or rectangleHeight > self.packingAreaHeight:
|
||||
if rectangle_width > self.packingAreaWidth or rectangle_height > self.packingAreaHeight:
|
||||
return None
|
||||
|
||||
# Determine the placement for the new rectangle
|
||||
placement = self.tryFindBestPlacement(rectangleWidth, rectangleHeight)
|
||||
placement = self.try_find_best_placement(rectangle_width, rectangle_height)
|
||||
|
||||
# If a place for the rectangle could be found, update the height slice
|
||||
# table to mark the region of the rectangle as being taken.
|
||||
if placement:
|
||||
self.integrateRectangle(placement.x, rectangleWidth, placement.y + rectangleHeight)
|
||||
self.integrate_rectangle(placement.x, rectangle_width, placement.y + rectangle_height)
|
||||
|
||||
return placement
|
||||
|
||||
def tryFindBestPlacement(self, rectangleWidth, rectangleHeight):
|
||||
def try_find_best_placement(self, rectangle_width, rectangle_height):
|
||||
"""Find the best position for a rectangle of the given dimensions.
|
||||
|
||||
rectangleWidth: Width of the rectangle to find a position for
|
||||
@ -169,70 +169,70 @@ class CygonRectanglePacker(RectanglePacker):
|
||||
"""
|
||||
# Slice index, vertical position and score of the best placement we
|
||||
# could find
|
||||
bestSliceIndex = -1 # Slice index where the best placement was found
|
||||
bestSliceY = 0 # Y position of the best placement found
|
||||
best_slice_index = -1 # Slice index where the best placement was found
|
||||
best_slice_y = 0 # Y position of the best placement found
|
||||
# lower == better!
|
||||
bestScore = self.packingAreaHeight
|
||||
best_score = self.packingAreaHeight
|
||||
|
||||
# This is the counter for the currently checked position. The search
|
||||
# works by skipping from slice to slice, determining the suitability
|
||||
# of the location for the placement of the rectangle.
|
||||
leftSliceIndex = 0
|
||||
left_slice_index = 0
|
||||
|
||||
# Determine the slice in which the right end of the rectangle is located
|
||||
rightSliceIndex = bisect_left(self.heightSlices, Point(rectangleWidth, 0))
|
||||
right_slice_index = bisect_left(self.height_slices, Point(rectangle_width, 0))
|
||||
|
||||
while rightSliceIndex <= len(self.heightSlices):
|
||||
while right_slice_index <= len(self.height_slices):
|
||||
# Determine the highest slice within the slices covered by the
|
||||
# rectangle at its current placement. We cannot put the rectangle
|
||||
# any lower than this without overlapping the other rectangles.
|
||||
highest = self.heightSlices[leftSliceIndex].y
|
||||
for index in range(leftSliceIndex + 1, rightSliceIndex):
|
||||
highest = max(self.heightSlices[index].y, highest)
|
||||
highest = self.height_slices[left_slice_index].y
|
||||
for index in range(left_slice_index + 1, right_slice_index):
|
||||
highest = max(self.height_slices[index].y, highest)
|
||||
|
||||
# Only process this position if it doesn't leave the packing area
|
||||
if highest + rectangleHeight < self.packingAreaHeight:
|
||||
if highest + rectangle_height < self.packingAreaHeight:
|
||||
score = highest
|
||||
|
||||
if score < bestScore:
|
||||
bestSliceIndex = leftSliceIndex
|
||||
bestSliceY = highest
|
||||
bestScore = score
|
||||
if score < best_score:
|
||||
best_slice_index = left_slice_index
|
||||
best_slice_y = highest
|
||||
best_score = score
|
||||
|
||||
# Advance the starting slice to the next slice start
|
||||
leftSliceIndex += 1
|
||||
if leftSliceIndex >= len(self.heightSlices):
|
||||
left_slice_index += 1
|
||||
if left_slice_index >= len(self.height_slices):
|
||||
break
|
||||
|
||||
# Advance the ending slice until we're on the proper slice again,
|
||||
# given the new starting position of the rectangle.
|
||||
rightRectangleEnd = self.heightSlices[leftSliceIndex].x + rectangleWidth
|
||||
while rightSliceIndex <= len(self.heightSlices):
|
||||
if rightSliceIndex == len(self.heightSlices):
|
||||
rightSliceStart = self.packingAreaWidth
|
||||
right_rectangle_end = self.height_slices[left_slice_index].x + rectangle_width
|
||||
while right_slice_index <= len(self.height_slices):
|
||||
if right_slice_index == len(self.height_slices):
|
||||
right_slice_start = self.packingAreaWidth
|
||||
else:
|
||||
rightSliceStart = self.heightSlices[rightSliceIndex].x
|
||||
right_slice_start = self.height_slices[right_slice_index].x
|
||||
|
||||
# Is this the slice we're looking for?
|
||||
if rightSliceStart > rightRectangleEnd:
|
||||
if right_slice_start > right_rectangle_end:
|
||||
break
|
||||
|
||||
rightSliceIndex += 1
|
||||
right_slice_index += 1
|
||||
|
||||
# If we crossed the end of the slice array, the rectangle's right
|
||||
# end has left the packing area, and thus, our search ends.
|
||||
if rightSliceIndex > len(self.heightSlices):
|
||||
if right_slice_index > len(self.height_slices):
|
||||
break
|
||||
|
||||
# Return the best placement we found for this rectangle. If the
|
||||
# rectangle didn't fit anywhere, the slice index will still have its
|
||||
# initialization value of -1 and we can report that no placement
|
||||
# could be found.
|
||||
if bestSliceIndex == -1:
|
||||
if best_slice_index == -1:
|
||||
return None
|
||||
return Point(self.heightSlices[bestSliceIndex].x, bestSliceY)
|
||||
return Point(self.height_slices[best_slice_index].x, best_slice_y)
|
||||
|
||||
def integrateRectangle(self, left, width, bottom):
|
||||
def integrate_rectangle(self, left, width, bottom):
|
||||
"""Integrate a new rectangle into the height slice table.
|
||||
|
||||
left: Position of the rectangle's left side
|
||||
@ -240,46 +240,46 @@ class CygonRectanglePacker(RectanglePacker):
|
||||
bottom: Position of the rectangle's lower side
|
||||
"""
|
||||
# Find the first slice that is touched by the rectangle
|
||||
startSlice = bisect_left(self.heightSlices, Point(left, 0))
|
||||
start_slice = bisect_left(self.height_slices, Point(left, 0))
|
||||
|
||||
# We scored a direct hit, so we can replace the slice we have hit
|
||||
firstSliceOriginalHeight = self.heightSlices[startSlice].y
|
||||
self.heightSlices[startSlice] = Point(left, bottom)
|
||||
first_slice_original_height = self.height_slices[start_slice].y
|
||||
self.height_slices[start_slice] = Point(left, bottom)
|
||||
|
||||
right = left + width
|
||||
startSlice += 1
|
||||
start_slice += 1
|
||||
|
||||
# Special case, the rectangle started on the last slice, so we cannot
|
||||
# use the start slice + 1 for the binary search and the possibly
|
||||
# already modified start slice height now only remains in our temporary
|
||||
# firstSliceOriginalHeight variable
|
||||
if startSlice >= len(self.heightSlices):
|
||||
# first_slice_original_height variable
|
||||
if start_slice >= len(self.height_slices):
|
||||
# If the slice ends within the last slice (usual case, unless it
|
||||
# has the exact same width the packing area has), add another slice
|
||||
# to return to the original height at the end of the rectangle.
|
||||
if right < self.packingAreaWidth:
|
||||
self.heightSlices.append(Point(right, firstSliceOriginalHeight))
|
||||
self.height_slices.append(Point(right, first_slice_original_height))
|
||||
else: # The rectangle doesn't start on the last slice
|
||||
endSlice = bisect_left(
|
||||
self.heightSlices, Point(right, 0), startSlice, len(self.heightSlices)
|
||||
end_slice = bisect_left(
|
||||
self.height_slices, Point(right, 0), start_slice, len(self.height_slices)
|
||||
)
|
||||
|
||||
# Another direct hit on the final slice's end?
|
||||
if endSlice < len(self.heightSlices) and not (
|
||||
Point(right, 0) < self.heightSlices[endSlice]
|
||||
if end_slice < len(self.height_slices) and not (
|
||||
Point(right, 0) < self.height_slices[end_slice]
|
||||
):
|
||||
del self.heightSlices[startSlice:endSlice]
|
||||
del self.height_slices[start_slice:end_slice]
|
||||
else: # No direct hit, rectangle ends inside another slice
|
||||
# Find out to which height we need to return at the right end of
|
||||
# the rectangle
|
||||
if endSlice == startSlice:
|
||||
returnHeight = firstSliceOriginalHeight
|
||||
if end_slice == start_slice:
|
||||
return_height = first_slice_original_height
|
||||
else:
|
||||
returnHeight = self.heightSlices[endSlice - 1].y
|
||||
return_height = self.height_slices[end_slice - 1].y
|
||||
|
||||
# Remove all slices covered by the rectangle and begin a new
|
||||
# slice at its end to return back to the height of the slice on
|
||||
# which the rectangle ends.
|
||||
del self.heightSlices[startSlice:endSlice]
|
||||
del self.height_slices[start_slice:end_slice]
|
||||
if right < self.packingAreaWidth:
|
||||
self.heightSlices.insert(startSlice, Point(right, returnHeight))
|
||||
self.height_slices.insert(start_slice, Point(right, return_height))
|
Loading…
Reference in New Issue
Block a user