multi size icons for wx apps

Hi folks. I’m getting around to addressing the fact that my app’s icon, when seen in the Alt-Tab app selector window looks jaggy/distorted, because it is a 16x16 icon that Windows XP is scaling up to be 32x32. I think the answer is to use an .ico file that contains a number of different sizes, something I have not done before.

I have the icon image I want to use, and from what I gather, what I have to do is to acquire a number of sizes of this image (available from where I got the icon) and then use some freeware to combine them into one .ico file. I can then use wxIconBundle and myapp.SetIcons() and after that the appropriate sized icon will be used by the OS for its different needs (alt-tab window, taskbar, app itself, etc.). Note: I will be using img2py so that I don’t have to include image files when I distribute my app.

I have a number of questions regarding this, and although this is not strictly wxPython content, it might be useful to know for wxPython app developers (well, at least this one), so I thought I’d ask:

  1. Is the way I am understanding it above right?

  2. Is there something already built into wxPython that helps with this?

  3. Are there concerns about this approach working on Linux and Mac just as well as on Windows XP and up, or are there OS-specific (or even OS version specific) concerns I need to know about?

  4. What are the sizes that I really should include these days so that all modern OSs have what they need to look great?

  5. Do I have to be concerned about creating both 4-bit and 8-bit versions of each size?

  6. Is using img2py going to present any problems with the use of a multi size .ico file?

Thanks,
Che

From: C M

Sent: Saturday, December 04, 2010 11:32 PM

To: wxPython-users@googlegroups.com

Subject: [wxPython-users] multi size icons for wx apps

Hi folks. I’m getting around to addressing the fact that my app’s icon, when seen in the Alt-Tab app selector window looks jaggy/distorted, because it is a 16x16 icon that Windows XP is scaling up to be 32x32. I think the answer is to use an .ico file that contains a number of different sizes, something I have not done before.

I have the icon image I want to use, and from what I gather, what I have to do is to acquire a number of sizes of this image (available from where I got the icon) and then use some freeware to combine them into one .ico file. I can then use wxIconBundle and myapp.SetIcons() and after that the appropriate sized icon will be used by the OS for its different needs (alt-tab window, taskbar, app itself, etc.). Note: I will be using img2py so that I don’t have to include image files when I distribute my app.

I have a number of questions regarding this, and although this is not strictly wxPython content, it might be useful to know for wxPython app developers (well, at least this one), so I thought I’d ask:

  1. Is the way I am understanding it above right?

I think you have the gist of it.

  1. Is there something already built into wxPython that helps with this?

wx and hence wxPython supports multiple size icons and will try to select the correct size from an Icon collection so yes.

  1. Are there concerns about this approach working on Linux and Mac just as well as on Windows XP and up, or are there OS-specific (or even OS version specific) concerns I need to know about?

It should work on all supported platforms automatically.

  1. What are the sizes that I really should include these days so that all modern OSs have what they need to look great?

Not a mac expert but as far as I know 8x8, 16x16, 24x24, 32x32 & 64x64 should cover most things.

  1. Do I have to be concerned about creating both 4-bit and 8-bit versions of each size?

Not as far as I know but if you create 1, 4, 8, 16 & 24 bit versions you will have more control of what they look like if they ever get used.

  1. Is using img2py going to present any problems with the use of a multi size .ico file?

Better yet it actively supports multiple sizes see the –i, –a, –n & –c options.

Gadget/Steve

···

Thanks,

Che

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en

Steve, thanks for the help. But I am still having a problem getting this to work using img2py.

First, note: Using CombineIcons (Googlable very ad hoc freeware) I have made an .ico file that has both a 16x16 and 32x32 size of my icon.

So then, if I don’t use img2py, this routine (by Phillip, and found online…see URL below), works fine to produce the correct sized icon when the app needs it:

icons = wx.IconBundle()

for sz in [16, 32, 48]:

try:

    icon = wx.Icon('my_combo_icon.ico', wx.BITMAP_TYPE_ICO,

              desiredWidth=sz, desiredHeight=sz)

    icons.AddIcon(icon)

except:

    pass

frame.SetIcons(icons)

(found at: http://wxpython-users.1045709.n5.nabble.com/Setting-icons-td2297478.html)

But, I want to use img2py, since I am making an .exe and would rather not include image files in distributing the app. So I tried a simpler variation on the above, relying on the idea that wx.IconBundle, as you wrote, would automatically choose the right icon size for the task. I did this:

    combo_icon = MyImages.my_combo_icon.GetIcon()
    icons = wx.IconBundle()
    icons.AddIcon(combo_icon)
    self.SetIcons(icons)

But when I do this, only the 32x32 size is used. Therefore, on WinXP, the alt-tab window image of the icon looks good, but the application bar image on the app, which should be 16x16, looks jaggy.

What am I doing wrong? Or did the (possible) bug that was mentioned on the web page above not yet get fixed?

Thanks,
Che

Hi,

···

On Sun, Dec 5, 2010 at 2:09 PM, C M <cmpython@gmail.com> wrote:

What am I doing wrong? Or did the (possible) bug that was mentioned on the
web page above not yet get fixed?

img2py converts to PNG and then serializes the data into a python
source file. So you won't have all the different resolutions embedded
in the single ico file since png is a single image.

You could try to embed each of the individual images using img2py and
try to create an IconBundle at runtime by combining each of them.

Cody

Cody,

img2py converts to PNG and then serializes the data into a python

source file. So you won’t have all the different resolutions embedded

in the single ico file since png is a single image.

Well then what’s arguably misleading about that is that the img2py method available is called .GetIcon(). I thought it should be able to provide a multi-size icon. OK, though, fine.

You could try to embed each of the individual images using img2py and

try to create an IconBundle at runtime by combining each of them.

But how? I tried this by using myIconBundle.AddIcon(icon16) and then myIconBundle.AddIcon(icon32) but then it just replaces the first icon with the second.

Thanks,
Che

You can give the -a flag to img2py.py to append a file into the Python module. The first time, don’t use the -a flag; but the second time and all other times use the -a flag in order to append the image into the Python module. And so you’d have an icon bundle.

My suggestion is this:

  1. img2py.py -i your-image-name.jpg my-icon-bundle.py (Note: the -i flag instructs img2py to output a function to return the image as a wxIcon object; you’ll need to call this function in your source code for the icon to actually appear)

  2. img2py.py -i -a your-image-name.jpg my-icon-bundle.py

  3. and then the same as number 2 for all icons you want to embed into your Python module

I assume you’re on Windows OS. So, open the Command Prompt (Start > Run > cmd > hit Enter key) and navigate to where the img2py.py is located. In my case it looks like this:

C:\Users\Boštjan> cd C:\Python27\Lib\site-packages\wx-2.9.1-msw\wx\tools

C:\Python27\Lib\site-packages\wx-2.9.1-msw\wx\tools> img2py.py -i your-first-image-name.ico my-icon-bundle.py

and then repeating the below line as may times you want to bundle a new icon into your Python module

C:\Python27\Lib\site-packages\wx-2.9.1-msw\wx\tools> img2py.py -i -a your-second-image-name.ico my-icon-bundle.py

P.S.: My previous post has typos:

img2py.py -i your-image-name.jpg my-icon-bundle.py and img2py.py -i -a your-image-name.jpg my-icon-bundle.py

should be img2py.py -i your-image-name.ico my-icon-bundle.py and img2py.py -i -a your-image-name.ico my-icon-bundle.py

True, though I don't know anyway to have the system recognize that icon bundle as the app's bundle.

It's awkward, but what I have done is:

Generate a windows icon bundle, and use use py2exe to add it to the exe.

On the Mac, I build a mac icon bundle and use py2app to associate it with the app.

Then I put another copy in a img2py file, and make that the main frame icon in the code.

It would be nice to do all that with one-stop shopping in python code, but I don't know how.

-Chris

···

On 12/5/10 12:48 PM, Cody Precord wrote:

img2py converts to PNG and then serializes the data into a python
source file. So you won't have all the different resolutions embedded
in the single ico file since png is a single image.

You could try to embed each of the individual images using img2py and
try to create an IconBundle at runtime by combining each of them.

Cody,

    img2py converts to PNG and then serializes the data into a python
    source file. So you won't have all the different resolutions embedded
    in the single ico file since png is a single image.

Well then what's arguably misleading about that is that the img2py
method available is called .GetIcon(). I thought it should be able to
provide a multi-size icon. OK, though, fine.

The embedded image's GetIcon simply loads the image into a wxBitmap and then converts to a wx.Icon.

    You could try to embed each of the individual images using img2py and
    try to create an IconBundle at runtime by combining each of them.

But how? I tried this by using myIconBundle.AddIcon(icon16) and then
myIconBundle.AddIcon(icon32) but then it just replaces the first icon
with the second.

That should be working. Please try to verify (perhaps by using GetIconOfExactSize to fetch the icons you've put in it) and submit a ticket about it if it is replacing the existing icons of a different size.

···

On 12/5/10 1:16 PM, C M wrote:

--
Robin Dunn
Software Craftsman

But how? I tried this by using myIconBundle.AddIcon(icon16) and then

myIconBundle.AddIcon(icon32) but then it just replaces the first icon

with the second.

That should be working. Please try to verify (perhaps by using GetIconOfExactSize to fetch the icons you’ve put in it) and submit a ticket about it if it is replacing the existing icons of a different size.

OK, but re: checking, am I doing this right? Because this is causing my app to crash:

    icon32 = MyImages.icon32.GetIcon()  #a 32x32 icon
    icon = MyImages.icon.GetIcon()         #a 16x16 icon

    icons = wx.IconBundle()
    icons.AddIcon(icon)
    icons.AddIcon(icon32)
   
    #This line is what causes the crash:
    got_icon = icons.GetIconOfExactSize(wx.Size(16,16))

    print 'got icon = ', got_icon
    self.SetIcons(icons)

Thanks,
Che

Not intending to distract from the actual issue, but doesn’t wx.SYS_ICON_X/Y, wx.SYS_SMALLICON_X/Y and wx.SYS_ICONSPACING_X/Y effect what icon size an app tries to use?

For that matter if OP has changed his desktop theme on his computer, shouldn’t that also effect what size icon his app choses to use from a multi-sized icon file?

        But how? I tried this by using myIconBundle.AddIcon(icon16) and
        then
        myIconBundle.AddIcon(icon32) but then it just replaces the first
        icon
        with the second.

    That should be working. Please try to verify (perhaps by using
    GetIconOfExactSize to fetch the icons you've put in it) and submit a
    ticket about it if it is replacing the existing icons of a different
    size.

OK, but re: checking, am I doing this right? Because this is causing my
app to crash:

Do you have a wx.App object created already? I assume you do...

         icon32 = MyImages.icon32.GetIcon() #a 32x32 icon
         icon = MyImages.icon.GetIcon() #a 16x16 icon

         icons = wx.IconBundle()
         icons.AddIcon(icon)
         icons.AddIcon(icon32)

         #This line is what causes the crash:
         got_icon = icons.GetIconOfExactSize(wx.Size(16,16))

It seems to be working for me with my current 2.9 workspace, I haven't checked 2.8. This is a session from PyCrust in the demo folder:

  >>> wx.version()
  '2.9.2.0 (msw-unicode)'
  >>> pwd
  C:\PROJECTS\wx\2.9\wxPython\demo
  >>> import images
  >>> i1 = images.Smiles.GetIcon()
  >>> i2 = images.Mondrian.GetIcon()
  >>> i1.Width, i1.Height
  (16, 16)
  >>> i2.Width, i2.Height
  (32, 32)
  >>> ib = wx.IconBundle()
  >>> ib.AddIcon(i1)
  >>> ib.AddIcon(i2)
  >>> ib.IsOk()
  True
  >>> ib.GetIconCount()
  2
  >>> ib.GetIconByIndex(0)
  <wx._gdi.Icon; proxy of <Swig Object of type 'wxIcon *' at 0x24578b0> >
  >>> ib.GetIconByIndex(1)
  <wx._gdi.Icon; proxy of <Swig Object of type 'wxIcon *' at 0x24667a0> >
  >>> ib.GetIconOfExactSize((16,16)).Width
  16
  >>> ib.GetIconOfExactSize((32,32)).Width
  32

···

On 12/6/10 10:57 AM, C M wrote:
  >>>

--
Robin Dunn
Software Craftsman

Not intending to distract from the actual issue, but doesn't
wx.SYS_ICON_X/Y, wx.SYS_SMALLICON_X/Y and wx.SYS_ICONSPACING_X/Y effect
what icon size an app tries to use?

It does affect what icon will be pulled by default from a wx.IconBundle object by wx code. I assume that the system will also behave that way for displaying icons in the task bar or for the Alt-Tab popup, etc.

For that matter if OP has changed his desktop theme on his computer,
shouldn't that also effect what size icon his app choses to use from a
multi-sized icon file?

Yes, it's possible. I would expect it to choose the icon that is closest to the size it wants to display. I don't know for sure however.

···

On 12/6/10 11:01 AM, Dev Player wrote:

--
Robin Dunn
Software Craftsman

Robin Dunn, you’re using wxPython 2.9.2.0? When are you going to release it publicly?

Robin Dunn, you're using wxPython 2.9.2.0?

That is the current version number in the code for the trunk version of the code. It's not an official, unofficial or preview release. It's just a snapshot from the source repository.

When are you going to release
it publicly?

Sometime after the 2.9.2 version of wxWidgets is released.

···

On 12/6/10 1:53 PM, Bo�tjan Mejak wrote:

--
Robin Dunn
Software Craftsman

Robin,

Do you have a wx.App object created already? I assume you do…

Yes. (See code below)

This is a session from PyCrust in the demo folder:

wx.version()

‘2.9.2.0 (msw-unicode)’

pwd

C:\PROJECTS\wx\2.9\wxPython\demo

import images

i1 = images.Smiles.GetIcon()

i2 = images.Mondrian.GetIcon()

i1.Width, i1.Height

(16, 16)

i2.Width, i2.Height

(32, 32)

ib = wx.IconBundle()

ib.AddIcon(i1)

ib.AddIcon(i2)

ib.IsOk()

True

ib.GetIconCount()

2

ib.GetIconByIndex(0)

<wx._gdi.Icon; proxy of <Swig Object of type ‘wxIcon *’ at 0x24578b0> >

ib.GetIconByIndex(1)

<wx._gdi.Icon; proxy of <Swig Object of type ‘wxIcon *’ at 0x24667a0> >

ib.GetIconOfExactSize((16,16)).Width

16

ib.GetIconOfExactSize((32,32)).Width

32

My PyCrust seems to be set up differently than yours; I can’t reproduce this in mine (it can’t do pwd and can’t find the images). But in my app, this is what I am trying (interspersing the output and the code):

version = wx.version()
app = wx.GetApp()
print 'app is: ', app
print 'version is: ', version

version is: 2.8.10.1 (msw-unicode)
app is: <wx._core.PySimpleApp; proxy of <Swig Object of type ‘wxPyApp *’ at 0x20d29d0> >

myicon = MyImages.my_icon.GetIcon()
print 'width, height: ', myicon.Width, myicon.Height

width, height: 32 32

ib = wx.IconBundle()
ib.AddIcon(myicon)

That doesn’t create any problem. But, when I do either of these two:

ib.IsOk()
icon_count = ib.GetIconCount()

It causes the app to crash (whether run through Boa Constructor or run on its own).

-Che

My PyCrust seems to be set up differently than yours; I can't reproduce
this in mine (it can't do pwd

The new version of PyCrust in in the 2.8.11.0 release.

and can't find the images). But in my
app, this is what I am trying (interspersing the output and the code):

version = wx.version()
app = wx.GetApp()
print 'app is: ', app
print 'version is: ', version

>>> version is: 2.8.10.1 (msw-unicode)
>>> app is: <wx._core.PySimpleApp; proxy of <Swig Object of type
'wxPyApp *' at 0x20d29d0> >

  myicon = MyImages.my_icon.GetIcon()
  print 'width, height: ', myicon.Width, myicon.Height

>>> width, height: 32 32

ib = wx.IconBundle()
ib.AddIcon(myicon)

That doesn't create any problem. But, when I do either of these two:

ib.IsOk()
icon_count = ib.GetIconCount()

It causes the app to crash (whether run through Boa Constructor or run
on its own).

Oops, sorry. It looks like those methods were added in the 2.9 series, I thought they had been there longer than that. I'm not sure what to suggest now...

···

On 12/7/10 9:18 AM, C M wrote:

--
Robin Dunn
Software Craftsman

It causes the app to crash (whether run through Boa Constructor or run

on its own).

Oops, sorry. It looks like those methods were added in the 2.9 series, I thought they had been there longer than that. I’m not sure what to suggest now…

Thanks for letting me know.

Well, let me put this question to all wxPython users: are there people on the list who are using:

a) wxPython 2.8.10.x (or at least not the 2.9 series)

b) multi-size icons successfully and cross-platform such that the correct size is always shown on their app (such as 16x16 for each frame’s taskbar but 32x32 when shown in the window that WinXP pops up when you do alt-tab to cycle through open applications)

If so, what are you doing right that I’m doing wrong?

I’m holding off upgrading to 2.9 because Boa Constructor apparently doesn’t play nice with it and because I’m currently dealing with other upgrading issues with another library.

Thanks,
Che

Python 2.7 (r27:82525, Jul 4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32

wx.version() ‘2.8.11.0 (msw-unicode)’

MS-Windows XP SP3, Pent4

Alt-tab i think shows 32x32 icons on my screen, but I’m using an old 22’ CRT 1600x1200. But my 16x16 icons do exist in my Quicklaunch bar and my start bar has both sizes. Also, because some wxpython widgets push my desktop back to

the standard theme, I’m always in Default theme. As mentioned before, your desktop theme can cause you issues. See Robins response to me about it above.

One of the frustrating things and scary things to me are that 3rd party Python libraries and packages that do not keep up with the language. It’s the worst of any language I’ve seen. HTML to HTML5, PHP4 to PHP5, C to C++, FoxPro to Visual FoxPro, BASIC to Visual Basic had better version conversion control. I’m dying to use PIL with wxPyDemo but it as well as others won’t install without trickery or hackieness with Python 2.7. It doesn’t look like I’ll be able too unless I rollback my Python to 2.6 or wait until PIL 3K is done, as it seems PIL 2.7 might be on hold (there is a version for another Python interpreter version) But all that gets messy in my head.

The task is just so huge, and for open source you just pray the primary contributors don’t (seemingly) disappear (i.e. Boa).

I’m dying to use PIL with wxPyDemo but it as well as others won’t install without trickery or hackieness with Python 2.7. It doesn’t look like I’ll be able too unless I rollback my Python to 2.6 or wait until PIL 3K is done, as it seems PIL 2.7 might be on hold (there is a version for another Python interpreter version)

PIL for Python 2.7

http://effbot.org/media/downloads/PIL-1.1.7/win32-py2.7.exe

Malcolm