Acknowledged

Creating Full White Color Results in Transparent

We might expect this code to draw a filled white circle:

var testWhite = Graphics.createColor(0xFF, 0xFF, 0xFF, 0xFF);
dc.setFill(testWhite);
dc.fillCircle(halfScreenWidth, halfScreenHeight, 10);

However, what actually happens is nothing is drawn. This is because Graphics.createColor translates the color to 0xFFFFFFFF, which is -1 in twos complement, and which is the same as Graphics.COLOR_TRANSPARENT. Changing e.g. the alpha value to 0xFE instead of 0xFF will cause the circle to draw as expected.

  • I stumbled upon this today. It's not great, but I "solved" it by adding a few if statements whenever I set a color that check if it's pure white an return a color that's barely not pure white or if it' actually a transparent color and return 0. I encapsulated it in a utility function:

    function checkColor(color as ColorType) as ColorType {
        if (color == 0xFFFFFFFF) {
            return 0xFFFFFFFE;
        }
        if (color < 0x01000000) {
            return 0x00000000;
        }
        return color;
    }

    I just wrap all my calls to setFill and setStroke with this:

    dc.setFill(Util.checkColor(fillColor))
    dc.setStroke(Util.checkColor(strokeColor))

    Not ideal, but seems to work as desired. I do wish that Monkey C had an 32-bit unsigned int type for this to avoid these quirks...

  • Probably the easiest comprehensive solution that doesn't require changing any types would be:

    - Graphics.createColor(0xFF, 0xFF, 0xFF, 0xFF) should return 0xFFFFFF. This gets around the bug where createColor() returns COLOR_TRANSPARENT for solid white (alpha = 0xff)

    - Graphics.createColor(0, ...) should return -1 / COLOR_TRANSPARENT. This gets around the bug where createColor() returns an opaque color when the alpha channel is 0.

  • Or if we could change ColorType to Long (which still probably wouldn't happen), one of the extra bits could be used to indicate the color format (RGB or ARGB). One problem with this approach is that it would be confusing for developers when reading and writing raw numerical / hex values for colors.

  • (I guess the perfect solution would be for Garmin to go back in time and retroactively use RGBA or ARGB internally for all colors. If only.)

  • Great find!

    TL;DR a related (and seemingly unsolvable) issue is that setting an alpha channel / opacity of 0 will have the opposite of the intended effect - the resulting color will be completely opaque.

    --

    Not to state the obvious, but this bug stems from the fact that all the CIQ API calls which produce or accept a color define a color value as Lang.Number (signed 32-bit). Conceivably, one way to fix this would be to use Lang.Long (signed-64 bit) instead, but ofc that would break backwards compatibility and lead to other issues (the memory usage for an array of Longs is much worse than the usage for an array of Numbers, for example.)

    Or Graphics.createColor() could be changed so that given an input of (0xff, 0xff, 0xff, 0xff), it returns 0xFFFFFF (as if the alpha value was 0.) Note that Graphics.COLOR_WHITE is 0xFFFFFF.

    This leads to another issue though - setting an alpha channel of 0 will not have the expected result.

    Logically, setting the alpha channel to 0 in the call to Graphics.createColor() should lead to a completely transparent color (same as effect as using COLOR_TRANSPARENT), but it actually seems to have the opposite effect: you get a completely opaque color instead.

    Again not to state the obvious but it seems that this problem stems from Garmin deciding to use both RGB and ARGB formats simultaneously, so that the alpha channel is in the most significant byte of the color, meaning that the underlying value of RGB(0xff, 0, 0) (red) is the same as ARGB(opacity = 0, 0xff, 0, 0) (red but completely transparent.) IOW, there is no way to distinguish between an RGB value and the corresponding ARGB value where the opacity happens to be 0.

    (Ofc it would've been even worse to use RGB and RGBA simultaneously, bc then 0xFF00 could either be green or blue with 0 opacity.)

    Seems that Graphics.ColorType should've been a class which includes information about the color format - to preserve backwards compatibility, it could also be a Number (in which case it would be interpreted as RGB or -1 / COLOR_TRANSPARENT). Ofc that could've potentially led to performance issues (even worse than making it a Long).