1

I am trying to draw a source image (GR32 TBitmap32) that contains some fully transparent and also partially transparent pixels on a normal (TBitmap) image while preserving the transparency in the source image.

I use this:

BMP32.DrawTo(BMP.Canvas.Handle, 0, 0);

but the image is not drawn transparently.


Code:
Everything is pretty basic: I have a background bitmap (Bkg) in which I load, at application start up, an image. Then in procedure Apply I load a second image from disk (the one with transparency) and I draw the it over the background.

var Bkg: TBitmap;

procedure TfrmPhoto.FormCreate(Sender: TObject);
begin
 Bkg:= LoadGraphEx(GetAppDir+ 'bkg.bmp'); { Load bitmap from file }
 {
 Bkg.Transparent:= TRUE;
 Bkg.PixelFormat:= pf32bit;
 Bkg.TransparentColor:= clPink;
 }
end;


procedure TfrmPhoto.Apply2;
VAR
   Loader: TBitmap;
   BMP32: tbitmap32;
begin
 BMP32:= TBitmap32.Create;
 TRY

  Loader:= TBitmap.Create;
  TRY
   Loader.LoadFromFile('c:\Transparent.BMP');
   BMP32.Assign(Loader);
  FINALLY
   FreeAndNil(Loader);
  END;

  { Mix images }
  BMP32.DrawTo(Bkg.Canvas.Handle, 0, 0);    <----- The problem is here

  imgPreview.Picture.Assign(Bkg);    { This is a TImage where I see the result }
 FINALLY
  FreeAndNil(BMP32);
 END;
end;
Aziz Shaikh
  • 16,245
  • 11
  • 62
  • 79
Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • Would it be too much to ask for an SSCCE? – David Heffernan Jan 30 '14 at 17:38
  • Edit your question please : add the tag of your Delphi version and show how you enable and set up transparency mode for your 32 bits per pixel stock TBitmap – Arioch 'The Jan 30 '14 at 17:48
  • Added source code. LoadGraphEx can be replaced with LoadFromFile(''). Otherwise, the project should be compilable. – Gabriel Jan 30 '14 at 18:15
  • There is an example in GR32 in which they draw a rotated image over a background. However, they use a bitmap32 also for the background! They don't combine bitmap with bitmap32 as I do. I have no clue about how am I supposed to combine these two images (transparently). Also, I couldn't find among their examples a concrete example about how to do this. – Gabriel Jan 30 '14 at 18:20
  • If all you do is combining, then maybe you should move TBitmap -> TBitmap32 rather than opposite direction ? Maybe you should just make it different than you wanted? – Arioch 'The Jan 30 '14 at 21:13
  • `BMP32.DrawTo(Bkg.Canvas.Handle` - try to make TBitmap transparent, 32 bits per pixel not 24. And Transparent. And Transparent mode to Auto. Idea: you take an empty TImageList, and you load half-transparent (that is some pixels have like 50% of color and 50% of transparency) pictures into it, like "Fugue" PNG icons pack. Then you explore what internal bitmap inside TImageList was arranged to hold that half-transparency half-tone pixels. – Arioch 'The Jan 30 '14 at 21:17
  • also can you use TIcon instead of TBitmap ? TImageList has GetBitmap method, but it does not provide transparency. However GetIcon method of it does export the transparent pictures. Maybe that example can lead you to something – Arioch 'The Jan 30 '14 at 21:24
  • @Arioch'The- Bitmap32 has a AssignTo method but unfortunately is protected. So, I don't think was intended to be used to transfer the image to a classic Tbitmap. – Gabriel Jan 30 '14 at 22:22
  • @Arioch'The- I have tried to change the color depth but with no success. – Gabriel Jan 30 '14 at 22:29
  • @Altar color depth is only step 1. After that you have to - quote - "enable (1) and set up (2) transparency mode for your 32 bits per pixel stock TBitmap". Really, read TImageList sources how does it load semi-transparent PNGs – Arioch 'The Jan 31 '14 at 09:09
  • "AssignTo method but unfortunately is protected." That is true for every Delphi object. It a backbone implementation of a public .Assign method. Also to assign into TBitmap32 from TBitmap you do no need AssignTo, the directio nis opposite – Arioch 'The Jan 31 '14 at 09:11

3 Answers3

5

It worked (but with 2 disadvantages) with TransparentBlt().

  1. I am not happy with the way TransparentBlt handles the semitransparent pixels (the edge of the rotate image). After merging the src image into the background the edges look bad.

  2. In order to use TransparentBlt, I had to define a color (clPink) in the source image as transparent. This means that if the source image has some pink in it, the result will look really nasty (it will be treated as transparent). Let's pray for non-pink images!

If you find a way to transfer the image (while preserving transparency) directly from Bitmap32 into the background please post and I will accept your answer!

A solution (still a hack) I see here is to process everything in a TBitmap32 and then 'export' the final result as TBitmap. I will try this tomorrow.


Update:
Solution:

This is how to merge two TBitmap32 images while preserving transparency:

 Dst.CombineMode:= cmBlend;
 Dst.DrawMode:= dmBlend;
 Src.Draw(0, 0, Dst);  

Dst and Src are TBitmap32 images. It doesn't work with TBitmap.

Gabriel
  • 20,797
  • 27
  • 159
  • 293
4

As already suggested by yourself, I would recommend performing blending operations entirely in the TBitmap32 domain! The reason for this is the fact that it offers more choices in regards of blending and it uses MMX/SSE/SSE2 where available (on modern machines always the case). With this one can typically get a notable performance boost in contrast to letting GDI perform the blending.

In particular this is not a good idea as GDI typically does not make use of any SIMD opcodes (MMX/SSE).

It also depends on how much each part changes. For example, typically the background is rather static and need to be transfered into a TBitmpa32 only occassionally on changes (e.g. on VCL style or UI theme changes). With each transfer (GR32 <-> TBitmap and alike) an implict conversion (DIB <-> DDB) might happen, which makes the entire blending an O(n²) operation. So you'd better transfer (with an implicit conversion) to TBitmap32 just once and then perform the blending entirely in the GR32 domain.

On the contrary, if the TBitmap32 is rather static and the TBitmap (or background) changes a lot, it might probably be better to leave GR32 alone and copy the TBitmap32 to TBitmap and perform the blending with GDI. Despite the fact that the GDI blending is slightly slower, you avoid the additional copy. Otherwise your bottleneck will likely be the memory throughput, while processing speed never can touch the limits.

CWBudde
  • 1,783
  • 1
  • 24
  • 28
1

It is dmBlend DrawMode of TBitmap32 to turn on the transparency, but it only works between two TBitmap32 bitmaps. Do not use TBitmap32 with transparent images to draw directly on HDC, Canvas or TBitmap. Use dmBlend and DrawTo or BlockTransfer() to draw on another TBitmap32. For example, to draw transparently on a TBitmap, create an intermediary cache TBitmap32:

  1. Copy the image from TBitmap to the cache TBitmap32;
  2. Apply your transparent image to the cache TBitmap32 using DrawTo or BlockTransfer(), avoid using Canvas or HDC to mix two images because they lose alpha layer information;
  3. Copy the image back from the cache TBitmap32 to your TBitmap.
Maxim Masiutin
  • 3,991
  • 4
  • 55
  • 72