bk1285 / rpi_wordclock

Software to create a Raspberry Pi based wordclock
GNU General Public License v3.0
214 stars 108 forks source link

[Enhancement] Rendering icon fonts and svg icons #179

Open FabianReister opened 3 years ago

FabianReister commented 3 years ago

Hey there!

Fonts such as Font Awesome (https://fontawesome.com/) and Octicons (https://primer.style/octicons/) can be rendered on the wordclock. See two octicon examples:

"Mail" icon Screenshot_20201222_012336

"Heart" icon Screenshot_20201222_011051

Miecjel commented 3 years ago

Hi @FabianReister ,

This looks nice. Do you have an example how to achieve this? Do you use wcd.showtext?

Best regards, Michel

FabianReister commented 3 years ago

@Miecjel in my fork (currently private repo), I made some fundamental changes to the architecture. You can have a look at the following code/class on how to create a rasterized image.

import io
import logging
import os

import PIL
import cairosvg

from wordclock.common.drawing.wordclock_icons import IconFont

class SvgIcon:
    def __init__(self, icon_font: IconFont, identifier: str):
        self.svg_filename = os.path.join(os.path.dirname(__file__),
                                         os.path.pardir,
                                         icon_font.filename(identifier),)

        assert os.path.exists(
            self.svg_filename
        ), f"The file '{self.svg_filename}' does not exist!"

        logging.getLogger(__name__).info(
            f"Loading svg image {self.svg_filename}")

    def load_as_image(self, size) -> PIL.Image:
        """Loads an svg icon and converts it to a rasterized image

        Args:
            size (List): Size of the rasterized image

        Returns:
            PIL.Image: the converted image
        """        

        # convert svg to png buffer
        image_data = cairosvg.svg2png(url=self.svg_filename,
                                      output_width=size[0],
                                      output_height=size[1])
        image = PIL.Image.open(io.BytesIO(image_data))

        # the alpha channel is fully transparent and would cause the image to be black when directly converted to RGB
        image_rgb = PIL.Image.new("RGB", image.size, (255, 255, 255))
        image_rgb.paste(image, mask=image.split()[3])  # 3 is the alpha channel

        # icons are black with white background => on the wordclock we should invert it
        image_rgb = PIL.ImageOps.invert(image_rgb)

        return image_rgb.copy()

There are many ways of how to create a rasterized image with the desired resolution of 11x10px. I tested some alternatives (intermediate image with higher resolution and downsampling) but the one presented here seems to be the sharpest.

Miecjel commented 3 years ago

@FabianReister ok, thnx!

bk1285 commented 3 years ago

Really nice to see this! ..especially in conjunction with a smart home system or similar, it would probably be nice to have functionality like this available: Ideally being able to provide a specified icon via API for further display on the wordclock.

Currently, I'm busy with migrating the code to py3 and fix various issues, but afterwards I can think about coming back to this.