🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.delphi.nativeapi.win32
30 messages
30 total messages Started by Ian Boyd Thu, 24 Jul 2008 20:08
How to determine the dimensions of an HICON?
#213
Author: Ian Boyd
Date: Thu, 24 Jul 2008 20:08
20 lines
1519 bytes
i want to draw an icon using:

    DrawIcon(dc, hIcon);

but i first need to know how big the icon (dimensions, not bytes) is.

i looked at GetIconInfo(), but that only gives me the location of the 
hot-spot, the color, and the mask.

Really, i'm trying to write the function:

    function CreateBitmapFromIcon(const icon: HICON): HBITMAP;
    begin
        //Step 2: ???
    end;

i was going to create a 32bpp bitmap, select it into a memdc, use DrawIcon 
to do the drawing (with alpha transparency support).

But i'm stuck at step 1: Create a bitmap. 
Re: How to determine the dimensions of an HICON?
#214
Author: Marc Rohloff [TeamB]
Date: Thu, 24 Jul 2008 20:34
14 lines
1686 bytes
On Thu, 24 Jul 2008 16:08:47 -0400, Ian Boyd wrote:

> i looked at GetIconInfo(), but that only gives me the location of the 
> hot-spot, the color, and the mask.

The color and masks are HBITMAPS, you should be able to pass one into
GetBitmapDimensionsEx to get the size. You could also use the HBITMAPs
to draw on your canvas if necessary.
Don;'t forget that the color bitmap is optional for black and white
icons and that you need to delete the bitmaps when you are done.

-- 
Marc Rohloff [TeamB]
marc -at- marc rohloff -dot- com
Re: How to determine the dimensions of an HICON?
#217
Author: Pieter Zijlstra
Date: Thu, 24 Jul 2008 21:41
28 lines
1656 bytes
Ian Boyd wrote:

> i want to draw an icon using:
> 
>    DrawIcon(dc, hIcon);
> 
> but i first need to know how big the icon (dimensions, not bytes) is.
> 
> i looked at GetIconInfo(), but that only gives me the location of the
> hot-spot, the color, and the mask.
> 
> Really, i'm trying to write the function:
> 
>    function CreateBitmapFromIcon(const icon: HICON): HBITMAP;
>    begin
>        //Step 2: ???
>    end;

You can create a TIcon and use the HICON to set the handle of the just
created Icon class, it should then be possible to retrieve the height
and width of that Icon instance.

If you do have the source have a look at Graphics.pas ->
TIcon.SetHandle to see how that is done and you could come up with your
own solution without using TIcon ... when still needed.

-- 
Pieter
Re: How to determine the dimensions of an HICON?
#218
Author: Chris Rolliston
Date: Thu, 24 Jul 2008 23:26
35 lines
1817 bytes
> i want to draw an icon using:
> 
>    DrawIcon(dc, hIcon);
> 
> but i first need to know how big the icon (dimensions, not bytes) is.
> 
> i looked at GetIconInfo(), but that only gives me the location of the
> hot-spot, the color, and the mask.

Possibly not the most efficient way, but it works for me (including on
Vista when the icon on disk amounts to a single PNG entry):

function GetRealIconSize(Icon: HICON): TSize; overload;
var
  Info: TIconInfo;
begin
  if not GetIconInfo(Icon, Info) then RaiseLastOSError;
  with TBitmap.Create do
  try
    Handle := Info.hbmMask;
    Result.cx := Width;
    Result.cy := Height;
  finally
    Free; //will destroy Info.hbmMask
  end;
  if Info.hbmColor = 0 then
    Result.cy := Result.cy div 2
  else
    DeleteObject(Info.hbmColor);
end;

function GetRealIconSize(Icon: TIcon): TSize; overload;
begin
  Result := GetRealIconSize(Icon.Handle);
end;
Re: How to determine the dimensions of an HICON?
#230
Author: Ian Boyd
Date: Fri, 25 Jul 2008 20:10
4 lines
1181 bytes
Thanks guys, those were good suggestions.

i even used the GDI+ version of the TIcon suggestion - ask the GDI+ object 
for the things width and height.
Re: How to determine the dimensions of an HICON?
#233
Author: Chris Rolliston
Date: Sat, 26 Jul 2008 19:29
10 lines
1169 bytes
> Really, i'm trying to write the function:
> 
>    function CreateBitmapFromIcon(const icon: HICON): HBITMAP;
>    begin
>        //Step 2: ???
>    end;

Out of curiosity, can I ask why?  Also, are you wanting to convert
icons that possibly already have an alpha channel, or only ones whose
transparency is 'solid' (as was the case for all icons before XP)?
Re: How to determine the dimensions of an HICON?
#234
Author: Ian Boyd
Date: Mon, 28 Jul 2008 13:51
17 lines
1600 bytes
>> Really, i'm trying to write the function:
>>
>>    function CreateBitmapFromIcon(const icon: HICON): HBITMAP;
>>    begin
>>        //Step 2: ???
>>    end;
>
> Out of curiosity, can I ask why?  Also, are you wanting to convert
> icons that possibly already have an alpha channel, or only ones whose
> transparency is 'solid' (as was the case for all icons before XP)?

Yes.

i want to draw an HICON using GDI+.

And while the Bitmap class of GDI+ does have a constructor that takes an 
HICON, it's doesn't handle partial transparency. 
Re: How to determine the dimensions of an HICON?
#235
Author: Ian Boyd
Date: Mon, 28 Jul 2008 17:08
5 lines
1174 bytes
> You can create a TIcon and use the HICON to set the handle of the just
> created Icon class, it should then be possible to retrieve the height
> and width of that Icon instance.

It returns the wrong size (32 vs 48) 
Re: How to determine the dimensions of an HICON?
#236
Author: Ian Boyd
Date: Mon, 28 Jul 2008 17:25
7 lines
1202 bytes
>> i looked at GetIconInfo(), but that only gives me the location of the
>> hot-spot, the color, and the mask.
>
> The color and masks are HBITMAPS, you should be able to pass one into
> GetBitmapDimensionsEx to get the size.

Nope. They both return 0,0. 
Re: How to determine the dimensions of an HICON?
#237
Author: Chris Rolliston
Date: Mon, 28 Jul 2008 17:25
18 lines
1692 bytes
> > Out of curiosity, can I ask why?  Also, are you wanting to convert
> > icons that possibly already have an alpha channel, or only ones
> > whose transparency is 'solid' (as was the case for all icons before
> > XP)?
> 
> Yes.
> 
> i want to draw an HICON using GDI+.
> 
> And while the Bitmap class of GDI+ does have a constructor that takes
> an HICON, it's doesn't handle partial transparency.

Ah, sounds tricky.  I take it you've come across this in your Googling:
http://msdn.microsoft.com/en-us/library/bb757020.aspx (or the blog
entry from which it comes - http://preview.tinyurl.com/6bo5f7).  I note
the GDI version of their HICON to HBITMAP conversion uses Vista-only
APIs (Begin/EndBufferedPaint), so the WIC version is in fact the more
generic one (given the WIC stuff can be installed on XP).
Re: How to determine the dimensions of an HICON?
#238
Author: Ian Boyd
Date: Mon, 28 Jul 2008 17:58
6 lines
1284 bytes
> I take it you've come across this in your Googling:
> (given the WIC stuff can be installed on XP).

i did.

i kept on driving since i don't have WIC, and nobody else on XP would. 
Re: How to determine the dimensions of an HICON?
#239
Author: Marc Rohloff [TeamB]
Date: Mon, 28 Jul 2008 18:45
10 lines
1515 bytes
On Mon, 28 Jul 2008 13:25:09 -0400, Ian Boyd wrote:

> Nope. They both return 0,0.

What does your code look like?
What version of Delphi are you using?

-- 
Marc Rohloff [TeamB]
marc -at- marc rohloff -dot- com
Re: How to determine the dimensions of an HICON?
#240
Author: Ian Boyd
Date: Mon, 28 Jul 2008 19:17
97 lines
3912 bytes
>> Nope. They both return 0,0.
>
> What does your code look like?
> What version of Delphi are you using?


>> Nope. They both return 0,0.
>
> What does your code look like?
> What version of Delphi are you using?


function GetIconDimensions_DoesntWork(icon: HICON): TSize;
var
    info: TIconInfo;
begin
    {
        This method doesn't work. Use GetIconDimenions instead.

        You can't just construct a TIcon, give it the handle, and then call
        Width and Height. It can (and usually will) return the wrong value
        (e.g. 32 when it's really 48, and DrawIconEx(0,0) draws it 48)
    }
    if icon = 0 then
        raise Exception.Create('GetIconDimensions: No icon handle 
supplied');

    Result.cx := 0; //for luck
    Result.cy := 0; //and safety

    Win32Check(GetIconInfo(icon, info));
    try
        if info.hbmColor <> 0 then
            Win32Check(GetBitmapDimensionEx(info.hbmColor, Result))
        else if info.hbmMask <> 0 then
            Win32Check(GetBitmapDimensionEx(info.hbmMask, Result))
        else
            raise Exception.Create('GetIconDimensions: icon has no 
bitmaps');
    finally
        DeleteObject(Info.hbmColor);
        DeleteObject(Info.hbmMask);
    end;
end;


Delphi 5. Doesn't matter too much, Chris Rolliston already discovered a 
method that does work: give one of the bitmap handles returned by 
GetIconInfo to a TBitmap and ask the VCL to figure out the width of the 
HBITMAPs.  The following works:

...happens to work
...on Windows XP
...service pack 2
...in 32-bit color mode
...today:


function GetIconDimensions(icon: HICON): TSize;
var
    info: TIconInfo;
begin
    {
        You can't just construct a TIcon, give it the handle, and then call
        Width and Height. It can (and usually will) return the wrong value
        (e.g. 32 when it's really 48, and DrawIconEx(0,0) draws it 48)

        You can't call GetBitmapDimensionEx on the bitmaps returned in 
InfoInfo,
        they both return zero.

        But you can give the handle to those bitmaps to Delphi's TBitmap, 
and
        ask it to give you the width.
    }
    if icon = 0 then
        raise Exception.Create('GetIconDimensions: No icon handle 
supplied');

    Win32Check(GetIconInfo(icon, info));
    with TBitmap.Create do
    try
        Handle := Info.hbmMask;
        Result.cx := Width;
        Result.cy := Height;
    finally
        Free; //will destroy Info.hbmMask
    end;
    if Info.hbmColor = 0 then
        Result.cy := Result.cy div 2
    else
        DeleteObject(Info.hbmColor);
end;


And no, the VCL doesn't call GetBitmapDimensionEx - it goes around the block 
6 times first. 
Re: How to determine the dimensions of an HICON?
#243
Author: Marc Rohloff [TeamB]
Date: Mon, 28 Jul 2008 19:44
13 lines
1757 bytes
On Mon, 28 Jul 2008 15:17:37 -0400, Ian Boyd wrote:

> Delphi 5. Doesn't matter too much, 
The implementation of TIcon is different in the latest version.

Try replacing GetBitmapDimensionsEx with:
var binfo:Windos.TBitmap;
Win32Check( Windows.GetObject(info.hbmMask, sizeof(binfo), @binfo) );
result.cx := binfo.bmWidth;
result.cy := binfo.bmHeight;

--
Marc
Re: How to determine the dimensions of an HICON?
#244
Author: Ian Boyd
Date: Mon, 28 Jul 2008 19:54
60 lines
3023 bytes
> Try replacing GetBitmapDimensionsEx with:
> var binfo:Windos.TBitmap;
> Win32Check( Windows.GetObject(info.hbmMask, sizeof(binfo), @binfo) );
> result.cx := binfo.bmWidth;
> result.cy := binfo.bmHeight;

i was just coming back to post that:

function GetIconDimensions(icon: HICON): TSize;
var
    info: TIconInfo;
    hbmp: HBITMAP;
    bm: tagBITMAP;
begin
    {
        You can't just construct a TIcon, give it the handle, and then call
        Width and Height. It can (and usually will) return the wrong value
        (e.g. 32 when it's really 48, and DrawIconEx(0,0) draws it 48)

        You can't call GetBitmapDimensionEx on the bitmaps returned in 
InfoInfo,
        they both return zero.

        You *could* create a TBitmap and have the VCL figure it out.

        But here's the actual working code that's faster,
        and probably safer than using Borland code.
    }
    if icon = 0 then
        raise Exception.Create('GetIconDimensions: No icon handle 
supplied');

    Result.cx := 0;
    Result.cy := 0;

    Win32Check(GetIconInfo(icon, info));
    try
        if info.hbmMask <> 0 then
            hbmp := info.hbmMask
        else if info.hbmColor <> 0 then
            hbmp := info.hbmColor
        else
            raise Exception.Create('GetIconDimensions: icon has no 
bitmaps');

        if GetObject(hbmp, SizeOf(tagBITMAP), @bm) = 0 then
            RaiseLastWin32Error;

        Result.cx := bm.bmWidth;
        Result.cy := bm.bmHeight;
    finally
        DeleteObject(Info.hbmColor);
        DeleteObject(Info.hbmMask);
    end;
end;


i'm still curious why Chris Rolliston divides the returned height by 2 when 
there's no color mask. Is the height wrong in that case? Was that a bug in 
Delphi's TIcon? Is GetObject () safe? 
Re: How to determine the dimensions of an HICON?
#242
Author: Ian Boyd
Date: Mon, 28 Jul 2008 19:55
9 lines
1343 bytes
> Possibly not the most efficient way, but it works for me (including on
> Vista when the icon on disk amounts to a single PNG entry):
>
 end;
>  if Info.hbmColor = 0 then
>    Result.cy := Result.cy div 2

Why do you think the height wrong by a factor of two if there's only a mask 
bitmap? 
Re: How to determine the dimensions of an HICON?
#241
Author: Chris Rolliston
Date: Mon, 28 Jul 2008 20:00
8 lines
1348 bytes
> And no, the VCL doesn't call GetBitmapDimensionEx - it goes around
> the block 6 times first.

Just as well really - from MSDN:

'The GetBitmapDimensionEx function retrieves the dimensions of a
compatible bitmap. The retrieved dimensions must have been set by the
SetBitmapDimensionEx function.'
Re: How to determine the dimensions of an HICON?
#245
Author: Chris Rolliston
Date: Mon, 28 Jul 2008 20:07
4 lines
1173 bytes
> i'm still curious why Chris Rolliston divides the returned height by
> 2 when there's no color mask. 

See my reply below.
Re: How to determine the dimensions of an HICON?
#249
Author: Pieter Zijlstra
Date: Mon, 28 Jul 2008 20:22
19 lines
1654 bytes
Ian Boyd wrote:

> i'm still curious why Chris Rolliston divides the returned height by
> 2 when there's no color mask. Is the height wrong in that case? Was
> that a bug in Delphi's TIcon? Is GetObject () safe?

Probably in the assumption that when there is no color mask it concerns
a black & white icon...

From MSDN:

hbmMask
Specifies the icon bitmask bitmap. If this structure defines a black
and white icon, this bitmask is formatted so that the upper half is the
icon AND bitmask and the lower half is the icon XOR bitmask. Under this
condition, the height should be an even multiple of two...[snipped]

-- 
Pieter
Re: How to determine the dimensions of an HICON?
#247
Author: Pieter Zijlstra
Date: Mon, 28 Jul 2008 20:25
15 lines
1298 bytes
Ian Boyd wrote:

> > You can create a TIcon and use the HICON to set the handle of the
> > just created Icon class, it should then be possible to retrieve the
> > height and width of that Icon instance.
> 
> It returns the wrong size (32 vs 48)

Hmm strange, looks like it does not contain a hbmColor bitmap and it
returns the system default for icon width & height.

Is it a B&W icon? 

-- 
Pieter
Re: How to determine the dimensions of an HICON?
#246
Author: Chris Rolliston
Date: Mon, 28 Jul 2008 20:27
12 lines
1404 bytes
> > if Info.hbmColor = 0 then
> >   Result.cy := Result.cy div 2
> 
> Why do you think the height wrong by a factor of two if there's only
> a mask bitmap?

It's for the case of 'true' black and white (1 bit) icons - see the
MSDN/SDK documentation for ICONINFO.  Testing this, it seems the lack
of a color bitmap and doubling up of the mask one only occurs with the
icon has been loaded the WinAPI's LoadImage - use TIcon's LoadFromFile
on exactly the same image and the quirk doesn't occur (to be clear, my
code does work for both cases however).
Re: How to determine the dimensions of an HICON?
#248
Author: Chris Rolliston
Date: Mon, 28 Jul 2008 20:32
10 lines
1417 bytes
>        But here's the actual working code that's faster,
>        and probably safer than using Borland code.

'Faster' (and so preferable) for sure, but hardly 'safer'...

> i'm still curious why Chris Rolliston divides the returned height by
> 2 when there's no color mask. Is the height wrong in that case? Was
> that a bug in Delphi's TIcon? Is GetObject () safe?

See my reply below.
Re: How to determine the dimensions of an HICON?
#250
Author: Chris Rolliston
Date: Mon, 28 Jul 2008 20:40
12 lines
1524 bytes
> > > You can create a TIcon and use the HICON to set the handle of the
> > > just created Icon class, it should then be possible to retrieve
> > > the height and width of that Icon instance.
> > 
> > It returns the wrong size (32 vs 48)

And a quick look at the VCL source (at least up to and including D2006)
will show why...  I think the reason for this behaviour (in the sense
of 'why this is the case' rather than 'why this should be the case') is
the limitations of the Win3.x API when it came to loading and drawing
icons, Borland never updating the TIcon code once these limitations
went away with Win32.
Re: How to determine the dimensions of an HICON?
#251
Author: Chris Rolliston
Date: Tue, 29 Jul 2008 01:40
10 lines
1486 bytes
> i want to draw an HICON using GDI+.
> 
> And while the Bitmap class of GDI+ does have a constructor that takes
> an HICON, it's doesn't handle partial transparency.

Does your version of Delphi have GetDIBSizes and GetDIB available in
Graphics.pas, or at least, are those routines copy and pasteable from
Graphics.pas's implementation section?  Also, when you say 'GDI+', do
you mean the wrappers from www.progdigy.com?  If your answers are all
'yes', then I think I may have a solution to your problem.
Re: How to determine the dimensions of an HICON?
#253
Author: Ian Boyd
Date: Tue, 29 Jul 2008 13:51
11 lines
1358 bytes
> Is it a B&W icon?

Nope. The icon i'm using is Adobe's 48x48 PDF icon.

And Microsoft's 48x48 XPS Icon.

And Windows Vista's 48x48 search icon

And Windows media player's 48x48 movie icon.

And... 
Re: How to determine the dimensions of an HICON?
#252
Author: Ian Boyd
Date: Tue, 29 Jul 2008 14:00
13 lines
1512 bytes
> Does your version of Delphi have GetDIBSizes
Yes.

> and GetDIB available in Graphics.pas
Yes

> Also, when you say 'GDI+', do
> you mean the wrappers from www.progdigy.com?
Yes.

> If your answers are all 'yes', then I think I may have a solution to
> your problem.
Yes? 
Re: How to determine the dimensions of an HICON?
#254
Author: Chris Rolliston
Date: Tue, 29 Jul 2008 14:25
5 lines
1247 bytes
> > If your answers are all 'yes', then I think I may have a solution to
> > your problem.
> Yes?

Assuming that's not a command, see attachments...
Re: How to determine the dimensions of an HICON?
#255
Author: Ian Boyd
Date: Tue, 29 Jul 2008 14:59
13 lines
1576 bytes
>> > If your answers are all 'yes', then I think I may have a solution to
>> > your problem.
>> Yes?
>
> Assuming that's not a command, see attachments...

No, it was.....picture a dog with it's head cocked sideways.... "Yes?"

That worked perfectly. i followed it up with a screenshot of before and 
after, with the working alpha transparency.


Did you just bang that out now? 
Re: How to determine the dimensions of an HICON?
#256
Author: Ian Boyd
Date: Tue, 29 Jul 2008 15:15
61 lines
2845 bytes
Here's the final, gold, function call:


function GetIconDimensions(icon: HICON): TSize;
var
    info: TIconInfo;
    hbmp: HBITMAP;
    bm: tagBITMAP;
begin
    {
        You can't just construct a TIcon, give it the handle, and then call
        Width and Height. It can (and usually will) return the wrong value
        (e.g. 32 when it's really 48, and DrawIconEx(0,0) draws it 48)

        You can't call GetBitmapDimensionEx on the bitmaps returned in 
InfoInfo,
        they both return zero.

        You *could* create a TBitmap and have the VCL figure it out.

        But here's the actual working code.
    }
    if icon = 0 then
        raise Exception.Create('GetIconDimensions: No icon handle 
supplied');

    Result.cx := 0;
    Result.cy := 0;

    //Get the color and mask bitmaps for the icon
    Win32Check(GetIconInfo(icon, info));
    try
        //Pick either the mask or color bitmap to measure
        if info.hbmMask <> 0 then
            hbmp := info.hbmMask
        else if info.hbmColor <> 0 then
            hbmp := info.hbmColor
        else
            raise Exception.Create('GetIconDimensions: icon has no 
bitmaps');

        //Get info about the bitmap (like it's width and height)
        if GetObject(hbmp, SizeOf(tagBITMAP), @bm) = 0 then
            RaiseLastWin32Error;

        Result.cx := bm.bmWidth;
        Result.cy := bm.bmHeight;

        {
            If there is no color mask, then the black and white mask is 2x 
high.
            Top half is AND, lower half is XOR. See ICONINFO docs
        }
        if info.hbmColor = 0 then
            Result.cy := Result.cy div 2;
    finally
        //Since we called GetInfoInfo, we must delete those two bitmaps
        DeleteObject(Info.hbmColor);
        DeleteObject(Info.hbmMask);
    end;
end;
Re: How to determine the dimensions of an HICON?
#257
Author: Chris Rolliston
Date: Tue, 29 Jul 2008 15:20
6 lines
1361 bytes
> Did you just bang that out now?

Pretty much.  Once you said GDI+ was the context, a Google search
(can't remember what for exactly) came up with the two links I note at
the top of the PAS file, with which I thought, should be simple
enough...
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads