5

According to MS KB entry, there is a quirk in CreateIconIndirect which recognizes HBITMAPs been created with BITMAPV5HEADER passed to CreateDIBSection (and BGRA channel layout).

However, TBitmap instances with (PixelFormat = pf32bit) and (AlphaFormat = afDefined) (behaving as alpha blended for the other purposes) when referred by its Handles are not being recognized as valid alpha blended bitmaps for creation of icons or cursors.

Currently, I have to create a full copy of TBitmap using described API calls (see) to make CreateIconIndirect accept a bitmap handle as alpha blended. How do I overcome this clumsiness?

OnTheFly
  • 2,059
  • 5
  • 26
  • 61

1 Answers1

8

Here is an example:

procedure TForm1.Button1Click(Sender: TObject);
const
  crAlpha = TCursor(-25);
var
  Bmp: TBitmap;
  Px: PRGBQuad;
  X, Y: Integer;

  BmpMask: TBitmap;
  II: TIconInfo;
  AlphaCursor: HCURSOR;
begin
  Bmp := TBitmap.Create;
  Bmp.PixelFormat := pf32bit;
  Bmp.Canvas.Brush.Color := clWhite;
  Bmp.SetSize(32, 32);
  Bmp.Canvas.Font.Style := [fsBold];
  Bmp.Canvas.Font.Color := clRed;
  Bmp.Canvas.TextOut(1, 10, 'alpha');

  for Y := 0 to (Bmp.Height - 1) do
  begin
    Px := Bmp.ScanLine[Y];
    for X := 0 to (Bmp.Width - 1) do begin
      if DWORD(Px^) = DWORD(clWhite) then
        Px.rgbReserved := $00
      else
        Px.rgbReserved := $FF;
      Inc(Px);
    end;
  end;

  BmpMask := TBitmap.Create;
  BmpMask.SetSize(Bmp.Width, Bmp.Height);

  II.fIcon := False;
  II.xHotspot := 32;
  II.yHotspot := 32;
  II.hbmMask := BmpMask.Handle;
  II.hbmColor := Bmp.Handle;

  AlphaCursor := CreateIconIndirect(II);
  Win32Check(AlphaCursor <> 0);
  BmpMask.Free;
  Bmp.AlphaFormat := afDefined;  // AlphaBlend below, premultiply channels
  Canvas.Draw(0, 0, Bmp);        // test draw
  Bmp.Free;

  Screen.Cursors[crAlpha] := AlphaCursor;
  Cursor := crAlpha;

end;


sample image (Top 'alpha' is test draw, the other is a cursor)

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • I'd set opacity channel to $FF/2 for illustrative purpose :) Beside of that, now I'm really confused because my VCL-based code attempt is almost the same as yours, except I'm trying to load pf32bit DIB with alpha channel and KABOOM! partial transparency got lost eg. inserting the following at line 32 breaks transparency: Bmp.LoadFromFile('[test.dib](http://tmp.is-great.org/test.dib)'); Assert(Bmp.AlphaFormat = afDefined); – OnTheFly Oct 28 '12 at 21:21
  • @user - AlphaFormat is a VCL enumeration (it just tells VCL whether it should apply pre-multiplication), it is not something that is stored with the file - that assertion should of course fail. But leave AlphaFormat alone and AFAICS your dib becomes a cursor preserving its transparency with the example code. – Sertac Akyuz Oct 28 '12 at 21:58
  • Here is it: http://www.everfall.com/paste/id.php?f2c6atbrjrk6 It looks like there is something special with real example as opposed to synthetic example... – OnTheFly Oct 28 '12 at 22:06
  • @user - Works fine here (when I replace 'test.dib' with 'c:\temp\test.dib' (where I put it)). – Sertac Akyuz Oct 28 '12 at 22:11
  • @user - I can't tell what's wrong by looking at the picture (looks fine to me). – Sertac Akyuz Oct 28 '12 at 23:05
  • Here is a better screenshot showing resulting HICON in the TImage control with transparency grid - http://i.imgur.com/shVx5.png – OnTheFly Oct 28 '12 at 23:58
  • Yes. Also, note the "horns" of the blue crescent at the top left corner of picture, faint and translucent at the source images, sharp and distinctive at the resulting. (left to right: source PNG from FreeOrion, decoded 32bpp bitmap with alpha, composed icon using basic CreateIconIndirect technique) – OnTheFly Oct 29 '12 at 00:07
  • 1
    I think you need to remove the `Bmp.AlphaFormat := afDefined;` line altogether when loading the bitmap from a file (also mentioned in my first comment). Regardless, I'd hardly call that *"not being recognized as valid alpha blended bitmaps"*. – Sertac Akyuz Oct 29 '12 at 00:15
  • 1
    .. or set PixelFormat to pfDevice before setting AlphaFormat (which would copy the bitmap to a DDB) – Sertac Akyuz Oct 29 '12 at 00:47
  • 1
    Hm, setting `AlphaFormat` to `afIgnored` removes that sharpness effect in the both resulting icons and cursors. That is, to draw alpha blended bitmap afDefined is required, but CreateIconIndirect wants afIgnored (??). This appears little counter intuitive for me. Do you know why this might happen? – OnTheFly Oct 29 '12 at 00:47
  • I am not sure 'afDefined' is correct when loading from a file, maybe the file is written with premultiplied alpha. Nevertheless, why it should be different drawing a bitmap or creating an icon/cursor, that I don't know. – Sertac Akyuz Oct 29 '12 at 00:53
  • If you noticed that whole bunch of buttons - I did tests for all of the combinations :-) Anyway, problem seems to be resolved with your valuable assistance. Thanks! – OnTheFly Oct 29 '12 at 01:02
  • I came here wondering what a 1bpp icon mask would look like. Raymond Chen [has a blog entry a few years ago](http://blogs.msdn.com/b/oldnewthing/archive/2010/10/21/10078690.aspx). People would construct the 32-bpp, pre-multiplied alpha bitmap. *"you are still required to provide a mask. I've seen some people be a bit lazy about providing a meaningful mask and just pass in all-zeroes. And everything seems to work just fine, until you hit a case where it doesn't work.) talking about people"*. Looks like the example here was just `TBitmap.Create`, set size, and ignore the mask. – Ian Boyd Jun 02 '14 at 14:29
  • @Ian - If you think you'll be able to have a 1 bit mask that makes sense for a partially transparent image, then go ahead and fill your mask. – Sertac Akyuz Jun 02 '14 at 17:34