Beispiel #1
0
    def _draw_date_box(self, draw: ImageDraw.Draw, top_left_corner: Tuple[int, int], width: int, date: datetime) -> int:
        """
        Draws a date/time clock onto the canvas at the given position.

        Args:
            draw: The ImageDraw instance to draw on the desired canvas.
            top_left_corner: Where to start the box.
            width: The fixed horizontal dimension of the box.
            date: The date/time to display on the clock.

        Returns:
            The bottom y coordinate of the box, so that further elements may be drawn after it
        """
        time_str = format_time(date, 'HH:mm', locale='pt_BR')
        time_font = self.fonts['huge']
        time_font_height = time_font.getsize('X')[1]

        date_str = format_date(date, "EEEE\ndd 'de' MMM 'de' yyyy", locale='pt_BR').capitalize()
        date_font = self.fonts['large']
        date_font_height = date_font.getsize('X')[1]

        margin = 20 * self.scaler_value

        bottom_y = int(top_left_corner[1] + time_font_height + date_font_height * 2 + margin * 4)
        draw.rectangle(
            (
                top_left_corner[0],
                top_left_corner[1],
                top_left_corner[0] + width,
                bottom_y
            ),
            fill=self.colors['date_box_background']
        )

        time_y = top_left_corner[1] + margin
        draw.text(
            (top_left_corner[0] + margin, time_y),
            time_str,
            fill=self.colors['date_box_text'],
            font=time_font,
        )

        draw.multiline_text(
            (top_left_corner[0] + margin, time_y + time_font_height + margin),
            date_str,
            fill=self.colors['date_box_text'],
            font=date_font
        )

        return bottom_y
Beispiel #2
0
def make_text(
        text: str,
        box=(0, 0),
        font_path='',
        init_font_size=76,
        color=(0, 0, 0, 255),
        stroke=None,  # stroke can be a color tuple
        align='left',
        emojis={},
        instance=''):
    if contains_emojis(text, emojis):
        # fancy rendering enabled
        # redirect to fit_text_with_emojis_in_box()
        return make_emoji_text(text,
                               emojis=emojis,
                               instance=instance,
                               box=box,
                               font_path=font_path,
                               color=color,
                               stroke=stroke,
                               align=align)

    canvas = Image.new('RGBA', box, color=(255, 255, 255, 0))
    draw = Draw(canvas)
    textsize = (box[0] + 1, box[1] + 1)
    font_size = init_font_size  # max font size is 72; decrease by 4 until fit
    while textsize[0] > box[0] or textsize[1] > box[1]:  # doesn't fit
        if 0 < font_size <= 16:
            font_size -= 1
        elif 16 < font_size < 32:
            font_size -= 2
        elif font_size >= 32:
            font_size -= 4
        else:
            break
        font = truetype(font_path, size=font_size)
        # try to fit in the horizontal boundary
        wrapped = wrap_text(text, box[0], font)
        textsize = draw.multiline_textsize(wrapped, font=font)
        # when wrapped text fits in box, loop will exit, and font is remembered

    draw.multiline_text(
        (0, 0),
        wrapped,
        fill=color if stroke is None else WHITE,
        font=font,
        stroke_fill=stroke,
        stroke_width=(max(font_size // 20, 2) if stroke is not None else 0),
        align=align)
    return canvas
Beispiel #3
0
def _draw_text(draw: ImageDraw.Draw, words: Sequence[str],
               font: ImageFont.ImageFont, fill: Sequence[int],
               vertical_offset: float, picture_width: int) -> None:
    """
    Нанесение текста на изображение
    """
    y = vertical_offset
    for index, word in enumerate(words):
        word_width, word_height = _get_word_size_in_px(font, word)
        x = (picture_width - word_width[0]) / 2

        draw.multiline_text((x, y),
                            text=word,
                            align='center',
                            fill=fill,
                            font=font)
        y += word_width[1] + max(abs(word_height[1]), int(word_width[1] / 5))
Beispiel #4
0
def draw_text_with_outline(
    draw: ImageDraw.Draw,
    xy: t.Tuple[int, int],
    text: str,
    font,
    color: t.Tuple[int, int, int],
    background_color: t.Tuple[int, int, int],
) -> None:
    """
    Draw outlined text

    :param draw: target
    :param xy: location
    :param text: content
    :param font: font
    :param color: text color
    :param background_color: outline color
    :return: None
    """
    _xy = np.asarray(xy)
    offset_range = (-1, 0, 1)

    for offset in ((x, y) for x in offset_range for y in offset_range):
        draw.multiline_text(
            xy=_xy + np.asarray(offset),
            text=text,
            font=font,
            fill=background_color,
            align='center',
        )

    draw.multiline_text(
        xy=_xy,
        text=text,
        font=font,
        fill=color,
        align='center',
    )
Beispiel #5
0
    def _draw_berthed_ship_box(
        self,
        draw: ImageDraw.Draw,
        top_left_corner: Tuple[int, int],
        width: int,
        ship: pd.Series
    ) -> int:
        """
        Draws a berthed ship's information on a box.

        Args:
            draw: The ImageDraw instance to draw on the desired canvas.
            top_left_corner: Where to start the box.
            width: The fixed horizontal dimension of the box.
            ship: Source of the information for the ship, obtained from the LogKeeper.

        Returns:
            The bottom y coordinate of the box, so that further elements may be drawn after it
        """
        berco = get_ship_berth_number(ship)
        # Alternate colors for different designated berthing numbers.
        if berco is None or berco % 2 == 0:
            background_color = self.colors['berthed_ship_box_background_even']
        else:
            background_color = self.colors['berthed_ship_box_background_odd']

        name_str = ship['Navio']
        name_font = self.fonts['large']
        # Resize the font until the name fits within the specified width.
        while (name_font.size > 12) and (name_font.getsize(name_str)[0] > (width - 30)):
            name_font = self._load_font(self.font_path, max(1, name_font.size - 1))
        name_font_height = name_font.getsize('X')[1]

        berco_str = 'Berço ' + str(berco)
        berco_font = self.fonts['medium']
        berco_font_height = berco_font.getsize('X')[1]

        margin = (20 * self.scaler_value)

        bottom_y = int(top_left_corner[1] + name_font_height + berco_font_height + margin * 3)

        draw.rectangle(
            (
                top_left_corner[0],
                top_left_corner[1],
                top_left_corner[0] + width,
                bottom_y
            ),
            fill=background_color
        )

        draw.multiline_text(
            (top_left_corner[0] + margin, top_left_corner[1] + margin),
            name_str,
            fill=self.colors['berthed_ship_box_text'],
            font=name_font
        )

        if berco is not None:
            draw.multiline_text(
                (top_left_corner[0] + margin, top_left_corner[1] + name_font_height + margin * 2),
                berco_str,
                fill=self.colors['berthed_ship_box_text'],
                font=berco_font
            )

        return bottom_y