Closed Bug 314030 Opened 19 years ago Closed 13 years ago

API to generate win32 icons from PNGs (and canvases?)

Categories

(Core :: Widget: Win32, defect)

x86
Windows XP
defect
Not set
normal

Tracking

()

RESOLVED WORKSFORME

People

(Reporter: benjamin, Assigned: bbondy)

References

Details

I need an API to generate win32 icons from PNGs. This will have a couple applications:

XULRunner application icons should probably be in a cross-platform format (I'm leaning towards PNG), and at install-time I'd like to generate a windows icon from that PNG which can be used for shortcuts and OS-integration tasks.

I want a generic tray-icon API where XUL apps can put up tray icons for notifications: to do this, apps need to be able to specify the tray icon: PNG would be a good first step, but I'd also like to be able to generate that tray icon dynamically using canvas (much lower priority).

My basic thought was to create an nsIWin32Icon interface which would wrap a win32 HICON resource, refactor the code from nsWindow::SetCursor, and write some sort of save-to-disk method (pav tells me that you basically write the in-memory representation of the icon to disk, so it shouldn't be hard).

What I don't know is whether I need to deal with multiple bit-depths or icon sizes, and if I do, how I would do that.
Multiple sizes, at least, are very useful for window icons, as larger icons often don't look so good small. The ChatZilla window icon, to take an extreme example, has 12 versions in it: 64x64, 48x48, 32x32, 16x16 all in 4bit, 8bit and 32bit. :-)

Also, AIUI, HICONs are not really the best way to handle images about to be saved to disk, though, as they represent only a single icon image, and are in DDB format, not DIB. If you have the DIB data (as you will do from the PNG via imagelib), that can be written out to disk easily (it's just some simple headers + mask + data).
So silver, if I had an API to set the tray icon, what do you think it should look like:

setTrayIcon(pngimage);
setTrayIcon(array of png images of different sizes and bit-depths); ?

I'm pretty sure that the windows tray API (Shell_NotifyIcon) only takes one HICON resource, so I'm not sure how we'd go about selecting the best one.
For the tray icon, I don't think there is that much need for multiple formats. However, if you wanted to go that way, I would suggest that an nsIWin32Icon-implementing object could be created (via contract id), and any number of PNGs added/removed from it (actually, you could probably support any image supported by imagelib, but PNG is my fav.), and then pass that to the setTrayIcon API.

If you like overloads, you could easily have a 2nd version of setTrayIcon that took a nsIURL (or even a string if you wanted to be extra nice to callers) and wrapped it up in an nsIWin32Icon for you.

nsIWin32Icon would then have a method for getting the best image from its collection (with ideal size provided by the caller), maybe directly as an HICON or maybe indirectly via another interface or method.

If my reference about HICON only being a single image at a time is right (I'm not totally convinced, but can't find anything to contradict it yet), you can relatively easily pick the 'best' image from a set. For a start, http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/structures/notifyicondata.asp tells you (in the hIcon info) what colour depth is supported on each previous version of Windows, and there is a pretty simply algol used by Windows for loading icons (closest size, highest colour depth <= screen colour depth, etc.). I could find a reference for choosing the best icon if you want.
Any references you could provide would be great!
eh, why not setTrayIcon(imgIContainer icon)?
I'd recommend creating an imgIEncoder that encodes HICONs.
The "Icon Display" section in http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/icons/abouticons.asp explains how Windows goes looking for an appropriate icon image when loading (step 2 is the important bit).
I have code which generate HICON from nsIDOMHTMLImageElement and nsICanvasElement (http://www.jabberstudio.org/cgi-bin/viewcvs.cgi/jabberzilla/trunk/src/components/base/src/systray/). 

I can work on this bug, but i know first how should api looks like.
I want one scriptable API:

 void createIconFromPNG(in nsIFile aImageFile, in nsIFile aICOResult);

I'd also like an internal API that gives me an HICON from a PNG (or from an internal image object), for use in "minimize-to-tray" code... you're welcome to design that API however is convenient.

Thank you so much for taking this on!
as I said earlier, this should go through imgIEncoder.  Expand the API if you want (as it currently only deals with raw data).  I would suggest only dealing with raw data though.  Let the decoding happen externally.  Maybe provide an external helper class/api though.
How about multiple image icons? If i take imgIEncoder route how about not 24 bit icons?
I wrote ico image encoder, and now want to add interface like this:

interface nsIImageConverter : nsISupports
{
    void init(in string outputMimeType, in string outputOptions);

    void imageFromURI(in nsIURI uri);
    void imageFromCanvas(in nsIDOMHTMLCanvasElement canvas);

    void writeToStream(in nsIOutputStream);
};

Any idea where should i put it? I can't put it to libpr0n because of dom dependancy.
> Any idea where should i put it? I can't put it to libpr0n because of dom
> dependancy.

That's not true. Since libpr0n and dom are in the same tier (tier 9==gecko), you should be able to do this just fine. You may need to forward-declare interface nsIDOMHTMLCanvasElement but that's ok.

The interface you've proposed, however, needs to deal with asynchronous loading somehow.
(In reply to comment #13)
> > Any idea where should i put it? I can't put it to libpr0n because of dom
> > dependancy.
> 
> That's not true. Since libpr0n and dom are in the same tier (tier 9==gecko),
> you should be able to do this just fine. You may need to forward-declare
> interface nsIDOMHTMLCanvasElement but that's ok.
> 

No, don't add a DOM dep to imagelib.
I've posted a proposal to https://bugzilla.mozilla.org/show_bug.cgi?id=325353, based on Jabberzilla code written by Pawel. After discussing this with biesi, we felt that an encoder is not the proper place to do this since there is actually very little shared code between this and a component that writes encoded data to a stream. The main work in the case of the encoding is in writing the correct header, which would then have to be reparsed in order to create a native icon.

Probably this code should be moved here (once we decide where to put it) and referenced from the system tray icon bug.
Assignee: win32 → nobody
QA Contact: ian → win32
Depends on: 600556
Assignee: nobody → netzen
It’s been since 2006 that this task was last discussed so here is an overview of how I think everything should be implemented and what tasks need to be defined.

> I need an API to generate win32 icons from PNGs. 

We have the needed ICO encoder in imglib now.  It's not pushed to mozilla-central yet, but probably will be within the next 2-3 weeks. The encoder can be found in the patch from Bug 549468 and its dependents.  

You can specify not only PNGs but also anything we have a decoder for, which is BMP, GIF, ICO, JPEG, PNG.  Allowing only PNG vs allowing all types is the same amount of work.

We currently only have support for putting 1 image of a specific size in the ICO format.  But since you probably want to generate it from a single image this may be enough.  


> XULRunner application icons should probably be in a cross-platform format (I'm leaning towards PNG)

You can convert from any image type to an ICO of a specific size via EncodeScaledImage with code similar to the following:

mimeType.AssignLiteral("image/vnd.microsoft.icon");
nsCOMPtr<nsIInputStream> iconStream;
rv = imgtool->EncodeScaledImage(container, mimeType,
 systemIconWidth,
 systemIconHeight,
 getter_AddRefs(iconStream));


> and at install-time I'd like to generate a windows icon from that PNG which can be used for shortcuts and OS-integration tasks

Could you give me an example of how the icon would be specified in some config file?
By install time do you mean with NSIS? So the conversion would be an NSIS plugin?  Or do you mean something else relating to the build process?
Perhaps you could send me to a link about XUL Runner packaging?


> I want a generic tray-icon API where XUL apps can put up tray icons for notifications: to do this, apps need to be able to specify the tray icon: PNG would be a good first step, 

You mean the system tray on the bottom right next to the system clock right?
Would you also like support for right click system tray menus? 
This would all be windows only XPCOM right?

I envision this new API being a new XPCOM object inside <mozilla-central>\widget\src\windows.


> but I'd also like to be able to generate that tray icon dynamically using canvas (much lower priority).

I already generate ICO files dynamically from canvas using the reftests of Bug 549468.  
It is done via the canvas.toDataURL function with a mime type of image/vnd.microsoft.icon.
See encoder.html here: 
https://bugzilla.mozilla.org/page.cgi?id=splinter.html&bug=549468&attachment=548650

I don't think any extra APIs are need here.


> My basic thought was to create an nsIWin32Icon interface which would wrap a win32 HICON resource, refactor the code from nsWindow::SetCursor, and write some sort of save-to-disk method 

Now that we have it, I think the best route is to use the ICO encoder.  I don't think the user of the API should have to know about HICONs at all.  
Likewise I don't think we need an nsIWin32Icon because we can just use an imgIContainer.


> What I don't know is whether I need to deal with multiple bit-depths or icon sizes, and if I do, how I would do that.

You can specify the bit depths with ICO encoder options, but this should be done internally and not exposed to the user of the API.  
I also added support for canvas bit depths, and you can specify whether to use BMP or PNG based ICO files.  
As for sizes you can create exactly 1 size currently.  Windows will scale them to your need but you get the best picture/resolution.  
We do a slightly better job of scaling than Windows which we can do with imgtool->EncodeScaledImage.  

You would probably want to provide a 16x16 always since that is most common.  Internally we can use:

PRInt32 systemIconWidth = GetSystemMetrics(SM_CXSMICON);
PRInt32 systemIconHeight = GetSystemMetrics(SM_CYSMICON);

to get the desired file size for the system tray which returns usually 16x16 but possibly bigger if you have a larger DPI setting.

Multiple icon sizes in one file would be useful for other areas, if you want the icon to be used elsewhere than just the system tray.


> what do you think it should look like:
> setTrayIcon(pngimage);
> setTrayIcon(array of png images of different sizes and bit-depths); ?

I think we should have a tray XPCOM object and it would have a method on it for setTrayIcon which would take an imgIContainer or a URI.
An imgIContainer can hold multiple frames.  The Jump List API which I just did takes a URI and obtains the resource for you.  

I also think we should have a setNotificaitonIcon method that will be displayed in the notification messages you send.
or it could be displayed in a displayNotification(string) API.
We could also implement callbacks when the user clicks on a notification or left/right clicks on the system tray icon.

> I'm pretty sure that the windows tray API (Shell_NotifyIcon) only takes one HICON resource

That is correct and HICON refers to only 1 image resource inside an ICO.  But behind the scenes we can scale it to the needed size based on the DPI setting.  We do this same thing in jump lists icons today.

> Overview 

I think we should do the following:

Bugs to be added:
0) Use this bug as tracking bug
1) multi image ICO encoder (lower priority than the other tasks here)
2) install-time generation of ICO to PNG for XUL Runner apps (need more details here)
3) Add system tray XPCOM object with setTrayIcon support and support for notifications (I can add a task for this now and start working on it pending your approval Benjamin)
Ignore the install-time bits for now, we aren't focusing on generic XULRunner app install.

There are already various pieces around for tray icons (thunderbird already uses a tray icon, and Firefox might for downloads, I'm not sure). There is already a notification API also.

So I'm not sure there is much specifically to do here once the encoder lands: we'll definitely want to use this to support the installable webapps work which is being specced out now.
Talked to Benjamin on IRC, this task should be closed.

- Encoder that this task wanted is implemented in Bug 549468.
- Install bits: we aren't focusing on generic XULRunner app install.  
- Tray icons already implemented in various places.
Status: NEW → RESOLVED
Closed: 13 years ago
Resolution: --- → WORKSFORME
You need to log in before you can comment on or make changes to this bug.