def __init__(self, fontname: str) -> None: self.face = freetype.Face(fontname) height_base = int(BASE_FONT) self.face.set_char_size(height=PRESCALE * height_base * 64) dim = 1024 self.margin = 3 self.packer = SkyLine(dim, dim) load_results = loadCached() if load_results is not None: self.atlas, self.image = load_results else: self.atlas = {} self.image = numpy.zeros((dim, dim), dtype=numpy.uint8) old_set = frozenset(list(self.atlas.keys())) import string chars = string.digits + string.ascii_letters + string.punctuation + ' ' #self.addGlyphs(string.digits + string.letters + string.punctuation) for i in chars: self.getGlyph(i) new_set = frozenset(list(self.atlas.keys())) if old_set != new_set: saveCached(self.image, self.atlas)
def __init__(self, fontname): self.face = freetype.Face(fontname) pre = time.time() height_base = int(BASE_FONT) self.face.set_char_size(height=PRESCALE * height_base * 64) dim = 1024 self.margin = 3 self.packer = SkyLine(dim, dim) load_results = loadCached() if load_results is not None: self.atlas, self.image = load_results else: self.atlas = {} self.image = numpy.zeros((dim, dim), dtype=numpy.uint8) old_set = frozenset(list(self.atlas.keys())) import string chars = string.digits + string.ascii_letters + string.punctuation + ' ' #self.addGlyphs(string.digits + string.letters + string.punctuation) for i in chars: self.getGlyph(i) d = time.time() - pre new_set = frozenset(list(self.atlas.keys())) if old_set != new_set: saveCached(self.image, self.atlas)
class SDFTextAtlas(object): def __init__(self, fontname): self.face = freetype.Face(fontname) pre = time.time() height_base = int(BASE_FONT) self.face.set_char_size(height=PRESCALE * height_base * 64) dim = 1024 self.margin = 3 self.packer = SkyLine(dim, dim) load_results = loadCached() if load_results is not None: self.atlas, self.image = load_results else: self.atlas = {} self.image = numpy.zeros((dim, dim), dtype=numpy.uint8) old_set = frozenset(list(self.atlas.keys())) import string chars = string.digits + string.ascii_letters + string.punctuation + ' ' #self.addGlyphs(string.digits + string.letters + string.punctuation) for i in chars: self.getGlyph(i) d = time.time() - pre new_set = frozenset(list(self.atlas.keys())) if old_set != new_set: saveCached(self.image, self.atlas) def addGlyphs(self, multi): """ Add multiple glyphs at a time, packing by best-packing-score first Execution time is poor, and gains don't seem to be worth increased execution time The packer algorithm could almost certainly made smarter (specifically, the "find" algo) :param multi: :return: """ # Tuples of (char, ae, bitmap) glyphs = [] # Pre-build the bitmap info for char in multi: self.face.load_char(char) #bitmap = self.face.glyph.bitmap #w,h = bitmap.width, bitmap.rows #bl, bt = self.face.glyph.metrics.horiBearingX/64.0, self.face.glyph.metrics.horiBearingY/64.0 #bm = numpy.array(bitmap.buffer, dtype=numpy.ubyte).reshape(h,w) #ha = self.face.glyph.metrics.horiAdvance/64.0 ae = AtlasEntry.fromGlyph(self.face.glyph) #bm = numpy.array(self.face.glyph.bitmap.buffer, dtype=numpy.ubyte).reshape(ae.h, ae.w) w, h = self.face.glyph.bitmap.width, self.face.glyph.bitmap.rows bm = distance_transform_bitmap(self.face.glyph.bitmap, self.margin) #print char, bl, bt, self.face.glyph.metrics.horiBearingX/64.0, self.face.glyph.metrics.horiBearingY/64.0, ha/64.0, w #glyphs.append((char, w, h, bl, bt, ha, bm)) glyphs.append((char, ae, bm)) # Submit a list of rects to pack to the packer packlist = [(x[1].w + 2 * self.margin, x[1].h + 2 * self.margin) for x in glyphs] multiple = self.packer.pack_multiple(packlist) assert len(multiple) == len(packlist) # Now fill those rects fw = float(self.packer.width) fh = float(self.packer.height) for (char, ae, bm), (x0, y0) in zip(glyphs, multiple): x1, y1 = x0 + ae.w + 2 * self.margin, y0 + ae.h + 2 * self.margin ae.updatePos(self.packer.width, self.packer.height, x0, y0, x1, y1) self.atlas[char] = ae self.image[y0:y1, x0:x1] = bm def addGlyph(self, char): self.face.load_char(char) bitmap = self.face.glyph.bitmap w,h = bitmap.width, bitmap.rows ae = AtlasEntry.fromGlyph(self.face.glyph) pos = self.packer.pack(ae.w + 2 * self.margin, ae.h + 2 * self.margin) if pos is not None: x0, y0 = pos x1, y1 = x0 + ae.w, y0 + ae.h x1 += 2 * self.margin y1 += 2 * self.margin self.image[y0:y1, x0:x1] = distance_transform_bitmap(bitmap, self.margin) ae.updatePos(self.packer.width, self.packer.height, x0 , y0, x1, y1) self.atlas[char] = ae def getGlyph(self, char): try: return self.atlas[char] except KeyError: self.addGlyph(char) return self.atlas[char]
class SDFTextAtlas: atlas: Dict[str, AtlasEntry] image: 'npt.NDArray[numpy.uint8]' def __init__(self, fontname: str) -> None: self.face = freetype.Face(fontname) height_base = int(BASE_FONT) self.face.set_char_size(height=PRESCALE * height_base * 64) dim = 1024 self.margin = 3 self.packer = SkyLine(dim, dim) load_results = loadCached() if load_results is not None: self.atlas, self.image = load_results else: self.atlas = {} self.image = numpy.zeros((dim, dim), dtype=numpy.uint8) old_set = frozenset(list(self.atlas.keys())) import string chars = string.digits + string.ascii_letters + string.punctuation + ' ' #self.addGlyphs(string.digits + string.letters + string.punctuation) for i in chars: self.getGlyph(i) new_set = frozenset(list(self.atlas.keys())) if old_set != new_set: saveCached(self.image, self.atlas) def addGlyphs(self, multi: str) -> None: """ Add multiple glyphs at a time, packing by best-packing-score first Execution time is poor, and gains don't seem to be worth increased execution time The packer algorithm could almost certainly made smarter (specifically, the "find" algo) :param multi: :return: """ # Tuples of (char, ae, bitmap) glyphs = [] # Pre-build the bitmap info for char in multi: self.face.load_char(char) #bitmap = self.face.glyph.bitmap #w,h = bitmap.width, bitmap.rows #bl, bt = self.face.glyph.metrics.horiBearingX/64.0, self.face.glyph.metrics.horiBearingY/64.0 #bm = numpy.array(bitmap.buffer, dtype=numpy.ubyte).reshape(h,w) #ha = self.face.glyph.metrics.horiAdvance/64.0 ae = AtlasEntry.fromGlyph(self.face.glyph) #bm = numpy.array(self.face.glyph.bitmap.buffer, dtype=numpy.ubyte).reshape(ae.h, ae.w) w, h = self.face.glyph.bitmap.width, self.face.glyph.bitmap.rows bm = distance_transform_bitmap(self.face.glyph.bitmap, self.margin) #print char, bl, bt, self.face.glyph.metrics.horiBearingX/64.0, self.face.glyph.metrics.horiBearingY/64.0, ha/64.0, w #glyphs.append((char, w, h, bl, bt, ha, bm)) glyphs.append((char, ae, bm)) # Submit a list of rects to pack to the packer packlist = [(x[1].w + 2 * self.margin, x[1].h + 2 * self.margin) for x in glyphs] multiple = self.packer.pack_multiple(packlist) assert len(multiple) == len(packlist) for (char, ae, bm), (x0, y0) in zip(glyphs, multiple): x1, y1 = x0 + ae.w + 2 * self.margin, y0 + ae.h + 2 * self.margin ae.updatePos(self.packer.width, self.packer.height, x0, y0, x1, y1) self.atlas[char] = ae self.image[y0:y1, x0:x1] = bm def addGlyph(self, char: str) -> None: self.face.load_char(char) bitmap = self.face.glyph.bitmap w,h = bitmap.width, bitmap.rows ae = AtlasEntry.fromGlyph(self.face.glyph) pos = self.packer.pack(ae.w + 2 * self.margin, ae.h + 2 * self.margin) if pos is not None: x0, y0 = pos x1, y1 = x0 + ae.w, y0 + ae.h x1 += 2 * self.margin y1 += 2 * self.margin self.image[y0:y1, x0:x1] = distance_transform_bitmap(bitmap, self.margin) ae.updatePos(self.packer.width, self.packer.height, x0 , y0, x1, y1) self.atlas[char] = ae def getGlyph(self, char: str) -> AtlasEntry: v = self.atlas.get(char) if v is not None: return v self.addGlyph(char) return self.atlas[char]