Beispiel #1
0
def __get_x_centered(text_line: str, width_avail: int,
                     font: ImageFont.FreeTypeFont) -> int:
    """Get the X coordinate at which to draw a text line horizontally-centered.

    Parameters
    ----------
    text_line : str
        Text line to draw.
    width_avail : int
        Width available to draw (essentially the image's width).
    font : ImageFont.FreeTypeFont
        Font used to draw.

    Returns
    -------
    int
        The X coordinate at which to draw the text line horizontally-centered.
    """
    # https://stackoverflow.com/a/46220683/9263761
    ascent, descent = font.getmetrics()

    # Width needed to draw the line
    width_text = font.getmask(text_line).getbbox()[2] + font.font.getsize(
        text_line)[1][0]

    # Calculate the centered X coordinate
    x = (width_avail - width_text) // 2

    # Return the first Y coordinate and a list with the height of each line
    return x
Beispiel #2
0
def __calculate_username_width(user_name: str, user_pic: str,
                               font: ImageFont.FreeTypeFont) -> float:
    """Calculate the width of the username.
    The width is given as the width of the largest username line (in case it is broken up into multiple lines).

    user_name : str
        User name.
    user_pic : str
        Path to the profile picture.
    font : ImageFont.FreeTypeFont
        Font to be used for the username (header).

    Returns
    -------
    float
        Width needed to draw the username.
    """
    # Calculate username character limit per line based on the presence of\
    # the profile picture
    username_char_limit = 19 if user_pic != "" else 38
    # Break the text into multiple lines based on the character limit
    username_wrapped = wrap(user_name, username_char_limit)

    # The username's width is set by the largest username text line
    width_username = max([
        font.getmask(text_line).getbbox()[2] +
        font.font.getsize(text_line)[1][0] for text_line in username_wrapped
    ])

    return width_username
Beispiel #3
0
def __calculate_text_width(tweet_info: TweetInfo,
                           graphic_settings: GraphicSettings,
                           font: ImageFont.FreeTypeFont) -> float:
    """Calculate the width of the tweet content. 
    The width is given as the width of the largest tweet text line.

    Parameters
    ----------
    tweet_info : TweetInfo
        Dictionary with all the tweet's information.
    graphic_settings : GraphicSettings
        Dictionary with the graphic's settings.
    font : ImageFont.FreeTypeFont
        Font to be used for the text.

    Returns
    -------
    float
        Width needed to draw the text.
    """
    # Break the text into multiple lines based on the character limit
    text_wrapped = wrap(tweet_info["tweet_text"],
                        graphic_settings["wrap_limit"])

    # The text's width is set by the largest text line
    width_text = max([
        font.getmask(text_line).getbbox()[2] +
        font.font.getsize(text_line)[1][0] for text_line in text_wrapped
    ])

    return width_text
Beispiel #4
0
 def _get_metrics_map(
     text: str,
     font: ImageFont.FreeTypeFont,
     with_vertical_metrics: bool = True
 ) -> typing.Union[typing.Dict[str, typing.Tuple[int, int]], typing.Dict[
         str, typing.Tuple[int, int, int, int]], ]:
     return {
         char:
         (*size, size[1] - height, size[1]) if with_vertical_metrics and
         (height := font.getmask(char).size[1]) is not None else size
         for char in set(text) if (size := font.getsize(char))
     }
Beispiel #5
0
def __calculate_header_height(
    tweet_info: TweetInfo,
    graphic_settings: GraphicSettings,
    font: ImageFont.FreeTypeFont,
) -> float:
    """Calculate the header height: username, user tag and profile picture.

    Parameters
    ----------
    tweet_info : TweetInfo
        Dictionary with all the tweet's information.
    graphic_settings : GraphicSettings
        Dictionary with the graphic's settings.
    font : ImageFont.FreeTypeFont
        Font to be used for the header.

    Returns
    -------
    float
        Height needed for the header (pixels).
    """
    user_pic = tweet_info["user_pic"]
    height_margin = graphic_settings["margin_bottom"]
    profile_pic_size = graphic_settings["profile_pic_size"]
    user_name = tweet_info["user_name"]
    user_tag = tweet_info["user_tag"]

    # Calculate the height of the header's text: user name and user tag
    height_user_name = __calculate_username_height(user_name, user_pic,
                                                   height_margin, font)
    height_usertag = font.getmask(user_tag).getbbox()[3] + font.font.getsize(
        user_tag)[1][1]
    height_header_text = height_user_name + height_usertag + height_margin

    # If the header's text is taller than the profile picture, than that's\
    # the header height
    if (height_header_text + height_margin) > profile_pic_size[1]:
        height_header = height_header_text
    # Otherwise, the profile picture sets the header height
    else:
        height_header = profile_pic_size[1]

    return height_header
Beispiel #6
0
def __calculate_header_width(tweet_info: TweetInfo,
                             graphic_settings: GraphicSettings,
                             font_header: ImageFont.FreeTypeFont) -> float:
    """Calculate the width of the header.

    Parameters
    ----------
    tweet_info : TweetInfo
        Dictionary with all the tweet's information.
    graphic_settings : GraphicSettings
        Dictionary with the graphic's settings.
    font : ImageFont.FreeTypeFont
        Font to be used for the text.

    Returns
    -------
    float
        Width needed to draw the header (pixels).
    """
    # Calculate the header of the profile picture
    profile_pic_width = graphic_settings["profile_pic_size"][0]
    # Calculate the user name width
    username_width = __calculate_username_width(tweet_info["user_name"],
                                                tweet_info["user_pic"],
                                                font_header)
    # Calculate the user tag width
    user_tag = tweet_info["user_tag"]
    usertag_width = font_header.getmask(user_tag).getbbox()[2] +\
        font_header.font.getsize(user_tag)[1][0]

    # The width of the header's text is set by the largest of the user\
    # name and user tag
    if username_width > usertag_width:
        text_width = username_width
    else:
        text_width = usertag_width

    # The header width is given as the sum of the profile picture and\
    # the header text width
    width_header = profile_pic_width + \
        graphic_settings["margin_bottom"] + text_width

    return width_header
Beispiel #7
0
def __get_y_and_heights(text_wrapped: List[str], height_avail: int,
                        margin: float,
                        font: ImageFont.FreeTypeFont) -> Tuple[int, List[int]]:
    """Calculate the height needed to draw all text lines, vertically centered.
    Return the vertical coordinate to draw the first line at and a list of the heights for each line (margin included).

    Parameters
    ----------
    text_wrapped : List[str]
        Lines of text to draw.
    height_avail : int
        Height available to draw in (essentially the image's height).
    margin : float
        Vertical margin between text lines.
    font : ImageFont.FreeTypeFont
        Font used to draw.

    Returns
    -------
    Tuple[int, List[int]]
        The vertical coordinate of the first text line and a list with the heights of all lines.
    """
    # https://stackoverflow.com/a/46220683/9263761
    ascent, descent = font.getmetrics()

    # Calculate the height needed to draw each line of text
    height_lines = [
        font.getmask(text_line).getbbox()[3] +
        font.font.getsize(text_line)[1][1] + margin
        for text_line in text_wrapped
    ]
    # The last line doesn't have a bottom margin
    height_lines[-1] -= margin

    # Total height needed
    height_text = sum(height_lines)

    # Calculate the Y coordinate at which to draw the first line of text
    y = (height_avail - height_text) // 2

    # Return the first Y coordinate and a list with the height of each line
    return (y, height_lines)
Beispiel #8
0
def __calculate_text_height(
    tweet_info: TweetInfo,
    graphic_settings: GraphicSettings,
    font: ImageFont.FreeTypeFont,
) -> float:
    """Calculate the height needed to draw the tweet text.

    Parameters
    ----------
    tweet_info : TweetInfo
        Dictionary with all the tweet's information.
    graphic_settings : GraphicSettings
        Dictionary with the graphic's settings.
    font : ImageFont.FreeTypeFont
        Font to be used for the text.

    Returns
    -------
    float
        Height needed to draw the text (pixels).
    """
    # Wrap the tweet's text based on the line character limit
    text_wrapped = wrap(tweet_info["tweet_text"],
                        graphic_settings["wrap_limit"])
    height_margin = graphic_settings["margin_bottom"]

    # Total text height is the sum of height of each text line
    heights_text = [
        font.getmask(line).getbbox()[3] + font.font.getsize(line)[1][1] +
        height_margin for line in text_wrapped
    ]
    # Last line does not have bottom margin
    heights_text[-1] -= height_margin
    total_text_height = sum(heights_text)

    return total_text_height
Beispiel #9
0
def __calculate_username_height(user_name: str, user_pic: str,
                                height_margin: int,
                                font: ImageFont.FreeTypeFont) -> float:
    """Calculate the height of the username.
    The height is given as the sum of the heights each line of username (when the username exceeds the limit of characters per line).

    Parameters
    ----------
    user_name : str
        User name.
    user_pic : str
        Path to the profile picture.
    height_margin: int
        Vertical margin between lines of text.
    font : ImageFont.FreeTypeFont
        Font to be used for the username (header).

    Returns
    -------
    float
        Height needed to draw the username.
    """
    # Wrap the username into multiple lines as needed
    username_char_limit = 19 if user_pic != "" else 38
    user_name = wrap(user_name, username_char_limit)

    # Total username height is the sum of height of each username line
    heights_username = [
        font.getmask(line).getbbox()[3] + font.font.getsize(line)[1][1] +
        height_margin for line in user_name
    ]
    # Last line does not have bottom margin
    heights_username[-1] -= height_margin
    total_height_username = sum(heights_username)

    return total_height_username