Link to home
Start Free TrialLog in
Avatar of bugroger
bugroger

asked on

Drawing a highlighted bitmap

I want to draw a highlighted bitmap like
the explorer when you select a item (with icon).
Does anyone knows how can i do that?
Avatar of ginsonic
ginsonic
Flag of Romania image

Can you give me more details , please?
listening...
Avatar of bugroger
bugroger

ASKER

more details:

ex.
 When you click on an exe-file in the explorer
 the text changed to clHighlightText/clhighlight
 and the icon from the exe-file will be displayed
 darker.


 How can I "convert" a normal icon/bitmap to such
 a "darker" icon/bitmap?


I found the ImgList_DrawEx function.

With this function you can draw a "selcected Bitmap".
So you can write a function which convert a Bitmap to
a "darker" bitmap.


hello bugroger, here is some code that I used to TRY to simulate the Icon hilighting used in windows explorer windows. This uses a PatBlt with the dwRop set to $A000C9, which might be undocumented, it is a pixel blending dwRop operation. I never got an exact match for the windows highlighting operation, but this was close enough for me to use as a visual image highlighting method.

private
bmp: TBitmap;


procedure TForm1.FormCreate(Sender: TObject);
var
i, k, Dot: Integer;
begin
{this creates a 8x8 bitmap for your Brush, I put it in create because I used this bmp many, many times}
bmp:= TBitmap.Create;
  With bmp Do
  Begin
  width := 8;
  height:= 8;
  PixelFormat := pf24Bit;
  Dot := 0;
  for i:= 0 to 7 do
  begin
    for k:= 0 to 7 do
    if ((k+ Dot) mod 2) <> 0 then
    canvas.Pixels[k,i] := clSilver
    else
    canvas.Pixels[k,i] := GetSysColor(COLOR_HIGHLIGHT)};
{if you don't need the same color highlight as windows, you can try clGray here or your own color}
    Inc(Dot)
  end;
    End;

end;

procedure TForm1.Button_HiLiteClick(Sender: TObject);
var
FirstPic: TBitmap;
begin
if OpenpictureDialog1.Execute then
  begin
  FirstPic := TBitmap.Create;
  FirstPic.LoadFromFile(OpenpictureDialog1.FileName);
{if the bitmap is not 24 Bit then colors will be blocky}
  FirstPic.PixelFormat := pf24bit;
{set brush bitmap to the one you created}
  FirstPic.Canvas.Brush.Bitmap := bmp;

{you can try FirstPic.Canvas.Brush.Color := clHighlight ,
 and you don't need the bmp or bitmap brush at all,
but this didn't look close enough to the windows highlight for me}

{this will blend the FirstPic with the bmp brush, and then it's ready to use}
  PatBlt(FirstPic.Canvas.Handle, 0, 0, FirstPic.Width, FirstPic.Height, $A000C9);
  Canvas.Draw(0,0,FirstPic); // use bitmap
  FirstPic.Free;
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
bmp.Free;
end;

- - - - - - - - - - - - - - - - - - - - - -
there must be an undocumented dwRop for the windows highlighting operation, but I couldn't find it.
correction, I should have put this

for k:= 0 to 7 do
    if ((k+ Dot) mod 2) <> 0 then
    canvas.Pixels[k,i] := $00AAAAAA
    else
    canvas.Pixels[k,i] := clHightLight;
I have written my own function to highlight a bitmap.
I have used ALPHA-BLENDING to realized that.

NewRed    = Rs*Sr+Rd*Dr
NewGreen  = Gs*Sg+Gd*Dg
NewBlue   = Bs*Sb+Bd*Db
NewFactor = As*Sa+Ad*Da

  Rs=FactorSourceRed    | Sr=SourceRed     |
  Rd=FactorDestRed      | Dr=DestRed

  Gs=FactorSourceGreen  | Sg=SourceGreen   |
  Gd=FactorDestGreen    | Dg=DestGreen
     
  Bs=FactorSourceBlue   | Sb=SourceBlue    |
  Bd=FactorDestBlue     | Db=DestBlue

  As=FactorSourceFactor | Sa=SourceFactor  |
  Ad=FactorDestFactor   | Da=DestFactor


//Alpha 0.0 - 1.0
Procedure BlendWithColor(Src, Dest : TBitmap; BlendColor : TColor; Alpha : Real);
TYPE
 TRGB = record
         r, g, b, PALType : Byte;
        end;
 TpRGB = packed record
          b, g, r : Byte;
         end;

VAR
 BlendColorChannels : TRGB;
 DestRGBPixel       : ^TpRGB;
 SrcRGBPixel        : ^TpRGB;
 y, x               : Integer;
 SourceColorFaktor  : real;

Begin
 //Set BitPerPixel -> 24Bit
 Src.PixelFormat  := pf24Bit;
 Dest.PixelFormat := pf24Bit;
 Dest.Width       := Src.Width;
 Dest.Height      := Src.Height;


 //Get RGB-Channels from Color
 BlendColorChannels := TRGB(BlendColor);
 IF BlendColorChannels.PalType = 128 then
  BlendColorChannels := TRGB(GetSysColor((BlendColor AND $0000FFFF)));

 //Get SourceColorFaktor
 SourceColorFaktor := 1.0 - Alpha;

 //Get all Pixels
 For y := 0 to Dest.Height -1 do
 Begin
  //Get Pixel
  SrcRGBPixel  := Src.ScanLine[y];
  DestRGBPixel := Dest.ScanLine[y];
  For x := 0 to Dest.Width -1 do
  Begin
   DestRGBPixel.r := Round(SourceColorFaktor * SrcRGBPixel.r  + Alpha * BlendColorChannels.r);
   DestRGBPixel.g := Round(SourceColorFaktor * SrcRGBPixel.g  + Alpha * BlendColorChannels.g);
   DestRGBPixel.b := Round(SourceColorFaktor * SrcRGBPixel.b  + Alpha * BlendColorChannels.b);
 
   //Set Pointer to next Pixel
   Inc(DestRGBPixel);
   Inc(SrcRGBPixel);
  End;
 End;
End;
well bugroger, I like your code and it works real good, but its not an exact match for the windows icon highlighting effect, at least not on my puters. I got very close results with the alpha set to  .61 - I added a line to help the highlighted look with dark colors

For x := 0 to Dest.Width -1 do
 Begin
  if SrcRGBPixel.r + SrcRGBPixel.g + SrcRGBPixel.b < 64 then
  begin
  DestRGBPixel.r := SrcRGBPixel.r;
  DestRGBPixel.g := SrcRGBPixel.g;
  DestRGBPixel.b := SrcRGBPixel.b;
  end else
  begin
  DestRGBPixel.r := Round(SourceColorFaktor * SrcRGBPixel.r  + Alpha * BlendColorChannels.r);
  DestRGBPixel.g := Round(SourceColorFaktor * SrcRGBPixel.g  + Alpha * BlendColorChannels.g);
  DestRGBPixel.b := Round(SourceColorFaktor * SrcRGBPixel.b  + Alpha * BlendColorChannels.b);
  end;
  //Set Pointer to next Pixel
  Inc(DestRGBPixel);
  Inc(SrcRGBPixel);
 End;

- - - - - - -
good work
Here is my new code to get an exact match
for the "windows icon highlighting effect."

I have used ROUND(INT(......))...

 For y := 0 to Dest.Height -1 do
 Begin
  //Get Pixel
  SrcRGBPixel  := Src.ScanLine[y];
  DestRGBPixel := Dest.ScanLine[y];
  For x := 0 to Dest.Width -1 do
  Begin

    DestRGBPixel.r := ROUND(INT(SourceColorFaktor *     SrcRGBPixel.r  + BlendingColorFaktor *        BlendColorChannels.r));
    DestRGBPixel.g := ROUND(INT(SourceColorFaktor *      SrcRGBPixel.g  + BlendingColorFaktor *       BlendColorChannels.g));
    DestRGBPixel.b := ROUND(INT(SourceColorFaktor * SrcRGBPixel.b  + BlendingColorFaktor * BlendColorChannels.b));

   //Set Pointer to next Pixel
   Inc(DestRGBPixel);
   Inc(SrcRGBPixel);
  End;
 
ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Actually, if you look very carefully at a "selected" icon you can see that it's just had a mask drawn over it like this:

* * * * * * * *
 * * * * * * *
* * * * * * * *
 * * * * * * *
* * * * * * * *
 * * * * * * *
* * * * * * * *

where the spaces are transparent & the *'s are dark blue.  You could (if you've already got the "checkerboard" mask) do this with a couple of blts:

bmp.canvas.copyMode := cmMergeCopy;
bmp.canvas.draw(0,0,mask_bmp);
bmp.canvas.copymode := cmMergePaint;
bmp.canvas.draw(0,0,mask_bmp);


GL
Mike