Esempio n. 1
0
def linebreakString(draw: ImageDraw, text: str, lines = 2, maxWidth = 370, font = rbtv_config.fontSmall):
    splited = text.split(' ')
    
    result = ''
    test = ''
    twoline = False

    line = 1
    i = 0
    w, h = draw.textsize(result, font = font)
    while line < lines:
        while w < maxWidth and i < len(splited):
            test += str(splited[i]) + ' '
            w, h = draw.textsize(test, font = font)
            if w < maxWidth:
                result += str(splited[i]) + ' '
                i += 1
        result += '\n'
        test = ''
        line += 1
        w, h = draw.textsize(test, font = font)

    while i < len(splited):
        twoline = True
        result += str(splited[i]) + ' '
        i += 1
    
    return twoline, result
Esempio n. 2
0
    def _render_departure_font(
        self,
        draw: ImageDraw,
        y: int,
        departure: departure.Departure,
        font: FreeTypeFont,
    ) -> int:
        _, dst_height = draw.textsize(
            "{} {}".format(departure.line_number, departure.destination), font=font
        )
        time_width, time_height = draw.textsize(departure.display_time, font=font)

        dst_y = y + 5
        dst_x = 0  # set border

        time_x = self._d_width - time_width - 2
        time_y = y + 5

        draw.text(
            (dst_x, dst_y),
            "{} {}".format(departure.line_number, departure.destination),
            fill="white",
            font=font,
        )

        draw.text((time_x, time_y), departure.display_time, fill="white", font=font)

        return dst_height
Esempio n. 3
0
def renderDestinationRow(draw: ImageDraw, width, height):
    status = "On time"
    departureTime = data["departures"]["all"][0]["aimed_departure_time"]
    timeWidth, _ = draw.textsize(departureTime, font)
    statusWidth, _ = draw.textsize(status, font)

    draw.text((0, 0), departureTime, fill="yellow", font=font)
    destination = data["departures"]["all"][0]["destination_name"]
    draw.text((timeWidth + 5, 0), destination, fill="yellow", font=font)
    draw.text((width - statusWidth, 0), status, fill="yellow", font=font)
Esempio n. 4
0
def truncateString(draw: ImageDraw, text: str, maxWidth = 420, font = rbtv_config.fontSmall):
    w, h = draw.textsize(text, font = font)

    wasModified = False
    while w > maxWidth:
        text = text[:-1]
        w, h = draw.textsize(text, font = font)
        wasModified = True
    
    if wasModified:
        text = text + " ..."
    
    return text
Esempio n. 5
0
 def draw_captions(self, canvas: ImageDraw, captions, settings):
     for setting in settings[1:]:
         caption = captions.pop(0)
         lines = wrap(caption, setting.get("wrap", settings[0].get("wrap", 20)))
         real_line_height = setting.get("font_size", settings[0].get("font_size", self.FONT_SIZE)) + 5
         lines_count = len(lines)
         for line_index, line in enumerate(lines):
             x, y = setting.get("position")
             font = ImageFont.truetype("resources/fonts/lato.ttf", setting.get("font_size", settings[0].get("font_size", self.FONT_SIZE)))
             line_width, line_height = canvas.textsize(line, font=font)
             if setting.get("center", settings[0].get("center", True)):
                 x -= line_width / 2
             if setting.get("center_vertical", settings[0].get("center_vertical", False)):
                 y -= (lines_count * real_line_height) / 2
             shadow_color = setting.get("shadow_color", settings[0].get("shadow_color", None))
             real_y = y + line_index * real_line_height
             if shadow_color is not None:
                 shadow_size = setting.get("shadow_size", settings[0].get("shadow_size", 3))
                 for offset_x in range(-shadow_size, shadow_size + 1):
                     for offset_y in range(-shadow_size, shadow_size + 1):
                         canvas.text((x + offset_x, real_y + offset_y), line, font=font, fill=shadow_color)
             canvas.text((x, real_y),
                         line,
                         font=font,
                         fill=setting.get("color", settings[0].get("color", self.BLACK)))
Esempio n. 6
0
 def from_text(cls,
               text,
               font,
               fg="black",
               bg=None,
               padding=0,
               max_width=None,
               line_spacing=0,
               align="left",
               tokenizer=whitespace_span_tokenize,
               hyphenator=None):
     """Create image from text. If max_width is set, uses the tokenizer and optional hyphenator
     to split text across multiple lines."""
     padding = Padding(padding)
     if bg is None:
         bg = ImageColor.getrgba(fg)._replace(alpha=0)
     if max_width is not None:
         text = ImageDraw.word_wrap(text, font, max_width, tokenizer,
                                    hyphenator)
     w, h = ImageDraw.textsize(text, font, spacing=line_spacing)
     if max_width is not None and w > max_width:
         logger.warning("Text cropped as too wide to fit: {}".format(text))
         w = max_width
     img = Image.new("RGBA", (w + padding.x, h + padding.y), bg)
     draw = ImageDraw.Draw(img)
     draw.text((padding.l, padding.u),
               text,
               font=font,
               fill=fg,
               spacing=line_spacing,
               align=align)
     return img
Esempio n. 7
0
 def render_text(self, _: Image, draw: ImageDraw, draw_property: Mapping,
                 bounding_box: Tuple[Tuple[int, int], Tuple[int, int]], current_x: int, current_y: int,
                 backwards: bool) -> Tuple[int, int]:
     font = ImageFont.truetype(draw_property["font"], draw_property["font_size"])
     text = self.properties.get(draw_property["property"])
     current_x, current_y = self.resolve_position(draw_property["position"], bounding_box, current_x, current_y)
     if text is not None:
         background = self.properties.get(draw_property["background_property"])
         if background is None:
             background = draw_property["background_default"]
         text_color = self.properties.get(draw_property["text_color_property"])
         if text_color is None:
             text_color = draw_property["text_color_default"]
         text_width, text_height = draw.textsize(text, font)
         desired_width = draw_property["size"][0] if draw_property["size"][0] != "auto" else text_width
         desired_height = draw_property["size"][1] if draw_property["size"][1] != "auto" else text_height
         if backwards:
             current_x -= desired_width
         draw.rectangle(((current_x, current_y), (current_x + desired_width, current_y + desired_height)),
                        fill=background)
         # CodeReview: center between current_y and bottom of bounding box
         x_coord = (current_x + (desired_width - text_width) // 2) if draw_property["centered_width"] else current_x
         y_coord = (current_y + (desired_height - text_height) // 2) if draw_property["centered_height"] \
             else current_y
         draw.text((x_coord, y_coord), text, fill=text_color, font=font)
         current_x += desired_width
     elif draw_property["required"]:
         raise Exception(f"Missing required property: {draw_property['property']} from card {self.properties}")
     return current_x, current_y
Esempio n. 8
0
def _wrap_text(image_draw: ImageDraw,
               text,
               width,
               max_lines=0,
               ellipsis='...',
               **kwargs):
    lines = []
    line = ''
    for token in iter(text):
        if len(lines) >= max_lines > 0:
            # TODO calculate the actual width
            lines[-1] = lines[-1][:-len(ellipsis)] + ellipsis
            break

        if token in '\r\n':
            lines.append(line)
            continue

        newline = line + token
        size = image_draw.textsize(newline, **kwargs)
        if size[0] < width:
            line = newline
            continue

        lines.append(line)
        line = token
    else:
        lines.append(line)
    return lines
Esempio n. 9
0
def draw_text(draw: ImageDraw, image: Image, font, text="Text example", gravity="South", fill=(0, 0, 0), padding=5, margin=10):
    text_width, text_height = draw.textsize(text, font=font)
    gravity = gravity.lower()

    if gravity == 'south':
        x = (image.width - text_width) // 2
        y = image.height - text_height - margin - padding
    elif gravity == 'north':
        x = (image.width - text_width) // 2
        y = margin + padding
    elif gravity == 'center':
        x = (image.width - text_width) // 2
        y = (image.height - text_height) // 2
    elif gravity == 'southwest':
        x = margin + padding
        y = image.height - text_height - margin - padding
    elif gravity == 'southeast':
        x = image.width - margin - padding - text_width
        y = image.height - text_height - margin - padding
    elif gravity == 'northwest':
        x = y = margin + padding
    elif gravity == 'northeast':
        x = image.width - margin - padding - text_width
        y = margin + padding
    else:
        x = y = 0

    draw.rectangle((x - padding, y - padding, x + text_width + padding, y + text_height + padding), fill=fill)
    draw.text((x, y), text=text, font=font)
Esempio n. 10
0
    def _render_alert(self, draw: ImageDraw) -> None:
        font = self._fonts["alert"]

        alert_width, alert_height = draw.textsize(self._display_alert[:30], font=font)
        alert_x = 0
        alert_y = self._d_height - alert_height

        draw.text((alert_x, alert_y), self._display_alert[:30], fill="white", font=font)
Esempio n. 11
0
def renderAdditionalRow3(draw: ImageDraw, width, height):
    nRow = "3rd:"
    draw.text((0, 0), nRow, fill="yellow", font=font)

    nTime = data["departures"]["all"][2]["aimed_departure_time"]
    nDestination = data["departures"]["all"][2]["destination_name"]
    nWidth, _ = draw.textsize(nRow, font)
    nTimeWidth, _ = draw.textsize(nTime, font)
    draw.text((nWidth + 5, 0), nTime, fill="yellow", font=font)
    draw.text((nWidth + nTimeWidth + 10, 0),
              nDestination,
              fill="yellow",
              font=font)

    status = "On time"
    statusWidth, _ = draw.textsize(status, font)
    draw.text((width - statusWidth, 0), status, fill="yellow", font=font)
Esempio n. 12
0
    def get_text_position(self, image: Image, draw: ImageDraw, font: ImageFont,
                          text: str) -> Tuple[float, float]:
        center = (image.size[0] / 2, image.size[1] / 2)
        position_centered_x, position_centered_y = find_centered_position(
            center, draw.textsize(text, font=font))

        if isinstance(self.position, Coordinate):
            return find_centered_position((self.position.x, self.position.y),
                                          draw.textsize(text, font=font))
        elif self.position == AutoPosition.TOP:
            position_y = image.size[1] * 0.05
        elif self.position == AutoPosition.CENTER:
            position_y = position_centered_y
        elif self.position == AutoPosition.BOTTOM:
            position_y = (image.size[1] * 0.95) - draw.textsize(text,
                                                                font=font)[1]

        return (position_centered_x, position_y)
Esempio n. 13
0
    def mark_image(self, draw: ImageDraw, captions):
        HEAD_X, HEAD_Y = (327, 145)
        JUG_X, JUG_Y = (373, 440)

        lines = wrap(captions[0], 20)
        for line_index, line in enumerate(lines):
            line_width, line_height = draw.textsize(line, font=self.font)
            draw.text((HEAD_X - line_width / 2,
                       HEAD_Y - line_height / 2 + line_index * 35),
                      line,
                      font=self.font,
                      fill=self.BLACK)
        lines = wrap(captions[1], 25)
        for line_index, line in enumerate(lines):
            line_width, line_height = draw.textsize(line, font=self.small_font)
            draw.text((JUG_X - line_width / 2,
                       JUG_Y - line_height / 2 + line_index * 20),
                      line,
                      font=self.small_font,
                      fill=self.BLACK)
Esempio n. 14
0
    def mark_image(self, draw: ImageDraw, captions):
        BALL_X, BALL_Y = (250, 90)
        lines = wrap(captions[0], 20)
        for line_index, line in enumerate(lines):
            line_width, line_height = draw.textsize(line, font=self.font)
            draw.text((BALL_X - line_width / 2,
                       BALL_Y - line_height / 2 + line_index * 35),
                      line,
                      font=self.font,
                      fill=self.WHITE)

        ARMS_X, ARMS_Y = (550, 275)
        lines = wrap(captions[1] if len(captions) > 1 else "me", 20)
        for line_index, line in enumerate(lines):
            line_width, line_height = draw.textsize(line, font=self.font)
            draw.text((ARMS_X - line_width / 2,
                       ARMS_Y - line_height / 2 + line_index * 35),
                      line,
                      font=self.font,
                      fill=self.WHITE)
Esempio n. 15
0
    def _render_time(self, draw: ImageDraw) -> None:
        font = self._fonts["alert"]
        hour, minute, second = str(datetime.now().time()).split(".")[0].split(":")

        time_width, time_height = draw.textsize("{}:{}".format(hour, minute), font=font)
        time_x = self._d_width - time_width
        time_y = self._d_height - time_height

        draw.text(
            (time_x, time_y), "{}:{}".format(hour, minute), fill="white", font=font
        )
Esempio n. 16
0
def renderClock(draw: ImageDraw, width, height):
    t = time.localtime()
    current_time = time.strftime("%H:%M:%S", t)

    textwidth, _ = draw.textsize(current_time, fontBoldTall)
    draw.text(
        ((width / 2) - (textwidth / 2), 0),
        current_time,
        fill="yellow",
        font=fontBoldTall,
    )
 def draw_func(draw: ImageDraw):
     font = ImageFont.load_default()
     try:
         if font_file is not None and font_size > 0:
             font = ImageFont.truetype(font_file, font_size)
     except OSError:
         _LOGGER.warning("Unable to find font file: %s", font_file)
     except ImportError:
         _LOGGER.warning("Unable to open font: %s", font_file)
     finally:
         w, h = draw.textsize(text, font)
         draw.text((x - w / 2, y - h / 2), text, font=font, fill=color)
Esempio n. 18
0
 def mark_image(self, draw: ImageDraw, captions, settings):
     for setting in settings:
         caption = captions.pop(0)
         lines = wrap(caption, setting.get("wrap", 20))
         for line_index, line in enumerate(lines):
             x, y = setting.get("position")
             font = ImageFont.truetype("resources/Lato-Regular.ttf", setting.get("font_size", self.FONT_SIZE))
             if setting.get("center", True):
                 line_width, line_height = draw.textsize(line, font=font)
                 x -= line_width / 2
             draw.text((x, y + line_index * (setting.get("font_size", self.FONT_SIZE) + 5)),
                       line,
                       font=font,
                       fill=setting.get("color", self.BLACK))
Esempio n. 19
0
 def watermark_with_text(self, file_obj, text, color, fontfamily=None):
     image = Image.open(file_obj).convert('RGBA')
     draw = ImageDraw(image)
     width, height = image.file_size
     margin = 10
     if fontfamily:
         font = ImageFont.truetype(fontfamily, int(height / 20))
     else:
         font = None
     textWidth, textHeight = draw.textsize(text, font)
     x = (width - textWidth - margin) / 2
     y = height - textHeight - margin
     draw.text((x, y), text, color, font)
     return image
Esempio n. 20
0
    def _render_centered_text(self, draw: ImageDraw, rect: Tuple[float, float, float, float],
                              text: str, fill: str, font: ImageFont, parent_rect=None,
                              mode="largest"):
        bb = BoundingBox(rect).partition_x(self.width, self.row_height)

        if mode == "largest":
            bb = [max(bb, key=lambda x: x.width())]
        elif mode == "first":
            bb = bb[:1]

        for b in bb:
            pos = rect_center(b.bb)
            rw, rh = rect_size(b.bb)
            w, h = draw.textsize(text, font=font)

            if rw < 1:
                continue

            if w > rw:
                text = "\n".join(list(text))
                w, h = draw.textsize(text, font=font)

            draw.text((pos[0] - w/2, pos[1] - h/2), text, fill=fill, font=font)
Esempio n. 21
0
 def draw(self, draw: ImageDraw):
     super().draw(draw)
     font_w, font_h = draw.textsize(self._text, font=self._font)
     if font_h <= self.height and font_w <= self.width:
         horizontal_offset = self.abs_col
         if self._horizontal_align == Alignments.CENTER:
             horizontal_offset += (self.width - font_w) // 2
         elif self._horizontal_align == Alignments.RIGHT:
             horizontal_offset += self.width - font_w
         vertical_offset = self.abs_row
         if self._vertical_align == Alignments.CENTER:
             vertical_offset += (self.height - font_h) // 2 - 1
         elif self._vertical_align == Alignments.BOTTOM:
             vertical_offset += self.height - font_h
         draw.text((horizontal_offset, vertical_offset),
                   self.text,
                   fill=self.foreground,
                   font=self._font)
Esempio n. 22
0
    def mark_image(self, draw: ImageDraw, captions):
        SIGN_X, SIGN_Y = (579, 460)
        """
        ROTATION = -20.6

        text_layer = Image.new('L', (W, H))
        text_draw = ImageDraw.Draw(text_layer)

        lines = wrap(captions[0], 20)
        for line_index, line in enumerate(lines):
            line_width, line_height = draw.textsize(line, font=self.font)
            text_draw.text((SIGN_X-line_width/2, SIGN_Y-line_height/2 + line_index * 35), line, font=self.font)

        text_layer = text_layer.rotate(ROTATION, expand=0)
        """
        lines = wrap(captions[0], 19)
        for line_index, line in enumerate(lines):
            line_width, line_height = draw.textsize(line, font=self.large_font)
            draw.text((SIGN_X - line_width / 2,
                       SIGN_Y - line_height / 2 + line_index * 55),
                      line,
                      font=self.large_font,
                      fill=self.BLACK)
Esempio n. 23
0
 def _renderSubText(offset, text_color, subText: str, draw: ImageDraw):
     stroke_color = (0, 0, 0)
     font = ImageFont.truetype(os.sep.join((os.getcwd(), "resource", "ttf", "DFKai-SB.ttf")), size=50, encoding='utf-8')
     draw.text(offset, subText, fill=text_color, font=font, stroke_width=2, stroke_fill=stroke_color)
     return draw.textsize(subText, font)
Esempio n. 24
0
    def render_list(self, result: Image, draw: ImageDraw, draw_property: Mapping,
                    bounding_box: Tuple[Tuple[int, int], Tuple[int, int]], current_x: int, current_y: int,
                    backwards: bool) -> Tuple[int, int]:
        theme_font = None
        if "text" in draw_property["type"]:
            theme_font = ImageFont.truetype(draw_property["font"], draw_property["font_size"])
        items = self.properties.get(draw_property["property"])
        current_x, current_y = self.resolve_position(draw_property["position"], bounding_box, current_x, current_y)
        size_x, size_y = draw_property["size"]
        if size_x == "auto":
            size_x = bounding_box[1][0] - current_x + bounding_box[0][0]
            if backwards:
                size_x = current_x - bounding_box[0][0]
        if size_y == "auto":
            size_y = bounding_box[1][1] - current_y + bounding_box[0][1]
        print(current_x, size_x, backwards)
        if backwards:
            current_x = current_x - size_x
        orientation = draw_property["orientation"]
        internal_current_y = current_y
        internal_current_x = current_x
        if items is not None:
            cached_current_x = current_x
            cached_current_y = current_y
            spacing = draw_property["spacing"]
            x_border = current_x + size_x
            y_border = current_y + size_y
            rows = draw_property["rows"]
            columns = draw_property["columns"]
            first = True
            # CodeReview: Specify an order that all will conform to
            for item in items:
                resource_name = f"resources/icons/{item}.png"
                if "icon" in draw_property["type"] and os.path.isfile(resource_name):
                    icon = Image.open(resource_name)
                    icon_width, icon_height = icon.size
                    icon = icon.resize((self.format["icon_height"] * icon_width // icon_height,
                                        self.format["icon_height"]), Image.HAMMING)
                    icon_width, icon_height = icon.size
                    x_coord = internal_current_x
                    y_coord = internal_current_y
                    if orientation == "horizontal":
                        if not first:
                            x_coord += spacing
                        first = False
                        if draw_property["centered_height"]:
                            y_coord += (size_y // (rows or 1) - icon_height) // 2
                    if orientation == "vertical":
                        if not first:
                            y_coord += spacing
                        first = False
                        if draw_property["centered_width"]:
                            x_coord += (size_x // (columns or 1) - icon_width) // 2
                    if orientation == "horizontal" and x_coord + icon_width > x_border \
                            and rows is not None and internal_current_y < current_y + (rows - 1) * (size_y // rows):
                        internal_current_y += size_y // rows
                        internal_current_x = cached_current_x
                        x_coord = internal_current_x
                        y_coord += size_y // rows
                    elif orientation == "vertical" and y_coord + icon_height > y_border \
                            and columns is not None and \
                            internal_current_x < current_x + (columns - 1) * (size_y // columns):
                        internal_current_x += size_x // rows
                        internal_current_y = cached_current_y
                    result.paste(icon, (x_coord, y_coord))
                    if orientation == "horizontal":
                        internal_current_x = x_coord + icon_width
                    elif orientation == "vertical":
                        internal_current_y = y_coord + icon_height
                elif "text" in draw_property["type"]:
                    text_width, text_height = draw.textsize(item, theme_font)
                    if draw_property["wrap"] is not None:
                        item = textwrap.fill(item, draw_property["wrap"])
                        text_width, text_height = draw.multiline_textsize(item, theme_font)
                    x_coord = internal_current_x
                    y_coord = internal_current_y
                    text_color = self.properties.get(draw_property["text_color_property"]) or \
                        draw_property["text_color_default"]
                    if draw_property["bulleted"]:
                        draw.ellipse((internal_current_x + spacing,
                                      internal_current_y + (text_height - draw_property["font_size"]) // 2,
                                      internal_current_x + spacing + draw_property["font_size"],
                                      internal_current_y + (text_height + draw_property["spacing"]) // 2),
                                     fill=text_color)
                        x_coord += spacing*2 + draw_property["font_size"]
                    if orientation == "horizontal":
                        if not first:
                            x_coord += spacing
                        first = False
                        if draw_property["centered_height"]:
                            y_coord += (size_y // (rows or 1) - text_height) // 2
                    if orientation == "vertical":
                        if not first:
                            y_coord += spacing
                        first = False
                        if draw_property["centered_width"]:
                            x_coord += (size_x // (columns or 1) - text_width) // 2
                    print(x_coord, text_width, x_border, cached_current_x, internal_current_y)
                    if orientation == "horizontal" and x_coord + text_width > x_border \
                            and rows is not None and internal_current_y < current_y + (rows - 1) * (size_y // rows):
                        internal_current_y += size_y // rows
                        internal_current_x = cached_current_x
                        x_coord = internal_current_x
                        y_coord += size_y // rows
                    elif orientation == "vertical" and y_coord + text_height > y_border \
                            and columns is not None and \
                            internal_current_x < current_x + (columns - 1) * (size_y // columns):
                        internal_current_x += size_x // rows
                        internal_current_y = cached_current_y
                    if draw_property["wrap"] is None:
                        draw.text((x_coord, y_coord), item, fill=text_color, font=theme_font)
                    else:
                        draw.multiline_text((x_coord, y_coord), item, fill=text_color, font=theme_font)

                    if orientation == "horizontal":
                        internal_current_x = x_coord + text_width
                    elif orientation == "vertical":
                        internal_current_y = y_coord + text_height
                else:
                    raise Exception(f"Could not find handler for {item} for {draw_property['type']}")
            if not backwards:
                current_x += size_x
            if orientation == "vertical":
                current_y += size_y
        else:
            if draw_property["required"]:
                raise Exception(f"Missing required property: {draw_property['property']} from card {self.properties}")
        return current_x, current_y
Esempio n. 25
0
def draw_calendar(epd_width, draw: ImageDraw, now: datetime):
    # Generate calendar in top-right
    cal_topleftx = epd_width / 2
    cal_toplefty = 0
    cal_x_offset = 10
    cal_y_offset = 50

    # Configure Calendar settings
    calendar.setfirstweekday(calendar.SUNDAY)
    cal_with_zeros = calendar.monthcalendar(now.year, now.month)
    leading_zeroes = cal_with_zeros[0].count(0)
    # Calculate header format
    cal_header = calendar.month_name[now.month] + ' ' + str(now.year)
    w, h = draw.textsize(cal_header, font=textfont32)
    draw.rectangle([(cal_topleftx, cal_toplefty),
                    (epd_width, cal_toplefty + 1.5 * h)],
                   fill=0)
    draw.text((cal_topleftx +
               (cal_topleftx - w) / 2, cal_toplefty + cal_y_offset - 40),
              cal_header,
              font=textfont32,
              fill=255)
    y = h - 3
    # Draw calendar rows
    days = 'Su Mo Tu We Th Fr Sa'
    w, h = draw.textsize(days, font=textfont24)
    draw.text(
        (cal_topleftx + (cal_topleftx - w) / 2, cal_toplefty + cal_y_offset),
        days,
        font=textfont24)
    for row in cal_with_zeros:
        row = [' ' + (str(x)) if x < 10 else str(x)
               for x in row]  # list comprehension magic
        row = ['  ' if x == ' 0' else x
               for x in row]  # Remove zeros from calendar
        line = ' '.join(row)
        logging.debug("Printing calendar row starting at {},{}".format(
            cal_topleftx + cal_x_offset, cal_toplefty + cal_y_offset + y))
        draw.text((cal_topleftx +
                   (cal_topleftx - w) / 2, cal_toplefty + cal_y_offset + y),
                  line,
                  font=textfont24)
        y += h + 3
    offset_from_zero = now.day + leading_zeroes - 1
    today_x_grid = offset_from_zero % 7
    today_y_grid = floor(offset_from_zero // 7)
    logging.debug("Grid coordinates for today's date: {},{}".format(
        today_x_grid, today_y_grid))
    true_date_w, true_date_h = draw.textsize(" 00", font=textfont24)
    px_buffer = 3
    square_w, square_h = draw.textsize("00", font=textfont24)
    start_x = cal_topleftx + (cal_topleftx - w) / 2 + (
        true_date_w * today_x_grid) - px_buffer
    start_y = cal_toplefty + cal_y_offset + (today_y_grid *
                                             30) + true_date_h - px_buffer
    logging.debug("Square starting at {},{}".format(start_x, start_y))
    draw.rectangle([(start_x, start_y),
                    (start_x + square_w + 2 * px_buffer,
                     start_y + square_h + 2 * px_buffer)],
                   width=2)
    return
Esempio n. 26
0
def fetch_weather(epd_width, epd_height, draw: ImageDraw, now: datetime,
                  config: configparser.ConfigParser):
    try:
        owm_api_key = config['Config']['owm_api_key']
        mapbox_api_key = config['Config']['mapbox_api_key']
        weather_units = config['Config']['units']
        weather_zip = config['Config']['city_zip_code']
        weather_country = config['Config']['city_country_code']
    except configparser.MissingSectionHeaderError as e:
        logging.error(e)
        sys.exit(1)
    # geomap address to coordinates
    query = weather_zip + "," + weather_country
    r = requests.get(
        "https://api.mapbox.com/geocoding/v5/mapbox.places/{}.json?access_token={}"
        .format(query, mapbox_api_key))
    geolocation = r.json()

    try:
        logging.debug("Weather fetched for {}".format(
            geolocation["features"][0]["place_name"]))
    except TypeError:
        logging.error("Error occured when trying to fetch weather location")
        sys.exit(1)
    weather_long = geolocation["features"][0]["center"][0]
    weather_lat = geolocation["features"][0]["center"][1]
    # pull from weather service
    r = requests.get(
        "https://api.openweathermap.org/data/2.5/onecall?lat={}&lon={}&appid={}&units={}"
        .format(weather_lat, weather_long, owm_api_key, weather_units))
    logging.debug("Openweathermap returned status code " + str(r.status_code))
    weather = r.json()
    # Current Weather
    weather_header = "Weather"
    weather_topleftx = epd_width / 2
    weather_toplefty = epd_height / 2
    todayx = weather_topleftx + 100
    forecasty = weather_toplefty + 50
    tomorrowx = todayx + 130
    weather_image_offset = 30
    tempoffset = 100
    w, h = draw.textsize(weather_header, font=textfont32)
    draw.rectangle([(weather_topleftx, weather_toplefty),
                    (epd_width, weather_toplefty + 1.5 * h)],
                   fill=0)
    draw.text(
        (weather_topleftx + (weather_topleftx - w) / 2, weather_toplefty + 5),
        "Weather",
        font=textfont32,
        fill=255)
    w, h = draw.textsize("Now", font=textfont32)
    draw.text(
        (weather_topleftx + ((todayx - weather_topleftx) - w) / 2, forecasty),
        "Now",
        font=textfont32)
    w, h = draw.textsize(
        weather_font_dict[weather["current"]["weather"][0]["icon"]],
        font=weatherfont48)
    draw.text(
        (weather_topleftx + ((todayx - weather_topleftx) - w) / 2,
         forecasty + weather_image_offset),
        weather_font_dict[weather["current"]["weather"][0]["icon"]],
        font=weatherfont48,
        fill=0,
    )
    w, h = draw.textsize(str(round(weather["current"]["temp"])) + "°",
                         font=textfont24)
    draw.text((weather_topleftx +
               ((todayx - weather_topleftx) - w) / 2, forecasty + tempoffset),
              str(round(weather["current"]["temp"])) + "°",
              font=textfont24,
              fill=0)
    w, h = draw.textsize("Feels Like:", font=textfont16)
    draw.text((weather_topleftx +
               ((todayx - weather_topleftx) - w) / 2, forecasty + 128),
              "Feels Like:",
              font=textfont16,
              fill=0)
    w, h = draw.textsize(str(round(weather["current"]["feels_like"])) + "°",
                         font=textfont24)
    draw.text((weather_topleftx +
               ((todayx - weather_topleftx) - w) / 2, forecasty + 145),
              str(round(weather["current"]["feels_like"])) + "°",
              font=textfont24,
              fill=0)

    # Today's Forecast
    w, h = draw.textsize("Today", font=textfont32)
    draw.text((todayx + ((tomorrowx - todayx) - w) / 2, forecasty),
              "Today",
              font=textfont32)
    w, h = draw.textsize(
        weather_font_dict[weather["daily"][0]["weather"][0]["icon"]],
        font=weatherfont48)
    draw.text(
        (todayx +
         ((tomorrowx - todayx) - w) / 2, forecasty + weather_image_offset),
        weather_font_dict[weather["daily"][0]["weather"][0]["icon"]],
        font=weatherfont48,
        fill=0)
    todaymintemp = round(weather["daily"][0]["temp"]["min"])
    todaymaxtemp = round(weather["daily"][0]["temp"]["max"])
    w, h = draw.textsize(str(todaymaxtemp) + "°/" + str(todaymintemp) + "°",
                         font=textfont24)
    draw.text(
        (todayx + ((tomorrowx - todayx) - w) / 2, forecasty + tempoffset),
        str(todaymaxtemp) + "°/" + str(todaymintemp) + "°",
        font=textfont24,
        fill=0)
    precipxoffset = 40
    precipyoffset = 120
    # today's precip chance
    if todaymintemp < 32:
        # snow image!
        w_image, h = draw.textsize(weather_font_dict['13d'],
                                   font=weatherfont32)
        w_text, h = draw.textsize(str(round(weather["daily"][0]["pop"])),
                                  font=textfont32)
        sum_w = w_image + w_text + precipxoffset / 2
        draw.text(
            (todayx +
             ((tomorrowx - todayx) - sum_w) / 2, forecasty + precipyoffset),
            weather_font_dict['13d'],
            font=weatherfont32,
            fill=0)
    else:
        # lame, no snow
        w_image, h = draw.textsize(weather_font_dict['10d'],
                                   font=weatherfont32)
        w_text, h = draw.textsize(str(round(weather["daily"][0]["pop"])),
                                  font=textfont32)
        sum_w = w_image + w_text + precipxoffset / 2
        draw.text(
            (todayx +
             ((tomorrowx - todayx) - sum_w) / 2, forecasty + precipyoffset),
            weather_font_dict['10d'],
            font=weatherfont32,
            fill=0)
    draw.text((todayx + ((tomorrowx - todayx) - sum_w) / 2 + precipxoffset,
               forecasty + precipyoffset + 13),
              str(round(weather["daily"][0]["pop"])) + "%",
              font=textfont32,
              fill=0)

    # Tomorrow's Forecast

    w, h = draw.textsize("Tomorrow", font=textfont32)
    draw.text((tomorrowx + ((epd_width - tomorrowx) - w) / 2, forecasty),
              "Tomorrow",
              font=textfont32)
    w, h = draw.textsize(
        weather_font_dict[weather["daily"][1]["weather"][0]["icon"]],
        font=weatherfont48)
    draw.text(
        (tomorrowx +
         ((epd_width - tomorrowx) - w) / 2, forecasty + weather_image_offset),
        weather_font_dict[weather["daily"][1]["weather"][0]["icon"]],
        font=weatherfont48,
        fill=0)
    tomorrowmaxtemp = round(weather["daily"][1]["temp"]["max"])
    tomorrowmintemp = round(weather["daily"][1]["temp"]["min"])
    w, h = draw.textsize(str(tomorrowmaxtemp) + "°/" + str(tomorrowmintemp) +
                         "°",
                         font=textfont24)

    draw.text((tomorrowx +
               ((epd_width - tomorrowx) - w) / 2, forecasty + tempoffset),
              str(tomorrowmaxtemp) + "°/" + str(tomorrowmintemp) + "°",
              font=textfont24,
              fill=0)
    # tomorrow's precip chance
    if tomorrowmintemp < 32:
        # snow image!
        w_image, h = draw.textsize(weather_font_dict['13d'],
                                   font=weatherfont32)
        w_text, h = draw.textsize(str(round(weather["daily"][1]["pop"])),
                                  font=textfont32)
        sum_w = w_image + w_text + precipxoffset / 2
        draw.text(
            (tomorrowx +
             ((epd_width - tomorrowx) - sum_w) / 2, forecasty + precipyoffset),
            weather_font_dict['13d'],
            font=weatherfont32,
            fill=0)
    else:
        # lame, no snow
        w_image, h = draw.textsize(weather_font_dict['10d'],
                                   font=weatherfont32)
        w_text, h = draw.textsize(str(round(weather["daily"][1]["pop"])),
                                  font=textfont32)
        sum_w = w_image + w_text + precipxoffset / 2
        draw.text(
            (tomorrowx +
             ((epd_width - tomorrowx) - sum_w) / 2, forecasty + precipyoffset),
            weather_font_dict['10d'],
            font=weatherfont32,
            fill=0)
    draw.text(
        (tomorrowx + ((epd_width - tomorrowx) - sum_w) / 2 + precipxoffset,
         forecasty + precipyoffset + 13),
        str(round(weather["daily"][1]["pop"])) + "%",
        font=textfont32,
        fill=0)

    # Draw division lines
    if draw_weather_lines:
        weather_bottom_divider_offset = 18
        draw.line([(todayx, weather_toplefty + 1.5 * h),
                   (todayx, epd_height - weather_bottom_divider_offset)],
                  width=2)
        draw.line([(tomorrowx, weather_toplefty + 1.5 * h),
                   (tomorrowx, epd_height - weather_bottom_divider_offset)],
                  width=2)
        draw.line(
            [(weather_topleftx, epd_height - weather_bottom_divider_offset),
             (epd_width, epd_height - weather_bottom_divider_offset)],
            width=2)
    # Print weather location, update time
    w, h = draw.textsize("{}".format(geolocation["features"][0]["place_name"]),
                         font=textfont12)
    draw.text((weather_topleftx + 8, epd_height - h - 2),
              "{}".format(geolocation["features"][0]["place_name"]),
              font=textfont12)
Esempio n. 27
0
def display_news(epd_width, epd_height, draw: ImageDraw,
                 config: configparser.ConfigParser):
    # This function could use a refactor because of all of the code reuse, but it works
    news_rightx = epd_width / 2
    general_news_header = "Top USA Headlines"
    tech_news_header = "Top Tech Headlines"
    header_font = textfont32
    headline_font = textfont16
    headline_offset_from_side = 10
    second_line_x_offset_from_headline = 10
    first_headline_offset_from_top = 50
    try:
        api_key = config['Config']['newsapi_key']
    except configparser.MissingSectionHeaderError as e:
        logging.error(e)
        sys.exit(1)
    # Draw header rectangle
    w, h = draw.textsize(general_news_header, font=header_font)
    draw.text(((news_rightx - w) / 2, 10),
              general_news_header,
              font=header_font)
    y = first_headline_offset_from_top
    r = requests.get(
        general_news_non_tech_url.format(
            api_key, ",".join(included_general_news_domains)))
    results = r.json()
    general_articles = results['data']
    # Process article headers
    titles_with_source = []
    for article in general_articles:
        titles_with_source.append([article['source'], article['title']])
    # For each headline: Calculate size, trim remainder, display
    for headline in titles_with_source:
        article_source = headline[0]
        article_title = headline[1]
        second_line = ""
        text_to_display = article_source + ": " + article_title
        text_to_display = text_to_display.encode('latin-1', 'ignore')
        w, h = draw.textsize(text_to_display, font=headline_font)
        # Split text into at most 2 lines
        while w + headline_offset_from_side > news_rightx:
            article_title, excess_word = article_title.rsplit(" ", 1)
            second_line = excess_word + " " + second_line
            text_to_display = article_source + ": " + article_title
            text_to_display = text_to_display.encode('latin-1', 'ignore')
            w, h = draw.textsize(text_to_display, font=headline_font)
        draw.text((headline_offset_from_side, y),
                  text_to_display,
                  font=headline_font)
        y += h
        if second_line:
            # trim excess characters and replace with "..." at the end
            second_line = second_line.encode('latin-1', 'ignore')
            encoded_space = " ".encode('latin-1')
            encoded_ellipse = "...".encode('latin-1')
            w, h = draw.textsize(second_line, font=headline_font)
            w_periods, h = draw.textsize("...", font=headline_font)
            needs_periods = False
            if w + headline_offset_from_side + second_line_x_offset_from_headline > news_rightx:
                while w + w_periods + headline_offset_from_side + second_line_x_offset_from_headline > news_rightx:
                    needs_periods = True
                    second_line = second_line[:-1]
                    w, h = draw.textsize(second_line, font=headline_font)
            if needs_periods:
                if second_line.endswith(encoded_space):
                    # Removes floating space issue
                    second_line = second_line[:-1]
                second_line = second_line + encoded_ellipse
            draw.text((headline_offset_from_side +
                       second_line_x_offset_from_headline, y),
                      second_line,
                      font=headline_font)
            y += 1.3 * h
    # Do Tech news here

    w, h = draw.textsize(tech_news_header, font=header_font)
    draw.text(((news_rightx - w) / 2, y), tech_news_header, font=header_font)
    y += 1.2 * h
    r = requests.get(
        tech_news_url.format(api_key, ",".join(excluded_tech_domains)))
    results = r.json()
    general_articles = results['data']

    # Process article headers
    titles_with_source = []
    for article in general_articles:
        titles_with_source.append([article['source'], article['title']])

    # For each headline: Calculate size, trim remainder, display
    for headline in titles_with_source:
        article_source = headline[0]
        article_title = headline[1]
        second_line = ""
        text_to_display = article_source + ": " + article_title
        text_to_display = text_to_display.encode('latin-1', 'ignore')
        w, h = draw.textsize(text_to_display, font=headline_font)
        # Split text into at most 2 lines
        while w + headline_offset_from_side > news_rightx:
            article_title, excess_word = article_title.rsplit(" ", 1)
            second_line = excess_word + " " + second_line
            text_to_display = article_source + ": " + article_title
            text_to_display = text_to_display.encode('latin-1', 'ignore')
            w, h = draw.textsize(text_to_display, font=headline_font)
        draw.text((headline_offset_from_side, y),
                  text_to_display,
                  font=headline_font)
        y += h
        if second_line:
            # trim excess characters and replace with "..." at the end
            second_line = second_line.encode('latin-1', 'ignore')
            encoded_space = " ".encode('latin-1')
            encoded_ellipse = "...".encode('latin-1')
            w, h = draw.textsize(second_line, font=headline_font)
            w_periods, h = draw.textsize("...", font=headline_font)
            needs_periods = False
            if w + headline_offset_from_side + second_line_x_offset_from_headline > news_rightx:
                while w + w_periods + headline_offset_from_side + second_line_x_offset_from_headline > news_rightx:
                    needs_periods = True
                    second_line = second_line[:-1]
                    w, h = draw.textsize(second_line, font=headline_font)
            if needs_periods:
                if second_line.endswith(encoded_space):
                    # Removes floating space issue
                    second_line = second_line[:-1]
                second_line = second_line + encoded_ellipse
            draw.text((headline_offset_from_side +
                       second_line_x_offset_from_headline, y),
                      second_line,
                      font=headline_font)
            y += 1.5 * h
        else:
            y += .6 * h
    return
Esempio n. 28
0
 def draw_func(draw: ImageDraw):
     font = ImageFont.load_default()
     if font_file != "" and font_size > 0:
         font = ImageFont.truetype(font_file, font_size)
     w, h = draw.textsize(text, font)
     draw.text((x - w / 2, y - h / 2), text, font=font, fill=color)