"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

  • Yes, a whole bunch of neat stuff with System 6!  But with scalaable/vector fonts, they aren't on all System6 devices, so be careful.  Here's a test app I have to try stuff.  "ABC is drawn with a scalable font based on screen height (using drawText), while the "123..) is a different size and uses drawRadialText(). while "hello" uses drawAngledText().  The top icon is just launcher_icon. while the lower one is 150% the size using drawScaledBitmap() (again, only available on some devices).  I've not messed around with drawBitmap2() yet, but looks to be pretty powerful

  • Thank you for your response. it's good to know this sooner. As for the mentioned things, it honestly doesn't excite me at all and doesn't even interest me much, since it concerns a maximum of 10 devices. making the functionality of one thing double is...

  • Hey i am very happy to see this disscussion is still going on after all thoses years.  I have a question.  I just got a Epix Gen 2 pro (454 x454 px) and i am trying to use this tool again (tilemapper).  I am wondering why always getting the error message: ''ERROR: number of tiles have exceeded maximum size (576). Try breaking your files up, or use a larger tile size''.

    Even when i try only a couple of degress, let's say rotation from 45 deg to 50 dregrees it say the same thing: ''ERROR: number of tiles have exceeded maximum size (576). Try breaking your files up, or use a larger tile size''

    Look at the code i have tell me if anything is wrong or what should i do to help:

    C:\Users\Jay\Desktop>python tilemapper.py -i C:\Users\Jay\Desktop\test\b\b.png -o C:\Users\Jay\Desktop\test\b\c -m rotate -r 454 -u 81 -v 90 -s 6
    CIQ tilemapper 0.9.3 (c) 2017-2019 Franco Trimboli
    Tile mode is rotate
    Target resolution 454x454
    Input file to process "C:\Users\Jay\Desktop\test\b\b.png"
    Format is PNG, resolution 576x576, mode RGB
    3 frame(s) to process
    ERROR: number of tiles have exceeded maximum size (576). Try breaking your files up, or use a larger tile size.

    C:\Users\Jay\Desktop>python tilemapper.py -i C:\Users\Jay\Desktop\test\b\b.png -o C:\Users\Jay\Desktop\test\b\c -m rotate -r 454 -u 81 -v 90 -s 6
    CIQ tilemapper 0.9.3 (c) 2017-2019 Franco Trimboli
    Tile mode is rotate
    Target resolution 454x454
    Input file to process "C:\Users\Jay\Desktop\test\b\b.png"
    Format is PNG, resolution 576x576, mode RGB
    3 frame(s) to process
    ERROR: number of tiles have exceeded maximum size (576). Try breaking your files up, or use a larger tile size.

    C:\Users\Jay\Desktop>python tilemapper.py -i C:\Users\Jay\Desktop\test\b\b.png -o C:\Users\Jay\Desktop\test\b\c -m rotate -r 454 -u 81 -v 130 -s 6
    CIQ tilemapper 0.9.3 (c) 2017-2019 Franco Trimboli
    Tile mode is rotate
    Target resolution 454x454
    Input file to process "C:\Users\Jay\Desktop\test\b\b.png"
    Format is PNG, resolution 576x576, mode RGB
    10 frame(s) to process
    ERROR: number of tiles have exceeded maximum size (576). Try breaking your files up, or use a larger tile size.

    C:\Users\Jay\Desktop>python tilemapper.py -i C:\Users\Jay\Desktop\test\b\b.png -o C:\Users\Jay\Desktop\test\b\c -m rotate -r 454 -u 81 -v 83 -s 6
    CIQ tilemapper 0.9.3 (c) 2017-2019 Franco Trimboli
    Tile mode is rotate
    Target resolution 454x454
    Input file to process "C:\Users\Jay\Desktop\test\b\b.png"
    Format is PNG, resolution 576x576, mode RGB
    2 frame(s) to process
    ERROR: number of tiles have exceeded maximum size (576). Try breaking your files up, or use a larger tile size.

    C:\Users\Jay\Desktop>python tilemapper.py -i C:\Users\Jay\Desktop\test\b\b.png -o C:\Users\Jay\Desktop\test\b\c -m rotate -r 454 -u 81 -v 82 -s 6
    CIQ tilemapper 0.9.3 (c) 2017-2019 Franco Trimboli
    Tile mode is rotate
    Target resolution 454x454
    Input file to process "C:\Users\Jay\Desktop\test\b\b.png"
    Format is PNG, resolution 576x576, mode RGB
    2 frame(s) to process
    ERROR: number of tiles have exceeded maximum size (576). Try breaking your files up, or use a larger tile size.

    Thank you very much, it is appreciate.

  • If I remember correctly you should use -t parameter in the end… if you look at the ftrimbollis samples, you can find the usage of the -t parameter like this -t 54

    github.com/.../process_baseball.sh

  • How to keep the original color of the picture? Is there any way?
  • Yes, for the latest models only!

    I'm disappointed that Garmin doesn't offer an update for relatively new watches like the Fenix 6 for example.

  • Is it possible to do seconds using this tool / technique? Thanks :)

  • Would you be willing to share an example please :)

    Also, I had trouble installing pillow so I installed using the following command: pip install --only-binary Pillow Pillow  

    That installs 10.2.0 and seems to change the results.

  • exactly like minutes each second is generated with the tool to rotate 6 degrees at the time.

    // load the appropriate tilemaps as
    // seconds are split across four tilemaps;
    // 0_14, 15_29, 30_44, 45_59
    if (_second>=45 && _second<=59) {
      _f_hands = WatchUi.loadResource(rf.font_seconds_45_59);
      _current_hand = WatchUi.loadResource(rj.font_seconds_45_59_data);
      sec = _second + 45;
    }
    if (_second>=30 && _second<=44) {
      _f_hands = WatchUi.loadResource(rf.font_seconds_30_44);
      _current_hand = WatchUi.loadResource(rj.font_seconds_30_44_data);
      sec = _second + 30;
    }
    if (_second>=15 && _second<=29) {
      _f_hands = WatchUi.loadResource(rf.font_seconds_15_29);
      _current_hand = WatchUi.loadResource(rj.font_seconds_15_29_data);
      sec = _second + 15;
    }
    if (_second>=0 && _second<=14) {
      _f_hands = WatchUi.loadResource(rf.font_seconds_0_14_b);
      _current_hand = WatchUi.loadResource(rj.font_seconds_0_14_data);
      sec = _second;
    }