Source code for fsleyes_widgets.utils.textbitmap

#
# textbitmap.py - A function which renders some text using matplotlib, and
# returns it as an RGBA bitmap.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides a single function, :func:`textBitmap`, which renders
some text off-screen using :mod:`matplotlib`, and returns it as an RGBA bitmap.
"""


[docs]def textBitmap(text, width=None, height=None, fontSize=None, fgColour=None, bgColour=None, alpha=1.0, fontFamily=None, dpi=96): """Draw some text using :mod:`matplotlib`. The rendered text is returned as a RGBA bitmap within a ``numpy.uint8`` array of size :math:`h \\times w \\times 4`, with the top-left pixel located at index ``[0, 0, :]``. At least one of the ``fontSize`` or the ``height`` arguments need to be specified - if one of these is provided, the other size options will be inferred, although the inference procedure does not support multi-line text. :arg text: Text to render. :arg width: Width in pixels. :arg height: Height in pixels. :arg fontSize: Font size in points. :arg fgColour: Foreground (text) colour - can be any colour specification that is accepted by :mod:`matplotlib`. :arg bgColour: Background colour - can be any colour specification that is accepted by :mod:`matplotlib`.. :arg alpha: Text transparency, in the range ``[0.0 - 1.0]``. :arg fontFamily: Font family, e.g. ``'monospace'`` or ``'sans-serif'``, defaults to matplotlib default. :arg dpi: Dots per inch, defaults to 96. :returns: ``numpy.uint8`` array of size :math:`h \\times w \\times 4` """ if text is None or text.strip() == '': raise ValueError('Some text must be specified.') if (fontSize is None) and (height is None): raise ValueError('One of fontSize or height must be specified.') # Imports are expensive import numpy as np import matplotlib.backends.backend_agg as mplagg import matplotlib.figure as mplfig # convert points to pixels or vice versa - # one point is 0,0138889 inches. Estimate # width from font size if not provided - # we will crop the result afterwards. crop = width is None if fontSize is None: fontSize = height / 0.0138889 / dpi if height is None: height = fontSize * 0.0138889 * dpi if width is None: width = max(fontSize, fontSize * len(text)) if fgColour is None: fgColour = '#000000' fig = mplfig.Figure(figsize=(width / dpi, height / dpi), dpi=dpi) canvas = mplagg.FigureCanvasAgg(fig) ax = fig.add_axes([0, 0, 1, 1]) ax.axis('off') if bgColour is not None: fig.patch.set_facecolor(bgColour) else: fig.patch.set_alpha(0) ax.set_xticks([]) ax.set_yticks([]) textobj = ax.text(0.5, 0.5, text, fontsize=fontSize, verticalalignment='center', horizontalalignment='center', transform=ax.transAxes, color=fgColour, alpha=alpha, fontfamily=fontFamily) # if a width wasn't specified, we auto- # fit the bitmap to the rendered text if crop: bbox = textobj.get_window_extent(renderer=canvas.get_renderer()) if bbox.width < width: fig.set_size_inches((bbox.width / dpi, height / dpi)) # no padding fig.subplots_adjust( bottom=0, top=1, left=0, right=1) canvas.draw() # get the bitmap data and reshape # and transpose it to (H, W, [RGBA]) ncols, nrows = canvas.get_width_height() bitmap = canvas.tostring_argb() bitmap = np.frombuffer(bitmap, dtype=np.uint8) bitmap = bitmap.reshape(nrows, ncols, 4) rgb = bitmap[:, :, 1:] a = bitmap[:, :, 0] bitmap = np.dstack((rgb, a)) return bitmap