def __init__(self, name, size, bold=False, italic=False, dpi=None): super(FreeTypeFont, self).__init__() if dpi is None: dpi = 96 # as of pyglet 1.1; pyglet 1.0 had 72. # Check if font name/style matches a font loaded into memory by user lname = name and name.lower() or '' if (lname, bold, italic) in self._memory_fonts: font = self._memory_fonts[lname, bold, italic] self._set_face(font.face, size, dpi) return # Use fontconfig to match the font (or substitute a default). ft_library = ft_get_library() match = self.get_fontconfig_match(name, size, bold, italic) if not match: raise base.FontException('Could not match font "%s"' % name) f = FT_Face() if fontconfig.FcPatternGetFTFace(match, FC_FT_FACE, 0, byref(f)) != 0: value = FcValue() result = fontconfig.FcPatternGet(match, FC_FILE, 0, byref(value)) if result != 0: raise base.FontException('No filename or FT face for "%s"' % \ name) result = FT_New_Face(ft_library, value.u.s, 0, byref(f)) if result: raise base.FontException('Could not load "%s": %d' % \ (name, result)) fontconfig.FcPatternDestroy(match) self._set_face(f, size, dpi)
def render(self, text): face = self.font.face FT_Set_Char_Size(face, 0, self.font._face_size, self.font._dpi, self.font._dpi) glyph_index = fontconfig.FcFreeTypeCharIndex(byref(face), ord(text[0])) error = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER) if error != 0: raise base.FontException('Could not load glyph for "%c"' % text[0], error) glyph_slot = face.glyph.contents width = glyph_slot.bitmap.width height = glyph_slot.bitmap.rows baseline = height - glyph_slot.bitmap_top lsb = glyph_slot.bitmap_left advance = int(f26p6_to_float(glyph_slot.advance.x)) mode = glyph_slot.bitmap.pixel_mode pitch = glyph_slot.bitmap.pitch if mode == FT_PIXEL_MODE_MONO: # BCF fonts always render to 1 bit mono, regardless of render # flags. (freetype 2.3.5) bitmap_data = cast(glyph_slot.bitmap.buffer, POINTER(c_ubyte * (pitch * height))).contents data = (c_ubyte * (pitch * 8 * height))() data_i = 0 for byte in bitmap_data: # Data is MSB; left-most pixel in a byte has value 128. data[data_i + 0] = (byte & 0x80) and 255 or 0 data[data_i + 1] = (byte & 0x40) and 255 or 0 data[data_i + 2] = (byte & 0x20) and 255 or 0 data[data_i + 3] = (byte & 0x10) and 255 or 0 data[data_i + 4] = (byte & 0x08) and 255 or 0 data[data_i + 5] = (byte & 0x04) and 255 or 0 data[data_i + 6] = (byte & 0x02) and 255 or 0 data[data_i + 7] = (byte & 0x01) and 255 or 0 data_i += 8 pitch <<= 3 elif mode == FT_PIXEL_MODE_GRAY: # Usual case data = glyph_slot.bitmap.buffer else: raise base.FontException('Unsupported render mode for this glyph') # pitch should be negative, but much faster to just swap tex_coords img = image.ImageData(width, height, 'A', data, pitch) glyph = self.font.create_glyph(img) glyph.set_bearings(baseline, lsb, advance) t = list(glyph.tex_coords) glyph.tex_coords = t[9:12] + t[6:9] + t[3:6] + t[:3] return glyph
def _load_font_face_from_system(self): match = get_fontconfig().find_font(self.name, self.size, self.bold, self.italic) if not match: raise base.FontException('Could not match font "%s"' % self.name) font_face = match.face if not font_face: # Try to load from file directly if not match.file: raise base.FontException('No filename for "%s"' % self.name) font_face = self._load_font_face_from_file(match.file) return font_face
def __init__(self, data): self.buffer = (ctypes.c_byte * len(data))() ctypes.memmove(self.buffer, data, len(data)) ft_library = ft_get_library() self.face = FT_Face() r = FT_New_Memory_Face(ft_library, self.buffer, len(self.buffer), 0, self.face) if r != 0: raise base.FontException('Could not load font data') self.name = self.face.contents.family_name self.bold = self.face.contents.style_flags & FT_STYLE_FLAG_BOLD != 0 self.italic = self.face.contents.style_flags & FT_STYLE_FLAG_ITALIC != 0 # Replace Freetype's generic family name with TTF/OpenType specific # name if we can find one; there are some instances where Freetype # gets it wrong. if self.face.contents.face_flags & FT_FACE_FLAG_SFNT: name = FT_SfntName() for i in range(FT_Get_Sfnt_Name_Count(self.face)): result = FT_Get_Sfnt_Name(self.face, i, name) if result != 0: continue if not (name.platform_id == TT_PLATFORM_MICROSOFT and name.encoding_id == TT_MS_ID_UNICODE_CS): continue if name.name_id == TT_NAME_ID_FONT_FAMILY: string = string_at(name.string, name.string_len) self.name = string.decode('utf-16be', 'ignore')
def from_fontconfig(cls, match): if match.face is not None: FT_Reference_Face(match.face) return cls(match.face) else: if not match.file: raise base.FontException('No filename for "%s"' % match.name) return cls.from_file(match.file)
def _get_bitmap_data(self): if self._mode == FT_PIXEL_MODE_MONO: # BCF fonts always render to 1 bit mono, regardless of render # flags. (freetype 2.3.5) self._convert_mono_to_gray_bitmap() elif self._mode == FT_PIXEL_MODE_GRAY: # Usual case assert self._glyph_slot.bitmap.num_grays == 256 self._data = self._glyph_slot.bitmap.buffer else: raise base.FontException('Unsupported render mode for this glyph')
def __init__(self, data): self.buffer = (ctypes.c_byte * len(data))() ctypes.memmove(self.buffer, data, len(data)) ft_library = ft_get_library() self.face = FT_Face() r = FT_New_Memory_Face(ft_library, self.buffer, len(self.buffer), 0, self.face) if r != 0: raise base.FontException('Could not load font data') self.name = self.face.contents.family_name self.bold = self.face.contents.style_flags & FT_STYLE_FLAG_BOLD != 0 self.italic = self.face.contents.style_flags & FT_STYLE_FLAG_ITALIC != 0
def _load_font_face_from_system(self): match = get_fontconfig().find_font(self.name, self.size, self.bold, self.italic) if not match: raise base.FontException('Could not match font "%s"' % self.name) self.face = FreeTypeFace.from_fontconfig(match)