Solved

draw an image semi-transparent upon another

Posted on 1998-02-10
10
221 Views
Last Modified: 2010-05-18
Hi,
I would like to be able to draw an image on top of one
other. But i would be able to se trought it. I don't mean
here the thing with a transparent color. But a formula where
I can state the transparency. If I want the picture 0% transparent, that would mean I can't
see the image in he background. And 100% transparent
would make that I can't see the image in the foreground.
If possible I would like source code.
Any hint someone ?
Jeurk.
0
Comment
Question by:jeurk
10 Comments
 
LVL 4

Expert Comment

by:d003303
ID: 1358879
This can be done with an additional channel to RGB, called alpha channel. It is like a grayscale picture where white means transparent and black means solid. You can store this channel as a separate image.
To draw the transparency, you will have to calculate each pixel. This mainly means you walk through the pixel array of the source, background and transparency mask bitmap and set each RGB value of the destination bitmap (this takes time and should be coded in assembler).

Slash/d003303
0
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1358880
Hi

There must be a much better way of doing this, but here is a function that I wrote, and I have used it quite successfully.  It's a bit slow for big bitmaps (so don't use it for real-time fading animation for 800*600 bitmaps!) but it works really well for animating 32*32 bitmaps on About screens & splash screens!

procedure CombineBmps(Bmp1, Bmp2, ResultBmp: TBitmap; PercentBmp1: Integer);
var
  x, y: Integer;
  NewCol: TColor;
begin
  ResultBmp.Width := Bmp1.Width;
  ResultBmp.Height := Bmp1.Height;
 
  for x := 0 to Bmp1.Width - 1 do
    for y := 0 to Bmp1.Height - 1 do
      begin
        NewCol := GetCombinedColor(Bmp1.Canvas.Pixels[x, y], Bmp2.Canvas.Pixels[x, y], PercentBmp1);
        ResultBmp.Canvas.Pixels[x, y] := NewCol;
      end;
end;

The above procedure uses the following function:

function GetCombinedColor(Col1, Col2: TColor; PercentCol1: Integer): TColor;
var
  RVal1, RVal2, GVal1, GVal2, BVal1, BVal2, NewR, NewG, NewB: Byte;
  PercentCol2: Integer;
begin
  RVal1 := GetRValue(Col1);
  GVal1 := GetGValue(Col1);
  BVal1 := GetBValue(Col1);
  RVal2 := GetRValue(Col2);
  GVal2 := GetGValue(Col2);
  BVal2 := GetBValue(Col2);

  PercentCol2 := 100 - PercentCol1;

  NewR := ((RVal1 * PercentCol1) + (RVal2 * PercentCol2)) div 100;
  NewG := ((GVal1 * PercentCol1) + (GVal2 * PercentCol2)) div 100;
  NewB := ((BVal1 * PercentCol1) + (BVal2 * PercentCol2)) div 100;

  Result := RGB(NewR, NewG, NewB);
end;


As an example, where MyImage is a TImage, and Delay will wait X milliseconds while doing Application.ProcessMessages:
  for i := 0 to 10 do
    begin
      CombineBmps(Bmp1, Bmp2, NewBmp, i * 10);
      MyImage.Picture.Assign(NewBmp);
      Delay(50);
    end;


Regards,
JB
0
 
LVL 5

Expert Comment

by:inter
ID: 1358881
Actually JimBob is RIGHT, and his method is correct. But if you plan to do such thing in medium size bitmaps you may use 24 bit color images and do the operation very very fast. Here is the code: (what slows down the method above is extensive number functions called per pixel but in 24 bit we can get the whole image and do the same)

This function gets 2 24 bit bitmaps and return the resulting image in first bitmap.

procedure MergeBitmaps24(Bitmap1, Bitmap2 : TBitmap; percent : integer);
type
  PByte = ^byte;
  TBITMAPX = packed record // I do not know the name in delphi
   bmType : longint;
   bmWidth: longint;
   bmHeight: longint;
   bmWidthBytes: longint;
   bmPlanes : WORD;
   bmBitsPixel : WORD;
   bmBits : PByte;
  end;

var
  Bitmapbits1, Bitmapbits1 : PByte;
  bminfo : TBitmapX;
  len : longint;
  per1 : integer;
begin
  // assuming that the images are of the same size allocate
  GetObject(Bitmap1.Handle, sizeof(TBitmapX), @bmpinfo);
  BitmapBits1 := bmpinfo.bmBits;
  GetObject(Bitmap2.Handle, sizeof(TBitmapX), @bmpinfo);
  BitmapBits2 := bmpinfo.bmBits;
  // combine them with percent since we work inplace the bitmaps
  // are modified inplace so we need to refresh the bitmaps after
  // wards.
  len := bmpinfo.widthbytes * bmpinfo.height;
  per1 := 100 - percent;
  while len <> 0 do
  begin
    BitmapBits1^ := (percent *BitmapBits1^ + per1 * BitmapBits2^ )div 100;
    Inc(BitmapBits1,1); Inc(BitmapBits2,1);Dec(len);
  end;
  // upon return do not forget to refresh the container of Bitmap1  
end;

Igor
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 4

Author Comment

by:jeurk
ID: 1358882
Salut,
I still not have tryed the thing.
Please be patient ;)

Jeurk
0
 
LVL 4

Author Comment

by:jeurk
ID: 1358883
Ok guys,
I tried the things,
inter, they were some typo in your code ;)
It seems to work. But I have a question,
how do I convert an image to 24 bits ?
Jeurk.
0
 
LVL 5

Expert Comment

by:inter
ID: 1358884
In normal color bitmaps, you now, there is a palette table at the begining of the bitmap after BITMAPINFOHEADER. In 24 bitmap the following applies:

The bitmap has a maximum of 2^24 colors, and the bmiColors member is NULL. Each 3-byte triplet in the bitmap array represents the relative intensities of blue, green, and red, respectively, for a pixel.

So, if we want to convert a 256 color or 16 color bitmap to 24 bit bitmap we should get the palette table and substitude the pixel values as RGB as described above.

Example:

say the following is a partial palette table for 256 color bitmap:
           R   G   B
pal[0] = (100,101,102);
pal[1] = (200,201,202);
pal[2] = (240,241,242);
...
And the data of it goes as
0,0,1,2,1...

The 24 bit equivalent is
pal = nil;

and the data be
102,101,100, 102,101,100, 202,201,200, 240,241,242, 202,201,200...

such that...

What? No I do not have code for this, but I may write it.

The easiest way is to do this with a Painting program. But if you need dynamic, run time conversion, we should do this by hand.

Igor
0
 
LVL 4

Author Comment

by:jeurk
ID: 1358885
OK,
let's say we gonna close the question.
Post an answer inter and you will earn the points.
Thank You for the help.
Thanks goes to You too JimBob. If you want some points
tell me and you will earn some , let's say 60 points ?

CU
0
 
LVL 5

Accepted Solution

by:
inter earned 80 total points
ID: 1358886
Nice to work with you friend,

Igor
0
 
LVL 4

Author Comment

by:jeurk
ID: 1358887
Me too.

Jeurk
0
 

Expert Comment

by:perkley
ID: 3036752
Hey, I read this question and I can't seem to get inter's accepted answer to work.  I know there is typos and I am sure I fixed them correctly, and the code does run, but it doesn't seem to give me any wanted results.

Inter, in the code you mentioned to refresh the container upon return.  I tried Bmp1.Refresh, but Refresh isn't available.  What exactly are you talking about?

Does someone have source code for a full working example of this.  The entire unit source code, not just segments.
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…
Attackers love to prey on accounts that have privileges. Reducing privileged accounts and protecting privileged accounts therefore is paramount. Users, groups, and service accounts need to be protected to help protect the entire Active Directory …

679 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question