From eaeed21773c3b807c41b75e6c9049ae4f6fe320e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 5 Dec 2020 15:55:09 -0600 Subject: [PATCH 1/3] label: Use new, optional 'ascent', 'descent' properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each time new glyphs have to be loaded from a font, it can take a long time (hundreds of milliseconds). In a parallel commit, 'ascent' and 'descent' properties will be added to BDF font objects, are essentially free to compute, and are in any case much quicker than entering load_glyphs. This may change the layout of text slightly. For instance, the height of the "M" glyph in GothamBlack-50.bdf is 35, but the Ascent of the font is 40 (and some characters, such as Å, are taller than the ascent at 45 pixels high) --- adafruit_display_text/label.py | 46 ++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/adafruit_display_text/label.py b/adafruit_display_text/label.py index 8ef4a32..705853e 100755 --- a/adafruit_display_text/label.py +++ b/adafruit_display_text/label.py @@ -147,28 +147,17 @@ def _create_background_box(self, lines, y_offset): y_box_offset = self._boundingbox[1] else: # draw a "loose" bounding box to include any ascenders/descenders. - - # check a few glyphs for maximum ascender and descender height - # Enhancement: it would be preferred to access the font "FONT_ASCENT" and - # "FONT_DESCENT" in the imported BDF file - glyphs = "M j'" # choose glyphs with highest ascender and lowest - # descender, will depend upon font used - ascender_max = descender_max = 0 - for char in glyphs: - this_glyph = self._font.get_glyph(ord(char)) - if this_glyph: - ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy) - descender_max = max(descender_max, -this_glyph.dy) + ascent, descent = self._get_ascent_descent() box_width = self._boundingbox[2] + self._padding_left + self._padding_right x_box_offset = -self._padding_left box_height = ( - (ascender_max + descender_max) + (ascent + descent) + int((lines - 1) * self.height * self._line_spacing) + self._padding_top + self._padding_bottom ) - y_box_offset = -ascender_max + y_offset - self._padding_top + y_box_offset = -ascent + y_offset - self._padding_top box_width = max(0, box_width) # remove any negative values box_height = max(0, box_height) # remove any negative values @@ -183,6 +172,25 @@ def _create_background_box(self, lines, y_offset): return tile_grid + def _get_ascent_descent(self): + if hasattr(self.font, "ascent"): + return self.font.ascent, self.font.descent + + # check a few glyphs for maximum ascender and descender height + glyphs = "M j'" # choose glyphs with highest ascender and lowest + self._font.load_glyphs(glyphs) + # descender, will depend upon font used + ascender_max = descender_max = 0 + for char in glyphs: + this_glyph = self._font.get_glyph(ord(char)) + if this_glyph: + ascender_max = max(ascender_max, this_glyph.height + this_glyph.dy) + descender_max = max(descender_max, -this_glyph.dy) + return ascender_max, descender_max + + def _get_ascent(self): + return self._get_ascent_descent()[0] + def _update_background_color(self, new_color): if new_color is None: @@ -196,7 +204,7 @@ def _update_background_color(self, new_color): self._background_color = new_color lines = self._text.rstrip("\n").count("\n") + 1 - y_offset = int((self._font.get_glyph(ord("M")).height) / 2) + y_offset = self._get_ascent() // 2 if not self._added_background_tilegrid: # no bitmap is in the self Group # add bitmap if text is present and bitmap sizes > 0 pixels @@ -248,13 +256,7 @@ def _update_text( i = 0 tilegrid_count = i - try: - self._font.load_glyphs(new_text + "M") - except AttributeError: - # ignore if font does not have load_glyphs - pass - - y_offset = int((self._font.get_glyph(ord("M")).height) / 2) + y_offset = self._get_ascent() // 2 right = top = bottom = 0 left = None From 28b3879f5bfb9c156b3aaf6186225b3775299704 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 7 Jan 2021 18:21:25 -0600 Subject: [PATCH 2/3] fallback for builtin font --- adafruit_display_text/label.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/adafruit_display_text/label.py b/adafruit_display_text/label.py index 705853e..5a19155 100755 --- a/adafruit_display_text/label.py +++ b/adafruit_display_text/label.py @@ -178,7 +178,11 @@ def _get_ascent_descent(self): # check a few glyphs for maximum ascender and descender height glyphs = "M j'" # choose glyphs with highest ascender and lowest - self._font.load_glyphs(glyphs) + try: + self._font.load_glyphs(glyphs) + except AttributeError: + # Builtin font doesn't have or need load_glyphs + pass # descender, will depend upon font used ascender_max = descender_max = 0 for char in glyphs: From bcd7c653ec1638a9771aec00f477750ce47731cd Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 7 Jan 2021 18:40:36 -0600 Subject: [PATCH 3/3] docstring fix for new sphinx --- adafruit_display_text/bitmap_label.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/adafruit_display_text/bitmap_label.py b/adafruit_display_text/bitmap_label.py index 348f5e4..a6caa4f 100755 --- a/adafruit_display_text/bitmap_label.py +++ b/adafruit_display_text/bitmap_label.py @@ -66,24 +66,24 @@ class Label(displayio.Group): Must include a capital M for measuring character size. :param str text: Text to display :param int max_glyphs: Unnecessary parameter (provided only for direct compability - with label.py) + with label.py) :param int color: Color of all text in RGB hex :param int background_color: Color of the background, use `None` for transparent :param double line_spacing: Line spacing of text to display :param boolean background_tight: Set `True` only if you want background box to tightly - surround text + surround text :param int padding_top: Additional pixels added to background bounding box at top :param int padding_bottom: Additional pixels added to background bounding box at bottom :param int padding_left: Additional pixels added to background bounding box at left :param int padding_right: Additional pixels added to background bounding box at right :param (double,double) anchor_point: Point that anchored_position moves relative to. - Tuple with decimal percentage of width and height. - (E.g. (0,0) is top left, (1.0, 0.5): is middle right.) + Tuple with decimal percentage of width and height. + (E.g. (0,0) is top left, (1.0, 0.5): is middle right.) :param (int,int) anchored_position: Position relative to the anchor_point. Tuple - containing x,y pixel coordinates. + containing x,y pixel coordinates. :param int scale: Integer value of the pixel scaling :param bool save_text: Set True to save the text string as a constant in the - label structure. Set False to reduce memory use. + label structure. Set False to reduce memory use. """ # pylint: disable=unused-argument, too-many-instance-attributes, too-many-locals, too-many-arguments