Better colour control for Toolbox gadgets
Pages: 1 2
Dave Higton (1515) 3584 posts |
It looks to me as though all Toolbox gadgets can only use the original 16 Wimp colours. That surely must be well overdue for an update. As an example, I’ve just managed to get IPPTrnspt to interrogate a printer for its marker (ink, toner, etc) levels and present them in a GUI. Martin Avison helpfully pointed out a way to display the names of the markers (e.g. “Light magenta ink”) on a background of the colour reported by the printer (a 24 bit RRGGBB number), but it means hacking into the Display gadgets in the window specified by the Res file and replacing their validation strings, which are currently string constants in the Window module. There is no way to do this via an official API. It seems a simple enough request. I hope it’s apparent from the above that simply making them fixed at resource creation time isn’t enough, they have to be alterable at run time via an API. |
Julie Stamp (8365) 479 posts |
That sounds a nice way to show the ink levels :-) I had a look in ResEd. It seems there are two parts to this. First, the only gadgets you can set any colours on currently are
Second, for these you can only choose the colour from the sixteen. However then looking at the API (I don’t have Tabs or TreeView to hand) there are differet ways to set colours at run-time.
In this case, Display feels to me closest to Button, so adding a set_validation method would be appropriate? |
Piers (3264) 62 posts |
That would mean all callers need to parse and update the validation string. Wouldn’t it be better if it’s done once, by the toolbox? Button should be updated, too. I’d choose a set_colour() method for all, with a flag to indicate 24bpp. They could all share the validation string code. |
Dave Higton (1515) 3584 posts |
However then looking at the API (I don’t have Tabs or TreeView to hand) there are differet ways to set colours at run-time. Thing is, the validation string is already used to set the slabbing and the old-style Wimp colours: R2;f17 To set the validation string without altering the style of a gadget, any set_validation ought IMHO to add to the original string… but that gets difficult when doing it on a subsequent occasion. set_colour looks to me to be the logical approach – “does what it says on the tin”, doesn’t have any side effects. |
Dave Higton (1515) 3584 posts |
Credit is due to Martin Avison. |
Dave Higton (1515) 3584 posts |
How about adding a call set_colour_BGR()? This could be added to all(?) gadgets, including those that already have a set_colour() method. |
nemo (145) 2644 posts |
Both the cyan and magenta colour fills have a luminance below 50% so ought to have white text. [and don’t make the mistake of calculating luma – you must take gamma into account] |
Rick Murray (539) 13958 posts |
This seems like the sort of thing that ColourTrans should do, rahter than everybody reinventing broken wheels… |
Dave Higton (1515) 3584 posts |
Y’know, nemo, it does look better with white foreground on cyan and magenta. I’m sure you’ll shoot this down in flames, but… I observed that the Rec.709 coefficients are nearly in the ration 3:10:1 (R:G:B), so I compute (3 * R) + (10 * G) + B, where R, G, B are the chroma values (0..255), then compare with 2550 to decide whether to make the foreground black or white. The closer that weighted sum is to the threshold, the less difference it makes whether the foreground is black or white. So I reckon that’s a good enough computation; it’s not CPU-hungry, nor does it take many lines of code. And I know it doesn’t take gamma into account. Anyway, go ahead, shoot. |
nemo (145) 2644 posts |
Any weighted sum of gamma components is luma – one would need to linearise and then sum to find luminance. But “50% luminance” is subjective anyway – anything is better than nothing (even just thresholding on green). So I’m delighted you’ve done something!
It’s funny you should mention that… <slides out of frame> |
Dave Higton (1515) 3584 posts |
I should have added a screenshot to show the difference. |
John WILLIAMS (8368) 499 posts |
I’m reminded of a little application Rick did for my Pic_Index program many years ago (a mere 20-odd) to help me find a suitably contrasting text colour for use against tiled web backgrounds. Nowhere near so sophisticated as is being discussed here, no doubt, but a useful utility at the time! |
David J. Ruck (33) 1675 posts |
That’s very green biased, I used to use a rough 3:6:1 ratio to get luminescence or more precisely 0.299, 0.587, 0.114.
That sums to 3570 so 1785 would be threshold, assuming linear gamma. |
Dave Higton (1515) 3584 posts |
I used the coefficients from Rec. ITU-R BT.709-6 section 3.2: 0.2126, 0.7152, 0.0722. Yours are from Rec. ITU-R BT.601-7 section 2.5.1: 0.299, 0.587, 0.114. Which, if either, is correct? It’s only for deciding whether to display lettering in white or black over a background of a given colour. It’s not for calibrating a monitor. So it’s easy to make a bigger deal of it than is warranted. |
Rick Murray (539) 13958 posts |
https://www.faceofit.com/what-is-rec-709-and-601-smpte-c/#Rec_709_vs_Rec_601_difference Given that typical (non-nemo) RISC OS doesn’t have any sort of calibration, and it’s only for picking a text colour, I’d be inclined to suggest that you all are already overthinking this. ;) |
Steve Pampling (1551) 8228 posts |
Think of it this way: |
Rick Murray (539) 13958 posts |
No, it isn’t. Because, as you saw, there are two specifications with different values, which means one would need to use an as-yet undefined API to interpret the future calibration in order to know how best to do this… …particularly as the calibration may well provide its own values – one cannot assume Rec.-anything on a calibrated system, as the intended output device could be a colour laser printer, for example. |
Steve Pampling (1551) 8228 posts |
Does no one ever pass values to such things and just go for the baked in static value? |
Rick Murray (539) 13958 posts |
This is getting off-topic, but SD era things (analogue TV, DVDs, etc) use the Rec. 601 values while HD era things (digital TV, Bluray, etc) use the Rec. 709 values. I think the difference is down to the behaviour of CRT phosphor dots versus LCD/LED screens. But, again, if one is looking at a “colour” in terms of amount of red, green, and blue and trying to determine anything about it… how does one “pass values” to an API that doesn’t exist?
Faulty analogy, as “IP addresses” (fixed or dynamic) are a known known. It’s more like baking in a mini network stack on a device that doesn’t have one, and may or may not ever have one. There is no way of knowing what the future calibration API would look like or whether it would even have SWIs or be something else hanging off the PaletteV vector, or indeed if it would be a part of the OS (wrong!) or ColourTrans (better!). Therefore, until such time as such a thing exists, just do a best guess and leave it at that. Though, to be really sure (and please nemo), one could grab the gamma tables and look up the actual value of the colour there. Why? Well, though I’ve not heard anything about it in a while, there was somebody working on having a “dark mode” RISC OS, so it’s possible that colours could be altered by abusing the gamma tables.
Just to be an annoying git <cough>my specialty</cough>, I feel that the cyan icon is more readable with black text. Your printer is way fancier than mine. Mine just has a tri-colour cartridge in it that reports as “colour” (rather than C, Y, and M). Here’s what my printer returns, as read by my IPP scanner: nameWithoutLanguage : marker-names = "tri-color ink" nameWithoutLanguage : (continued) "black ink" nameWithoutLanguage : marker-colors = "#00FFFF#FF00FF#FFFF00" nameWithoutLanguage : (continued) "#000000" keyword : marker-types = "ink-cartridge" keyword : (continued) "ink-cartridge" integer : marker-low-levels = "2" integer : (continued) "2" integer : marker-high-levels = "100" integer : (continued) "100" integer : marker-levels = "90" integer : (continued) "100" unspecified-octetString: printer-supply = "type=inkCartridge;maxcapacity=100;level=90;class=supplyThatIsConsumed;unit=percent;colorantname=multi-color;" unspecified-octetString: (continued) "type=inkCartridge;maxcapacity=100;level=100;class=supplyThatIsConsumed;unit=percent;colorantname=black;" textWithoutLanguage : printer-supply-description = "Tri-color Cartridge" textWithoutLanguage : (continued) "Black Cartridge" |
Rick Murray (539) 13958 posts |
I’ll just throw this in as looking up via gamma is only a few lines of code… DIM red% 255, green% 255, blue% 255 SYS "OS_CallAVector",red%,green%,blue%,,14,,,,,35 TO ,,,,cl% IF (cl% = 0) THEN FOR l% = 0 TO 255 PRINT l%, red%?l%, green%?l%, blue%?l% NEXT ELSE REM If R4 is not 0 on exit, gamma not supported. ENDIF If |
Dave Higton (1515) 3584 posts |
I’m wondering if debating the number of angels who could dance on the head of a pin might be equally productive. I’ll remind everyone with a slightly fuller story of how this started. I originally wrote the code just using the facilities that the Toolbox provides. The resulting Markers window was all grey-scale. Martin Avison helpfully pointed out a way to get the gadgets to display text on a background of the colour that the printer supplies when asked for its marker status. Clearly this also requires the foreground colour to be altered according to marker colour; black isn’t going to work on black, nor is white on yellow. So it was a simple test for black and switch the foreground colour on that basis alone. When I put a screenshot up, nemo stated that two of the colours were less than half perceived brightness, and that therefore white would work better as a foreground colour on them. This prompted me to search a bit on the Internet and do some experiments in BASIC. It then looked easy to do a weighted sum of the colour values and switch on that basis. The code was easy and is all simple integer arithmetic. I tried it, put in a threshold that was halfway between the lightest dark colour and the darkest light colour, and tried it. The result is what you can see in the second screenshot: black, cyan and magenta get white text; yellow, light cyan and light magenta get black text. And, as I said, I think it looks better. (Interestingly, Martin Avison disagrees; you’ll all have to make up your own minds.) That’s the end of my story. |
nemo (145) 2644 posts |
Well said Dave and thank you. The choice of black or white text on a coloured background is not the place for unwarranted precision nor for ill-informed colorimetric speculation – there are people who do know what they’re doing in this field. But for the record because it’s not entirely off-topic: Your monitor is, without doubt, designed for sRGB reproduction. sRGB uses the R709 primaries and a multipart gamma curve which leads to a great deal of misunderstanding. The curvy part has a power of 2.4 but there’s a small linear part too. Now if you’re fiddling 8b gamma components to get 8b linear components then you can ignore the multipart nature of the sRGB gamma map and use a simple power curve (which is what I imagine most of you think of as gamma). In which case the closest approximation is 2.2, NOT 2.4 – a common mistake. There are two ways of engineering something – you can employ domain experts who know exactly what they’re doing, or you can employ highly intelligent ignorant people. Acorn were firmly in the latter camp, which occasionally leads to inventing a CPU that’s so efficient it could run on the back EMF from a still-spinning fan, but usually leads to all of the colour, dithering, resizing, alpha-blending and anti-aliasing code getting the wrong result because they didn’t quite get what gamma means. This means, Rick, that the vector call you imagined would help does not help in the slightest. It ain’t that. The only API for reading the gamma of a RISC OS system is Cerilica’s Monitor module, which you probably don’t have:
So you read the system gamma via
[It isn’t even as simple as knowing the ‘power’ of the gamma curve, because you also have to take into account the expected viewer environment correction – the surround. i.e. it’s turtle-shaped curves all the way down.] But basically read the value, use &23333 if the SWI isn’t there, divide by 16384 and use as appropriate (depending on whether you’re trying to work out what the pixel components mean, or trying to work out which pixel components to use). As for the so called “calibration tables” on PaletteV, Rick, they have long been used for visual effects – for a period in RISC OS 4 they were used to fade the screen to black around mode changes in the desktop, for example. As such, though they have been used for “calibration” they’d frequently get mucked up. So the Monitor module implements two sets of curves – a calibration set used for implementing the desired system gamma (and this is manipulated through the extensive Monitor API), and a “user curve” which always has the calibration curve applied to it – so your code does the exact opposite of what you want, and usually would do nothing at all. Just to drive this home: If the PaletteV curve is linear then the monitor will probably be responding with a 2.2 gamma and so reading that curve tells you nothing unless you also apply 2.2 – but in the presence of the Monitor module that would be wrong too. In other words, very much as wrong as it’s possible to be. Sorry. The Monitor module was part of the Nucleus infrastructure and had support for 16b calibration curves. 12b LUTs are not uncommon in actual hardware, and that’s what Nucleus had. 8b curves are fine for visual effects such as fades but not so good for gamma correction, where 10b minimum is needed really. Incidentally, Monitor also includes this SWI:
I have a better version of SoundChannels which abstracts the sound system and allows Oh yeah, and the BreakAche module I released before Christmas not only does the BBC Micro bah-beep when you press the break key, it also dims the screen to near-black via the above call for extra-alarming effect, which only ex-Cerilica customers might have noticed. As hinted at earlier, I am working on a new Colour API which although it won’t simplify anything, will definitely be correct in a complicated way. So there’s that to look forward to. |
Steve Pampling (1551) 8228 posts |
Hmmm? Future? This bit (below) I was expecting to appear, sooner or later (About 2hrs and 20 minutes is quite pleasant):
This was a pleasant surprise:
Perhaps a private email to DH, with a few clues, will occur. |
Rick Murray (539) 13958 posts |
Until it is a standard part of the OS (either built in or widely softloaded like DeepKeys), thile remaining information doesn’t get us any further – it isn’t possible to call an API that isn’t present…
That’s what I was thinking with the dark mode. The simplest way to make that happen is to fudge the colours there (the alternative is screwing with all the windows, sprites, and icons and that’s icky).
Oh, FFS.
On your system with an API that nobody else has, born of necessity due to dumb things being done with the OS API.
Granted, yes, in 99.999recurring% of cases the gamma tables probably do come back as straight 0-255. I have used the gamma tables to set the colours up according to the way PhotoDesk does it, with a slight skew towards red as I found the screen to be a bit too blue for my liking. So colours on my setup won’t be exactly the same as those on David’s, though it’s not a bit enough change to make any material difference in whether the text should be light or dark.
Not at all. It would be nice to have a machine where what’s on screen isn’t entirely unlike what appears on paper. I find it ridiculous that on my phone and with my (admittedly cheap) inkjet, the scanner and the phone screen and the printer all seem to have a different idea of what a colour is (and in the case of the phone there are various options like “vivid”, “standard”, and “saturated”. Anyway, before printing I tend to run pictures through a process to boost the exposure and tone down the blacks (Google Photos isn’t smart enough to understand the concept of gamma) so it doesn’t print way too dark. Kind of hard to believe we’re still putting up with this nonsense in 2025.
Yay! ColourTrans is… (be polite, Rick) lacking. Anyway, I’m going to let this go now that somebody authoritative has entered the room, and I need to cut a path through the grass and must remember to hoik the paddles out of the bread maker before the baking…in fact I think I’ll go do that now or I’ll forget. |
nemo (145) 2644 posts |
Yes it is.
No. You tried to use the visual-effect tables as a way of removing the gamma curve. But as I said a linear table means 2.2 gamma so trying to use the table to linearise components (from luma to luminance) is exactly wrong. I’m sorry I haven’t made this clear. You’ve got the wrong end of a very long stick.
They aren’t gamma tables. Implementation details aside, the 8b RGB pixel values index the LUTs to produce 8b values that go to the monitor that interprets them as sRGB components with a compound gamma curve. All of the Acorn code thinks that the pixel values are linear, when they’re not. The linearity of the LUT means they’re ~2.2 gamma. If you adjust the LUT to remove that gamma curve, the result is that pixel values are linear, so the non-linearity of the LUT makes the pixel values linear, if done correctly. They may instead be making the pixel values black, orange, dim, inverted, or any other visual effect that may temporarily or permanently have been imposed by something on the user’s machine. Those curves don’t tell you anything, hence the necessity for a formal API which has existed for 25 years and was distributed with Vantage. As it happens, Monitor and its calibration utility were on my Christmas Presents list but got bumped off by other more generally interesting things. It seems I should promote it more because
I’m not sure what “the OS” means for a modular operating system with two branches and more than 72 published versions to date. I’m more interested in “the API” of which every published module forms part. Including yours. |
Pages: 1 2