Re: NSImages rendered at runtime and resolution independent UI...
Re: NSImages rendered at runtime and resolution independent UI...
- Subject: Re: NSImages rendered at runtime and resolution independent UI...
- From: Ricky Sharp <email@hidden>
- Date: Fri, 27 Oct 2006 16:06:08 -0500
On Oct 27, 2006, at 1:57 PM, Shawn Erickson wrote:
I am attempting to get my code ready for resolution independence and I
am trying understand the best way to deal with icon images that I
create at runtime. The below is a cut down example of icon image cache
generation code that I have (the simplest example I have and not one
that would visually benefit the most but...).
Ideally when the user interface scale factor is other then 1.0 I would
want to create an NSImage that is still 12 point by 12 point but has
its pixel content scaled (DPI other then 72) at the time it is created
by the user interface scale factor. I know the framework will scale it
as needed when I go to draw the image but I want to create the image
content at the resolution needed for display to avoid unneeded
interpolation and rep caching.
It isn't clear to me if the following drawing code will automatically
create an image 12 by 12 point image with pixel DPI already adjusted
as needed for screen display (avoiding unneeded interpolation) or
should I modify the code in some fashion to allow the creating of
image content at a higher DPI then 72?
In some older code I had in my res-savvy framework, I used to create
cached NSImage objects. I believe what I saw was that it indeed auto-
scaled things for you. i.e. the size you feed it is the point size,
but one based upon 72 dpi.
However, I had many very strange drawing artifacts in those NSImage
instances. When I would draw bezier paths or text into the image,
they were always scaled correctly. For example, If I specified a
size of 128x128 and my scale factor is set at 2.0, I would end up
with a bitmap image rep of 256x256 pixels with a very crisp path/text
in it. When drawing other images into the cached NSImage, I would
get random failures. Sometimes the image was scaled correctly; other
times it was not scaled at all, or even scaled in the wrong direction
(i.e. 0.5x instead of 2.0x).
I filed a bug on this a while back. This was, BTW, all done when on
Tiger.
In my particular case, I really didn't need to get fancy and cache
images like that. So, my widgets ended up just drawing the images,
bezier paths and text directly in their drawRect,
drawInteriorWithFrame, etc. methods.
Since what you have below is only drawing bezier paths, you should be
OK. If you need to draw images and run into bad scaling, please file
a bug as that will show someone else being able to reproduce it.
Finally, just to throw these helpful tips out there...
* For static images that you load, it's best to move to vector-based
formats (e.g. PDF). I believe even NSCursor can benefit from images
of that type to provide you truly res-independent large cursors
* When you cannot move to vector-based, I've found that it's best to
have your artwork in two flavors: 72dpi and 288dpi. As I didn't have
tools to create multi-resolution image files at the time, I just
provided the flavors as separate files. At runtime, I query the
scale factor and if it's <= 1.0, I use the 72dpi image; otherwise the
288dpi. I found that I got poor downscaling of the 288dpi flavor.
Note that this is the same strategy to employ for app icons; you want
to provide a large one and one or more 'hints' at the smaller sizes.
Note that I have done no testing with multi-resolution image files,
so don't know if the Cocoa frameworks will do the right thing (i.e.
which flavor is used depending upon the scale factor).
If I need to do the later any recommendations on the best way to go
about doing this?
static NSImage* coloredPenIcons[12] = {nil};
if (coloredPenIcons[0] == nil) {
NSSize imageSize = NSMakeSize(12.0, 12.0); // size in points
NSBezierPath* penBody = [NSBezierPath bezierPath];
[penBody moveToPoint:NSMakePoint(1.0, 3.0)];
...
NSBezierPath* penShadow = [NSBezierPath bezierPath];
[penShadow moveToPoint:NSMakePoint(1.0, 2.0)];
...
NSAffineTransform* transform = [NSAffineTransform transform];
// Translate the origin to the center of the point grid, the
coordinate (0,0)
// is considered the lower left edge of a point in user
coordinate space so
// translating by 0.5 will place our drawing centered in the
point grid.
[transform translateXBy:0.5 yBy:0.5];
NSColor* shadowColor = [[NSColor colorWithCalibratedRed:COLOR256
(150)
green:COLOR256
(150)
blue:COLOR256
(150)
alpha:1.0] set];
for (int i = 0; i < 12; i++) {
NSImage* image = [[NSImage alloc] initWithSize:imageSize];
[image lockFocus];
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
[transform concat];
[[NSColor colorWithCalibratedRed:COLOR256(150)
green:COLOR256(150)
blue:COLOR256(150)
alpha:1.0] set];
[penShadow stroke];
...color for pen body varies based on index...
[penBody fill];
[penBody stroke];
[image unlockFocus];
coloredPenIcons[i] = image;
}
}
-Shawn
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
___________________________________________________________
Ricky A. Sharp mailto:email@hidden
Instant Interactive(tm) http://www.instantinteractive.com
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden