A few tips... Regarding the discussion in https://georeference.org/forum/t159438.12#159439 ... You have to be careful parsing that discussion because some posts use transparency and others opacity. Sloots, for example, in a post uses "alpha" meaning transparency, a number from 0 to 255 where 0 is no transparency (fully opaque) and 255 is fully transparent. apo, in contrast, in a post uses "Alpha" to mean percent opacity with values from 0 to 100. Manifold color code numbers are packed ARGB where the high bits are alpha (transparency, 0 to 255). That's convenient because if there is no alpha (numbers currently used in various palettes used in styles have no alpha... that may change with the next build) it's a simple decay into RGB. But when you're constructing partially transparent colors it's conceptually easier, I think, to use percent opacity. For example, you may want a red that's 70% opaque, which corresponds visually to what you'd get if you had a layer with that red color in it that has a 70% opacity setting in the Layers pane. Using percent opacity also gets around the endemic problem in graphics where some people use the word "alpha" to mean transparency and others to mean opacity. Converting R, G, B and percentOpacity into a Manifold packed ARGB number is easy. I do that in C# because I think the arithmetic logic is simpler and clearer than doing it in SQL. It's easy to call the C# function from SQL, too: // C# // A script named [RGBO to packed ARGB] class Script { public static uint PackColorARGB(uint red, uint green, uint blue, uint percentOpacity) { uint alpha = 255 - ((percentOpacity * 255 + 50) / 100); return (alpha << 24) | (red << 16) | (green << 8) | blue; } static void Main() { } } If you want to build a Manifold color from alpha instead of percent opacity just use alpha as an argument and eliminate the conversion from percentOpacity: // C# class Script { public static uint PackColorARGB(uint red, uint green, uint blue, uint alpha) { return (alpha << 24) | (red << 16) | (green << 8) | blue; } static void Main() { } } The above are written using uint, so they don't bother clamping ranges for percent opacity to 0 to 100 and channels to 0 to 255. It's simple to use C# scripts in your SQL. Save the script in your project using a convenient name, and then define a function using the script: FUNCTION PackORGB(@r UINT32, @g UINT32, @b UINT32, @o UINT32) UINT32 AS SCRIPT [RGBO to packed ARGB] ENTRY 'Script.PackColorARGB'; And then use the function. PackORGB([Red], [Green], [Blue], [OpacityPct]) The above could be an expression to create a new computed field that is a Manifold color code with transparency that is computed from four fields that give R, G, B and percent opacity values. The function definition goes in the Expression Context part of the expression builder when creating a computed field. Suppose you already have a packed, RGB, Manifold color code and you want to get the corresponding packed ARGB Manifold color code for some percent opacity you want? That's very easy to do using function defined in a script. Create a C# script called MCO to packed ARGB: // C# // A script named [MCO to packed ARGB] class Script { public static uint PackColorARGB(uint MC, uint percentOpacity) { uint alpha = 255 - ((percentOpacity * 255 + 50) / 100); return (alpha << 24) | MC; } static void Main() { } } You can then use it in your SQL by defining a function (put that in the Expression Context when using it to create computed fields): cUNCTION PackMCO(@m UINT32, @o UINT32) UINT32 AS SCRIPT [MCO to packed ARGB] ENTRY 'Script.PackColorARGB'; ... and then using the function in your SQL: PackMCO([MC], [OpacityPct] The example assumes your existing RGB Manifold color code is in a field called [MC]. Note that using such a PackMCO function is a lot more straightforward than what can be complex arithmetic inside SQL. All of the above functions, by the way are set up to round up or down to the nearest integer when converting percent opacity to alpha. If you want to convert alpha to percent opacity, that's easy, too. Here it is using int, with the input value of alpha clamped to 0 to 255 range with an if ... else if test: // C# // AlphaToPercentOpacity.cs class Script { public static int AlphaToPercentOpacity(int alpha) { if (alpha < 0) alpha = 0; else if (alpha > 255) alpha = 255; return ((255 - alpha) * 100 + 127) / 255; } static void Main() { } } For anybody that wants to extract alpha, R, G, and B from a Manifold packed ARGB color code, I do that using four functions, that can be put into their own script components: // C# // UnpackChannelA.cs class Script { public static uint UnpackColorA(uint packed) { uint alpha = (packed >> 24) & 0xFF; return (alpha == 0) ? 0 : alpha; } static void Main() { } } // C# // UnpackChannelR.cs class Script { public static uint UnpackColorR(uint packed) { return (packed >> 16) & 0xFF; } static void Main() { } } // C# // UnpackChannelG.cs class Script { public static uint UnpackColorG(uint packed) { return (packed >> 8) & 0xFF; } static void Main() { } } // C# // UnpackChannelB.cs class Script { public static uint UnpackColorB(uint packed) { return packed & 0xFF; } static void Main() { } } These are simple to use from SQL, for example, FUNCTION UnpackA(@m UINT32) UINT32 AS SCRIPT [UnpackChannelA] ENTRY 'Script.UnpackColorA'; And using the function... UnpackA([MC]) ... to get the alpha channel used in a packed ARGB value in a field called [MC]. Note that the alpha function works correctly even if the manifold code in MC was or was not created with an alpha value. Converting values to Hex is also very simple. A simple SQL way to do it if you have an RGB (no alpha) manifold color code was given by adamw in a post, with an example of use in the command window: --SQL9 FUNCTION HexByte(@c UINT32) NVARCHAR AS StringFormatNumber(@c MOD 256, 'X02', '') END; FUNCTION HexRGB(@c UINT32) NVARCHAR AS '#' + HexByte(@c / 256 / 256) + HexByte(@c / 256) + HexByte(@c) END; ? HexRGB(3329330) -- #32CD32 That takes advantage of the very rich StringFormatNumber SQL function in 9. It's trivial to extend that to converting an ARGB value (left as an exercise for the reader...). You may not need to preface the result with a # if you just want Hex strings to feed some other application. It is wise to build in support for ARGB (with alpha) manifold color codes since that is what is built into the machinery and what people are using now. A general solution as a C# script: // C# // Convert Hex string to uint class Script { public static uint HexStringToUInt(string hex) { uint result = 0; for (int i = 0; i < hex.Length; i++) { char c = hex[i]; uint value = 0; if (c >= '0' && c <= '9') value = (uint)(c - '0'); else if (c >= 'A' && c <= 'F') value = (uint)(c - 'A' + 10); else if (c >= 'a' && c <= 'f') value = (uint)(c - 'a' + 10); else throw new System.ArgumentException("Invalid character in hex string."); result = (result << 4) | value; } return result; } static void Main() { } } Hope that helps!
|