Retina Support for Mac

Do you have a typical platform dependent issue you're battling with ? Ask it here. Make sure you mention your platform, compiler, and wxWidgets version.
Post Reply
BeerSmith
Knows some wx things
Knows some wx things
Posts: 27
Joined: Mon Mar 07, 2011 8:39 pm

Retina Support for Mac

Post by BeerSmith »

I've researched this but really don't understand how to incorporate Retina support for various size icons into my program. Currently my icons are fuzzy when I go to a Retina display on Mac.

Currently at startup I load all of my icons as images from png files using wxImage::LoadFile() and then convert those to bitmaps which I use throughout the program for lists, toolbars, etc... I have @2x versions of these png files as well in the same locations, but they don't do anything.

So is there some magic trick or flag to get the wxImage or wxBitmap to load the retina @2x images with the regular png images so they will display clearly on a Retina display?

Thanks,
Brad
BeerSmith.com
User avatar
eranon
Can't get richer than this
Can't get richer than this
Posts: 867
Joined: Sun May 13, 2012 11:42 pm
Location: France
Contact:

Re: Retina Support for Mac

Post by eranon »

Hello,

Do you have the magic declaration "<key>NSPrincipalClass</key><string>NSApplication</string>" in your Info.plist?

Here is the way I load mine in one of my apps running under both Windows and Mac below (shopifight_icon being an embedded array built through wxInclude from a PNG file). Also, notice that, strictly, wxIconBundle should contain multiple icon copies in different sizes to never stretch and introduce any blur.

Code: Select all

    // App icon
    wxIconBundle iconset;
    wxIcon icon;
    icon.CopyFromBitmap(wxGetBitmapFromMemory(shopifight_icon));
    iconset.AddIcon(icon);
    SetIcons(iconset);
with:

Code: Select all

#define wxGetBitmapFromMemory(name) _wxGetBitmapFromMemory(name, sizeof(name))
inline wxBitmap _wxGetBitmapFromMemory(const unsigned char *data, int length)
{
    wxMemoryInputStream is(data, length);
    return wxBitmap(wxImage(is, wxBITMAP_TYPE_ANY, -1), -1);
}
EDIT: And (may count), what version of wxWidgets do you use here?
EDIT #2: Well, not very clear mind today:)... Also (and I hope finally) in some circumstances (but really don't remember exactly which; certainly to use for display in the Finder, desktop, info box, etc., outside of the app itself), OS X/ macOS needs an icon through its how convention: ie. a .icns file. So, you have to place one in the app bundle (Resource) and declare it in Info.plist like this below. This was my last EDIT, promise ^^

Code: Select all

<key>CFBundleIconFile</key><string>alify.icns</string>
[Ind. dev. - wxWidgets 3.0/3.1 under "Win 7 64-bit, TDM64-GCC" + "OS X 10.9, LLVM Clang"]
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7459
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Retina Support for Mac

Post by ONEEYEMAN »

eranon,
All this should be done for you in Xcode, right?

Thank you.
User avatar
eranon
Can't get richer than this
Can't get richer than this
Posts: 867
Joined: Sun May 13, 2012 11:42 pm
Location: France
Contact:

Re: Retina Support for Mac

Post by eranon »

Hello, Sorry for the delay, a little busy these days. I guess you can manage Info.plist and app bundle in Xcode, but I can't tell you how... I don't use Xcode on my part (I'm using Code::Blocks in both Windows and OS X). So, I edit Info.plist myself and I create the app bundle on post-build stage through a shell script.

Anyway, with or without Xcode, if you want to check if you have the right Info.plist and a .icns icon in the right place, you can open the generated app bundle in the Finder and see what it contains.

And for the part about code, it's the same whatever IDE you use :wink:
[Ind. dev. - wxWidgets 3.0/3.1 under "Win 7 64-bit, TDM64-GCC" + "OS X 10.9, LLVM Clang"]
chrism238
Earned a small fee
Earned a small fee
Posts: 20
Joined: Sun Feb 17, 2013 6:45 pm

Re: Retina Support for Mac

Post by chrism238 »

Hello; in my macOS application I load two PNG images :

- one is 16x16 pixels, stored in a file named, say, car.png
- the other is "the same" image but at 32x32 pixels, stored in a file named [email protected] (a "retina" version)

The code

Code: Select all

bm0 = wxBitmap("..../car.png", wxBITMAP_TYPE_PNG);
printf("%i x %i\n", bm0.GetWidth(), bm0.GetHeight() );
correctly prints 16x16, and similar code for

Code: Select all

bm1 = wxBitmap("..../vehicle.png", ....
correctly prints 32x32.

Now, I wish to centre both images around two points (px0,py) and (px1,py) so that, despite the images having different resolutions, they should both appear on the same line at py. Of course,

Code: Select all

dc.DrawBitmap(bm0, x - bm.GetWidth() / 2, y - bm.GetHeight() / 2);
works for the 16x16 image, but not the 32x32 image because it will be rendered differently.

Given a wxBitmap, or a wxImage or the underlying raw data, how can I determine the size at which it will be rendered, so that I can centre it?

Thank you.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Retina Support for Mac

Post by doublemax »

Try double wxBitmap::GetScaleFactor().

You'll probably need the latest wxWidgets version from GIT for this.
(Check <wxdir>/include/wx/bitmap.h to see if the method exists).
Use the source, Luke!
chrism238
Earned a small fee
Earned a small fee
Posts: 20
Joined: Sun Feb 17, 2013 6:45 pm

Re: Retina Support for Mac

Post by chrism238 »

doublemax wrote: Fri Apr 19, 2019 9:27 pm Try double wxBitmap::GetScaleFactor().

You'll probably need the latest wxWidgets version from GIT for this.
(Check <wxdir>/include/wx/bitmap.h to see if the method exists).
Thanks very much, that's solved it!
I'm using v3.1.1 and the indicated header file "reveals" lots of useful functions:

Code: Select all

    // support for scaled bitmaps
    virtual double GetScaleFactor()  const { return 1.0; }
    virtual double GetScaledWidth()  const { return GetWidth() / GetScaleFactor(); }
    virtual double GetScaledHeight() const { return GetHeight() / GetScaleFactor(); }
    virtual wxSize GetScaledSize() const
        { return wxSize(wxRound(GetScaledWidth()), wxRound(GetScaledHeight())); }
Post Reply