"tilemapper" tool for tile-mapped anti-aliased graphics

Hey folks,

Here's my command line tool that helps developers build tile-mapped anti-aliased graphics for Garmin wearables;
github.com/.../garmin-tilemapper

Way back in 2017, I showcased a tile-map sprite technique to compress graphics;
forums.garmin.com/.../my-technique-for-anti-aliased-animation-and-bitmaps

You've probably seen my anti-aliased watchfaces in the app store. 
https://apps.garmin.com/en-US/developer/e43b20dc-99b5-4906-ae38-65b36a68b208/apps

This is one of the tools I have been using to develop them.

As a handy extra, I've also included two sample watchfaces, and their artwork. This includes a new "steamboat willie" watchface.

The great thing about this approach, is that you can scale your designs seamlessly across many different devices and resolutions.

Please be mindful that this is the first release, so your milage may vary with bugs, and platform support. Happy to hear your feedback.

Can't wait to see what you all create!! Slight smile

  • Thank you Slight smile

    I read somewhere that the watches have a max number of bitmaps that can be loaded, but I assume because these are fonts it's not an issue if the device has enough memory.

  • exactly, fonts just eats up memory... however, with newer devices you can use AffineTransform to rotate bitmaps. So you could achieve same functionality by making a hour, min and secondhand (each one it's own image), and rotate them accordingly to the time. Possible also to scale them down, so you make for the largest 454px the hands, and then scale them down to lower resolutions.

  • Yes, I would be using affine transformations for more modern devices. Here's a few examples on how to do it:
    https://forums.garmin.com/developer/connect-iq/f/discussion/336765/bitmap-transformation/1634475#

    That being said, my tool is handy if you're keen on supporting legacy devices too, not just the more modern ones.

  • I ran the Analog example successfully, but after regenerating the tiles I'm getting an out of bounds error. I didn't change the artwork, I just wanted to see if I could generate tiles for a known working example. I think this is due to installing a later version of Python and Pillow 10.2.0. I'm on a Windows machine and struggled to get pillow 6.2.0 installed. For that version I get the message "We do not recommend building from source on Windows" so maybe I'll give it a try on WSL.

  • Thanks, will give that a try, I already have an idea for something :)

    I assume the fonts would have better performance than the affine transforms though?

  • Got it working on Windows, with Python 3.8 and Pillow 10.3.0. I think my previous attempt failed because I had some syntax incorrect when generating the tiles. Windows doesn't like the * syntax, so I had to use:

    python tilemapper.py -i samples/analogue/artwork/analogue-dial-01-chapter.png samples/analogue/artwork/analogue-dial-02-markers.png samples/analogue/artwork/analogue-dial-03-romans.png -o samples/analogue/resources-round-240x240/dial -r 240

    I made a basic edit to one of the hands and get this message. Is there a specific format the png must be in? I just added a few white dots to test with, it's still grayscale, I think.

    CIQ tilemapper 0.9.3 (c) 2017-2019 Franco Trimboli
    Tile mode is rotate
    Target resolution 240x240
    Input file to process "samples/analogue/artwork/analogue-minute.png"
    Format is PNG, resolution 1000x1000, mode P
    Traceback (most recent call last):
    File "tilemapper.py", line 451, in <module>
    main()
    File "tilemapper.py", line 88, in main
    canvas = preprocessCanvas(canvas)
    File "tilemapper.py", line 228, in preprocessCanvas
    canvas = invertCanvas(canvas)
    File "tilemapper.py", line 250, in invertCanvas
    inverted_image = ImageOps.invert(canvas)
    File "C:\Users\doubellj\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\PIL\ImageOps.py", line 630, in invert
    return image.point(lut) if image.mode == "1" else _lut(image, lut)
    File "C:\Users\doubellj\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\PIL\ImageOps.py", line 55, in _lut
    raise NotImplementedError(msg)
    NotImplementedError: mode P support coming soon