Embedding PNGs in wxWidgets programs

547 views
Skip to first unread message

Vadim Zeitlin

unread,
Sep 11, 2012, 5:50:08 PM9/11/12
to wx-dev
Hello,

I'm a bit tired of writing the same code all the time when I need to embed
some PNG images (because, let's face it, it can be nice to use something
other than BMP/XPM in 21st century) into my wxWidgets programs. It is, of
course, easy enough to do and we even have a wiki page[1] explaining this
in all the details but I think it should be even simpler than that.

Ideally I'd like to add wxBITMAP_PNG() macro that would work similarly to
the existing wxBITMAP(), i.e. load PNG from the resources under Windows and
from the embedded into the sources "xxx_png" arrays, similar to "xxx_xpm",
elsewhere. What do you think about this?

If there are no strong objections, I'm going to implement this soon.

Thanks for any feedback,
VZ

[1] http://wiki.wxwidgets.org/Embedding_PNG_Images

John Roberts

unread,
Sep 11, 2012, 10:36:31 PM9/11/12
to wx-...@googlegroups.com
I delay changing icons etc because it is time consuming to convert all
my png files even with a semi automated routine. I would welcome this
addition and can't imagine why anyone would object.
Regards, John

John Labenski

unread,
Sep 11, 2012, 11:26:54 PM9/11/12
to wx-...@googlegroups.com
On Tue, Sep 11, 2012 at 10:36 PM, John Roberts <jo...@iinet.net.au> wrote:
> On 12/09/2012 5:50 AM, Vadim Zeitlin wrote:
>>
>> Ideally I'd like to add wxBITMAP_PNG() macro that would work similarly
>> to
>> the existing wxBITMAP(), i.e. load PNG from the resources under Windows
>> and
>> from the embedded into the sources "xxx_png" arrays, similar to "xxx_xpm",
>> elsewhere. What do you think about this?

This is a good idea, I currently use pngs to add to the wxArtProvider
and this could be used to simplify that.

Is there any benefit in putting the pngs in the resources in MSW over
using bin2c and #including them as you would in Linux/OSX?

Regards,
John

Dimitri Schoolwerth

unread,
Sep 11, 2012, 11:51:44 PM9/11/12
to wx-...@googlegroups.com
I was wondering about that too, I prefer to use the bin2c method on
all 3 platforms. Yet some people might prefer something more suitable
for the platform, so perhaps let the macro version wxBITMAP_PNG be
platform dependent as mentioned. Then also add a wxBitmap
constructor+Create for the bin2c loading? I don't think there is one
currently, I see a ctor with a pointer but it also takes
width/height/depth while we probably need a pointer, a length, and a
wxBitmapType defaulting to PNG.

Since for wxBITMAP_PNG loading from resources is considered under MSW
(maybe mostly to be similar in behaviour to wxBITMAP? I wouldn't think
it's a popular option), it might also be a possibility for wxOSX to
load PNGs from the Contents/Resources/ directory of the application's
bundle?


Regards,
Dimitri

Julian Smart

unread,
Sep 12, 2012, 3:18:08 AM9/12/12
to wx-...@googlegroups.com
Hi Vadim,

On 11/09/2012 22:50, Vadim Zeitlin wrote:
> Hello,
>
> I'm a bit tired of writing the same code all the time when I need to embed
> some PNG images (because, let's face it, it can be nice to use something
> other than BMP/XPM in 21st century) into my wxWidgets programs. It is, of
> course, easy enough to do and we even have a wiki page[1] explaining this
> in all the details but I think it should be even simpler than that.
>
> Ideally I'd like to add wxBITMAP_PNG() macro that would work similarly to
> the existing wxBITMAP(), i.e. load PNG from the resources under Windows and
> from the embedded into the sources "xxx_png" arrays, similar to "xxx_xpm",
> elsewhere. What do you think about this?
Great idea! Though I do wonder whether it's worth the hassle for people
to have to think about managing PNGs in resources; is this such an
important performance consideration now? It would be nicer not to have
to think about the Windows platform differently from the others. But in
that case people can simply not bother with the macro. Will we have a
new wxBitmap constructor, or is it impossible to distinguish the data
from XPM using the constructor? In which case if we need to use a macro,
perhaps we can also have one that loads inline PNG data on all
platforms, e.g. wxBITMAP_PNG_DATA().
>
> If there are no strong objections, I'm going to implement this soon.
Many thanks!

Julian

Vadim Zeitlin

unread,
Sep 12, 2012, 3:39:07 AM9/12/12
to wx-...@googlegroups.com
On Wed, 12 Sep 2012 07:51:44 +0400 Dimitri Schoolwerth wrote:

DS> > Is there any benefit in putting the pngs in the resources in MSW over
DS> > using bin2c and #including them as you would in Linux/OSX?
DS>
DS> I was wondering about that too,

The main benefit is that it's the standard way of doing things under
Windows. Of course, this kind of "we were always doing it like this so
we're going to continue to do it like this" argument is not very
convincing. But it does have a few concrete benefits too, e.g. you can use
standard tools to add/view/edit PNGs to your application without
recompiling it. Also, the existence of the instructions about how to do it
on the wiki page as well as the requests I had to do it in quite a few
different projects shows that some people want to do it and while I'm
hard-pressed to find any real advantage in doing it, neither do I see any
disadvantages with it.

Finally, as Julian writes, if you want to use embedded PNGs everywhere,
you can just load them directly:

static const unsigned char foo_png[] = { ... bytes ... };

// The ctor from memory area would be added and used by wxBITMAP_PNG().
wxBitmap bmp(wxImage(foo_png, WXSIZEOF(foo_png), wxBITMAP_TYPE_PNG));

I don't know if it's worth adding another macro (and it has to be a macro
to use WXSIZEOF() inside it) for this? wxBITMAP_EMBEDDED_PNG() perhaps?

BTW, would anybody have any good naming ideas for the files containing
these arrays with PNG data? I call them foo_png.c right now but it's not
really a very good name.


DS> I prefer to use the bin2c method on all 3 platforms.

That's perfectly fine. You just won't use this new macro then. AFAICS it's
completely symmetrical to wxBITMAP(): if you want to put bitmaps into
Windows resources, you use it, otherwise you just always use XPMs directly.

DS> Then also add a wxBitmap constructor+Create for the bin2c loading? I
DS> don't think there is one currently, I see a ctor with a pointer but it
DS> also takes width/height/depth while we probably need a pointer, a
DS> length, and a wxBitmapType defaulting to PNG.

So far I've added wxImage ctor and wxBitmapType doesn't have any default
value as I'm afraid we'd run into some ambiguities otherwise. Do people
think we should also have wxBitmap ctor like this? I'd prefer to avoid it
and just use wxBitmap ctor from wxImage as above.

It would however make sense to have wxBitmap ctor from PNG if we could
load PNG directly under some platform(s), without going through wxImage.
I think in principle wxGTK might do this, e.g. we could presumably use
gdk_pixbuf_new_from_stream()...

So would you prefer to have a new

wxBitmap(const void* data, size_t len, wxBitmapType type);

ctor? I'm not sure if we're not going to get conflicts with the existing

wxBitmap(const char* bits, int width, int height, int depth = 1);

one though. Perhaps we could have

static wxBitmap NewFromData(const void*, size_t, wxBitmapType);

instead?


DS> Since for wxBITMAP_PNG loading from resources is considered under MSW
DS> (maybe mostly to be similar in behaviour to wxBITMAP? I wouldn't think
DS> it's a popular option), it might also be a possibility for wxOSX to
DS> load PNGs from the Contents/Resources/ directory of the application's
DS> bundle?

Yes, exactly. In fact I think it already works like this in wxOSX: it does
have a handler for wxBITMAP_TYPE_PNG_RESOURCE in src/osx/core/bitmap.cpp so
wxBITMAP_PNG() would load the files from resources there too (although I
didn't test it just yet). As before, if this is undesirable you can always
just create the bitmap directly.

Regards,
VZ

Dimitri Schoolwerth

unread,
Sep 12, 2012, 9:33:36 AM9/12/12
to wx-...@googlegroups.com
On Wed, Sep 12, 2012 at 11:39 AM, Vadim Zeitlin <va...@wxwidgets.org> wrote:
> On Wed, 12 Sep 2012 07:51:44 +0400 Dimitri Schoolwerth wrote:
>
> DS> > Is there any benefit in putting the pngs in the resources in MSW over
> DS> > using bin2c and #including them as you would in Linux/OSX?
> DS>
> DS> I was wondering about that too,
>
> The main benefit is that it's the standard way of doing things under
> Windows. Of course, this kind of "we were always doing it like this so
> we're going to continue to do it like this" argument is not very
> convincing. But it does have a few concrete benefits too, e.g. you can use
> standard tools to add/view/edit PNGs to your application without
> recompiling it.

I totally forgot that a resource references files and that changes
made to the files will recompile the resources, this is quite useful
indeed.


> BTW, would anybody have any good naming ideas for the files containing
> these arrays with PNG data? I call them foo_png.c right now but it's not
> really a very good name.

FWIW the custom 'bin2c' I use does the same and by default converts
file.ext to file_ext.cpp and .h and uses file_ext[] as a variable.


> DS> Then also add a wxBitmap constructor+Create for the bin2c loading? I
> DS> don't think there is one currently, I see a ctor with a pointer but it
> DS> also takes width/height/depth while we probably need a pointer, a
> DS> length, and a wxBitmapType defaulting to PNG.
>
> So far I've added wxImage ctor and wxBitmapType doesn't have any default
> value as I'm afraid we'd run into some ambiguities otherwise. Do people
> think we should also have wxBitmap ctor like this? I'd prefer to avoid it
> and just use wxBitmap ctor from wxImage as above.

You are right, it makes sense to add the ctor to wxImage as that's
also the type used when loading images.
BTW, if we also wrap loading embedded PNGs into a macro
(wxBITMAP_EMBEDDED_PNG sounds fine) do we actually need another
wxImage ctor? It can already be accomplished using wxImage
image(wxInputStream& stream, wxBitmapType) and using a
wxMemoryInputStream as stream argument (this is what I use in my
LoadEmbeddedImage). It does require wxUSE_STREAMS of course.


> It would however make sense to have wxBitmap ctor from PNG if we could
> load PNG directly under some platform(s), without going through wxImage.
> I think in principle wxGTK might do this, e.g. we could presumably use
> gdk_pixbuf_new_from_stream()...
>
> So would you prefer to have a new
>
> wxBitmap(const void* data, size_t len, wxBitmapType type);
>
> ctor? I'm not sure if we're not going to get conflicts with the existing
>
> wxBitmap(const char* bits, int width, int height, int depth = 1);

I failed to see that ctor in wxBitmapBase. Anyway I think using
wxImage is fine and modifying wxBitmap in any way right now would feel
like premature optimisation.


Regards,
Dimitri

Vadim Zeitlin

unread,
Sep 12, 2012, 9:41:37 AM9/12/12
to wx-...@googlegroups.com
On Wed, 12 Sep 2012 17:33:36 +0400 Dimitri Schoolwerth wrote:

DS> BTW, if we also wrap loading embedded PNGs into a macro
DS> (wxBITMAP_EMBEDDED_PNG sounds fine) do we actually need another
DS> wxImage ctor?

We need either another wxImage ctor or another wxBitmap ctor as the macro
can't create wxMemoryInputStream inside it (a temporary won't do as wxImage
stream loading code takes a non-const reference and this can't be changed
easily, even if we wanted to change this and it's not clear if we do).

DS> Anyway I think using wxImage is fine and modifying wxBitmap in any way
DS> right now would feel like premature optimisation.

Actually there is another consideration in wxOSX case: "retina display".
AFAIK we need to use the native image loading functions (CGImage) to handle
this correctly and from this point of view it seems that it does make sense
to have ctor in wxBitmap itself that could be implemented using native API
and not via wxImage at all.

So my latest plan is to add static wxBitmap::NewFromPNGData() and use this
in wxBITMAP_PNG() and wxBITMAP_EMBEDDED_PNG() (or wxBITMAP_PNG_DATA as
proposed by Julian? I don't want to spend more time agonizing over naming
decisions so opinions from others about this would be more than welcome)
macros.

Regards,
VZ

Vadim Zeitlin

unread,
Sep 12, 2012, 11:36:47 AM9/12/12
to wx-...@googlegroups.com
Here is the proposed patch: http://review.bakefile.org/r/440/

I've finally called the other macro wxBITMAP_PNG_FROM_DATA() which seems
more clear to me.

Any comments (not only the ones concerning the naming :-) welcome!
VZ
Reply all
Reply to author
Forward
0 new messages