Source code for stimupy.components.texts

import numpy as np
from PIL import Image, ImageDraw, ImageFont

from stimupy.utils import pad_dict_to_visual_size, resolution

__all__ = [
    "text",
]


[docs]def text( text, visual_size=None, ppd=None, shape=None, intensity_text=0.0, intensity_background=0.5, fontsize=36, align="center", # direction="ltr", ): """Draw given text into a (numpy) image-array If no shape is provided / can be resolved, tightly fits the bounding box of the drawn text. Parameters ---------- text : str Text to draw visual_size : Sequence[Number, Number], Number, or None (default) visual size [height, width] of image, in degrees visual angle ppd : Sequence[Number, Number], Number, or None (default) pixels per degree [vertical, horizontal] shape : Sequence[Number, Number], Number, or None (default) shape [height, width] of image, in pixels intensity_text : float, optional intensity of text in range (0.0; 1.0), by default 0.0 intensity_background : float, optional intensity value of background in range (0.0; 1.0), by default 0.5 fontsize : int, optional font size, by default 36 align : "left", "center" (default), "right" alignment of text, by default "center" Returns ------- dict[str, Any] dict with the stimulus (key: "img"), mask with integer index for the text (key: "text_mask"), and additional keys containing stimulus parameters """ # Try to resolve resolution try: shape, visual_size, ppd = resolution.resolve(shape=shape, visual_size=visual_size, ppd=ppd) except resolution.TooManyUnknownsError: shape = resolution.validate_shape(shape) visual_size = resolution.validate_visual_size(visual_size) ppd = resolution.validate_ppd(ppd) # Get font font = ImageDraw.ImageDraw.font if not font: try: # Not all machines will have Arial installed... font = ImageFont.truetype( "arial.ttf", fontsize, encoding="unic", ) except OSError: font = ImageFont.load_default() # Determine dimensions of total text n_lines = len(text.split("\n")) max_length = 0 for line in text.split("\n"): max_length = max(int(font.getlength(line)), max_length) _, top, _, bottom = font.getbbox(text) text_width = max_length text_height = int(top + bottom) * n_lines text_shape = (text_height, text_width) # Instantiate grayscale image of correct shape (in pixels) img = Image.new("L", (text_width, text_height), 0) draw = ImageDraw.Draw(img) # Draw text into this image draw.text( (0, 0), text, fill=1, font=font, align=align, # direction=direction ) # Turn into mask-array mask = np.array(img) img = np.where(mask, intensity_text, intensity_background) # Package as dict stim = { "img": img, "text_mask": mask, "text_shape": text_shape, } # Resolve resolution if not shape or shape == (None, None): shape = text_shape shape, visual_size, ppd = resolution.resolve(shape=shape, visual_size=visual_size, ppd=ppd) # Pad stim = pad_dict_to_visual_size(stim, visual_size=visual_size, ppd=ppd, pad_value=0.5) # Output return stim
def overview(**kwargs): """Generate example stimuli from this module Returns ------- stims : dict dict with all stimuli containing individual stimulus dicts. """ default_params = { "visual_size": (10, 10), "ppd": 32, } default_params.update(kwargs) # fmt: off stimuli = { "text(), single line": text(text="hello world", **default_params), "text(), multiline": text(text="hello\nworld", **default_params) } # fmt: on return stimuli if __name__ == "__main__": from stimupy.utils import plot_stimuli stims = overview() plot_stimuli(stims, mask=False, save=None)