Recent

Author Topic: [Solved] How to obtain the complementary color of a TColor ?  (Read 1561 times)

devEric69

  • Full Member
  • ***
  • Posts: 158
Hi,

I was using the Jedi's method JvgUtils.ComplementaryColor(AColor: TColor): TColor; , under Delphi.
Is there an equivalent in FPC or LCL packages?
« Last Edit: July 18, 2019, 02:44:01 pm by devEric69 »
use: Ubuntu 18.04 + Laz. 1.8.5 + FPC 3.0.5 (64 bits).

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7589
Re: How to obtain the complementary color of a TColor ?
« Reply #1 on: July 17, 2019, 02:51:01 pm »
jedi is third party, just port the relevant parts?

wp

  • Hero Member
  • *****
  • Posts: 6454
Re: How to obtain the complementary color of a TColor ?
« Reply #2 on: July 17, 2019, 06:14:09 pm »
I was search through all the sources in jvcl (https://github.com/project-jedi/jvcl/tree/master/jvcl/run). The current repository does not contain a unit JvgUtils any more; an older one which I have on my HD has it but it is lacking a function "ComplementaryColor". Please be more specific where to find it.

But when my understanding of "complementary color" is the same as theirs then why don't you just simply use
Code: Pascal  [Select]
  1. uses
  2.   Graphics;
  3.  
  4. function ComplementaryColor(AColor: TColor): TColor;
  5. begin
  6.   Result := RGBToColor(255 - Red(AColor), 255- Green(AColor), 255 - Blue(AColor));
  7. end;

A bit more refined version is "InvertColor" in unit Graphics.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

circular

  • Hero Member
  • *****
  • Posts: 3047
    • Personal webpage
Re: How to obtain the complementary color of a TColor ?
« Reply #3 on: July 17, 2019, 09:59:16 pm »
Or this:
Code: Delphi  [Select]
  1. function ComplementaryColor(AColor: TColor): TColor;
  2. begin
  3.   Result := clWhite - ColorToRGB(AColor);
  4. end;
Conscience is the debugger of the mind

garlar27

  • Hero Member
  • *****
  • Posts: 621
Re: How to obtain the complementary color of a TColor ?
« Reply #4 on: July 17, 2019, 11:20:24 pm »
Or this:
Code: Delphi  [Select]
  1. function ComplementaryColor(AColor: TColor): TColor;
  2. begin
  3.   Result := clWhite - ColorToRGB(AColor);
  4. end;
This is in case you need the complementary of the light color palette. If you need the complementary for the ink color palette then I think you should use CMYK (Cyan Magenta Yellow and Ink) colors, and I don't know well how to use them since I'd never programed using that palette.

winni

  • Hero Member
  • *****
  • Posts: 559
Re: How to obtain the complementary color of a TColor ?
« Reply #5 on: July 18, 2019, 12:22:21 am »
RGB and CMYK are linear converted. In theory you need only CMY to paint (print) everything, but 100% of CMY only gives an ugly gray-brown. So for printing you need the K (Kontrast = ink).

For converting RGB to CMYK see the following procedure. Notice that the resulting values of C,M,Y and K are in the range of 0..255 - not 0..100!!

Code: Pascal  [Select]
  1.  
  2. procedure RGBtoCMYK(r,g,b: byte; var c,m,y,k : byte);inline;
  3. var r1,g1,b1,c1,m1,y1,k1 : single;
  4.  
  5.     begin
  6.       r1 := r/255;
  7.       g1 := g/255;
  8.       b1 := b/255;
  9.       k1 := max(r1,g1);
  10.       k1 := max(k1,b1);
  11.       k1 := 1-k1;
  12.       if k1 = 1 then
  13.          begin
  14.           c1 := 0; m1 := 0; y1 := 0;
  15.          end else
  16.          begin
  17.            c1 := (1-r1-k1) / (1-k1);
  18.            m1 := (1-g1-k1) / (1-k1);
  19.            y1 := (1-b1-k1) / (1-k1);
  20.          end;
  21.       c := round(c1*255);
  22.       m := round(m1*255);
  23.       y := round(y1*255);
  24.       k := round(k1*255);
  25.     end;
  26.          
  27.  

Enough info?

Winni

devEric69

  • Full Member
  • ***
  • Posts: 158
Re: How to obtain the complementary color of a TColor ?
« Reply #6 on: July 18, 2019, 11:54:12 am »
@wp: sorry for forgetting to mention the Jedi version number.
@others: thank you for your answers.

I had the same result (but not as well, in 3..a few lines :) ):
Code: Pascal  [Select]
  1. uses
  2.   Graphics, FPImage;
  3.  
  4. function CompementaryColor2(AColor: TColor): TColor;
  5. var
  6.   aRGB: record
  7.     iRed, iGreen, iBlue: Byte;
  8.   end;
  9.   aFPColor: TFPColor;
  10.   aColorRef: TColorRef;
  11. begin
  12.   aFPColor:= TColorToFPColor(AColor);
  13.   aColorRef:= FPColorToTColorRef(aFPColor);
  14.   //(1) verification of RGB components, from the basic AColor composite
  15.   with aRGB do begin
  16.     iRed:= Graphics.Red(aColorRef);
  17.     iGreen:= Graphics.Green(aColorRef);
  18.     iBlue:= Graphics.Blue(aColorRef);
  19.   end;
  20.   Form1.lblRedBase.Caption:= 'RedBase: ' + IntToStr(aRGB.iRed);
  21.   Form1.lblGreenBase.Caption:= 'GreenBase: ' + IntToStr(aRGB.iGreen);
  22.   Form1.lblBlueBase.Caption:= 'BlueBase: ' + IntToStr(aRGB.iBlue);
  23.   //(2) obtain the complements of the RGB components, from the basic AColor composite
  24.   with aRGB do begin
  25.     iRed:= 255 - Graphics.Red(aColorRef);
  26.     iGreen:= 255 - Graphics.Green(aColorRef);
  27.     iBlue:= 255 - Graphics.Blue(aColorRef);
  28.   end;
  29.   (* Form1.lblRedCompl:= 'RedCompl: ' + ; Form1.lblGreenCompl:= 'GreenCompl: ' + ; Form1.lblBlueCompl:= 'BlueCompl: ' + ; *)
  30.   result:= RGBToColor(aRGB.iRed, aRGB.iGreen, aRGB.iBlue);
  31. end;  
       

But, I have the following comprehension problem; when I code...:
Code: Pascal  [Select]
  1. procedure TForm1.Button2Click(Sender: TObject);
  2. var
  3.   aBaseColor: TColor;
  4. begin
  5.   aBaseColor:= TColor($AA6239); //with $00AA6239, I get the same result; //with $AA623900, this color is a light grey, not the brown displayed by websites
  6.   Panel1.Color:= aBaseColor;
  7. end;
... then, I will check on https://www.colorhexa.com/aa6239: I don't see the same color, as the one on the TForm??!
However, when I take a calculator, I get:
Red = $aa = 170.
Green = $62 = 98.
Blue = $39 = 57.

Nevertheless, Free Pascal tells me, that:
Code: Pascal  [Select]
  1. with aRGB do begin
  2.     iRed:= Graphics.Red(aColorRef); // == 57.
  3.     iGreen:= Graphics.Green(aColorRef); // == 98.
  4.     iBlue:= Graphics.Blue(aColorRef); // == 170.
  5.   end;
==> So, iRed and iBlue are reversed (!!?), compared to all tested web sites of colors verification (by entering #aa6239, as in the *.css files).
➔ My question is ( using only simple RGB; no Hue, sensitivity, ..., ink that I don't know yet ): why this inversion :( ( i.e. how to get from $aa6239 in Free Pascal, the same color on a TForm as #aa6239 displayed by the *.css and Javascript )?
« Last Edit: July 18, 2019, 01:33:46 pm by devEric69 »
use: Ubuntu 18.04 + Laz. 1.8.5 + FPC 3.0.5 (64 bits).

circular

  • Hero Member
  • *****
  • Posts: 3047
    • Personal webpage
Re: How to obtain the complementary color of a TColor ?
« Reply #7 on: July 18, 2019, 01:27:29 pm »
Indeed TColor written in hex is swaped compared to #...

In binary that makes sense because the first bits are the ones on the right of the number.

You need to swap red and blue if you write as if it was #...

Code: Delphi  [Select]
  1. function SwapRedBlue(AColor: TColor): TColor;
  2. begin
  3.   Result := RGBToColor(Blue(AColor), Green(AColor), Red(AColor));
  4. end;
  5.  
  6. ...
  7.  
  8. Panel1.Color := SwapRedBlue($AA6239);
  9.  
Conscience is the debugger of the mind

devEric69

  • Full Member
  • ***
  • Posts: 158
Re: How to obtain the complementary color of a TColor ?
« Reply #8 on: July 18, 2019, 02:05:27 pm »
Thank you very much, circular, for your technical clarification, and your function\trick...
...which poses 2 problems for a basic Lazarus user, with the semantic:
- the TColor type could have a synonym named TBGRColor for exemple (but it's falsely clever, right?).
- some graphics.pas functions are bug traps, always because of semantics: they are called function xxxRGByyyy(R, G, B: Byte): TThis;, eg function RGBToColor(R, G, B: Byte): TColor; (the naming \ order of parameters is also a trap).

So - I'm asking the moderators (I have no vision at all of the involvement of these methods in the LCL) - first of all, what do I do?
A bug (or modification?) report with this hyperlinked thread? Nothing?
« Last Edit: July 18, 2019, 02:20:55 pm by devEric69 »
use: Ubuntu 18.04 + Laz. 1.8.5 + FPC 3.0.5 (64 bits).

wp

  • Hero Member
  • *****
  • Posts: 6454
Re: How to obtain the complementary color of a TColor ?
« Reply #9 on: July 18, 2019, 02:24:57 pm »
This leads to the elemental issue with "little endian" and "big endian" byte order: look at the number 256 - this is $01FF in hex. However, when this value is stored on a file by an Intel processor you'll the the bytes in the order FF 01. When you store to file with a Motorola processor you'll find the bytes in the "correct" order 01 FF.

Some file formats store the rgb bytes in the order r-g-b, others in b-g-r, and when there is a forth alpha channel byte it gets even more compilcated.

Confusing? Yes.

So, please: no error in the graphics unit. It's just a matter of convention - and to listen to the alarm clock in your head when you try to determine the rgb components out of a "color".
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

devEric69

  • Full Member
  • ***
  • Posts: 158
Re: How to obtain the complementary color of a TColor ?
« Reply #10 on: July 18, 2019, 02:43:31 pm »
All right: thank you for the explanations \ arguments.
I will think about increasing the volume of the alarm clock in my head, when I'll use a TColor (should I resonate contextually with the TColor , thinking about TRGBColor or TBGRColor ?).

PS: by the way, your complementary color algorithm is correct.
use: Ubuntu 18.04 + Laz. 1.8.5 + FPC 3.0.5 (64 bits).

wp

  • Hero Member
  • *****
  • Posts: 6454
Re: How to obtain the complementary color of a TColor ?
« Reply #11 on: July 18, 2019, 03:37:21 pm »
bby the way, your complementary color algorithm is correct.
In this case you should use circular's routine (reply #3), it is much more efficient and does exactly the same.
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

Thaddy

  • Hero Member
  • *****
  • Posts: 9278
Re: [Solved] How to obtain the complementary color of a TColor ?
« Reply #12 on: July 18, 2019, 04:38:53 pm »
You can probably use a cast a mask and the not operator? Should be faster than subtraction. It does a bit-wise negation.
also related to equus asinus.

devEric69

  • Full Member
  • ***
  • Posts: 158
Re: [Solved] How to obtain the complementary color of a TColor ?
« Reply #13 on: July 18, 2019, 06:32:23 pm »
Quote
You can probably use a cast a mask and the not operator?

Too complicated for me %) .

The main thing, is that I didn't understand that ( déjà vu ):
To call or not to call SwapRedBlue depends from my material context, and the purpose of this call:
- depending on the CPU processor type (Motorola versus Intel), I will write - in a file - AColor's RGB in that order ie RGB; or inversed ie BGR (cross-compilation problems are not yet fully in my head).
- depending on the logic of use: let's say I found a pretty #aabbcc color on a website, i.e. a hexdecimal representation in @string format ==> it means that Red='#aa', Green='#bb', and Blue='#cc'. If you want to assign this same compiled color, then $aabbcc to a Canvas property, it will not work: indeed, the binary bits are read from right to left (as @circular pointed out). So, the compiled equivalent will have to be: Red=$cc, Green=$bb Blue=$cc (lately, I've been developing with interpreted Javascript code).

PS: another simple manipulation of the bytes, to obtain 3 differents colors - which contrast with each other at most - is the "triadic color scheme": if color_base=aabbcc ==> triad_1=bbccaa, triad_2=ccaabb.
« Last Edit: July 18, 2019, 07:04:50 pm by devEric69 »
use: Ubuntu 18.04 + Laz. 1.8.5 + FPC 3.0.5 (64 bits).

winni

  • Hero Member
  • *****
  • Posts: 559
Re: [Solved] How to obtain the complementary color of a TColor ?
« Reply #14 on: July 18, 2019, 06:54:02 pm »
You have too check first, which convention is used:

* HTML writes the hex code in Motorola format
* The GIMP shows the color hex code in Motorola Format

So if you take a color code from HTML or the  GIMP you have to swap red and blue.

Easy test: Fill something with color = $FF
If it is red you are on an Intel machine.
Otherwise if it is blue you are on a motorala maschine

Winni
« Last Edit: July 18, 2019, 09:20:36 pm by winni »