Brett Wraight has asked for the wisdom of the Perl Monks concerning the following question:

Trying to convert a number color to hex

I know how to do for RGB to hex this is easy.

But I am using win32::GUI with the standard color chart
selector and what I get is a number for example

red is 255
white is 16777215

Is there a way to convert this to rgb or to hex?

the wi32 color selector goes like this....

i.e

##information about the color selected
sub Color_Click
{
$color = Win32::GUI::ChooseColor();
print $color
}
Many thanks

Replies are listed 'Best First'.
Re: Color Converstion
by pg (Canon) on Jan 15, 2004 at 04:13 UTC

    On win32, a color is defined as a 24-bit number, bits 23 to 16 define B, bit 15 to 8 define G, and bit 7 to 0 define R. see this web page for details.

    The formula you want is: (B * 256 + G) * 256 + R. You can wrap it in a sub.

    use strict; use warnings; print rgb(255,255,255), "\n"; #this gives you 16777215 print sprintf("0x%x", rgb(255,255,255)), "\n"; print rgb(255,0,0), "\n"; print sprintf("0x%x", rgb(255,0,0)), "\n"; sub rgb { return ($_[2] * 256 + $_[1]) * 256 + $_[0]; }
Re: Color Converstion
by Zaxo (Archbishop) on Jan 15, 2004 at 04:19 UTC
    If that red is accurate, it appears that microsoft lists its colors in BGR (relentlessly little-endian?).
    # my @rgb = reverse unpack 'xCCC', $colornum; #wrong my @rgb = ( $colornum & 255, $colornum >> 8 & 255, $colornum >> 16 & 255 }; my $hex = join '', map {sprintf '%x', $_} @rgb; print "#${hex}";

    Update: Oops, corrected code

    After Compline,
    Zaxo

Re: Color Converstion
by Roy Johnson (Monsignor) on Jan 15, 2004 at 15:56 UTC
    This will give you three hex numbers.
    my ($b,$g,$r) = sprintf('%06x', $color) =~ /(..)/g;
    This will give you a single hex RGB value:
    my $hexrgb = join '', reverse sprintf('%06x', $color) =~ /(..)/g;

    The PerlMonk tr/// Advocate
Re: Color Converstion
by bart (Canon) on Jan 16, 2004 at 00:28 UTC
    pack/unpack have a few rather strange templates for processing partial bytes, optionally with reversed output, namely 'b', 'B', 'h', and 'H', and one of them comes in handy here. The next appears to work:
    my $R = 0xF1; my $G = 0xE2; my $B = 0xD3; my $rgb_int = $R + ($G<<8) + ($B <<16); my $rgb_hex = uc unpack 'H6', pack 'V', $rgb_int; print $rgb_hex;
    Result:
    F1E2D3
    
    The way it works is by packing the long integer into a 4-byte binary string containing a Little Endian integer (red is first byte); and then unpack the first 3 bytes (= 6 nybbles, a nybble is half a byte) into a hex string, the higher nybble per byte coming first.

    "h" swaps order of the nybbles per byte; "B" and "b" respectively do the same in binary, "B" running from the higher to the lower bit, and "b" from low to high.