Re: is lockFocus main thread specific?
Re: is lockFocus main thread specific?
- Subject: Re: is lockFocus main thread specific?
- From: Troy Stephens <email@hidden>
- Date: Thu, 15 Nov 2007 13:44:18 -0800
Drawing to a bitmap via a bitmapped graphics context is background-
thread-safe, and also typically performs better than NSImage lockFocus-
based drawing (especially if your ultimate goal was to use -
[NSBitmapImageRep initWithFocusedViewRect:] to obtain the end result
as a bitmap anyway).
Below is a code sample showing how to do this using AppKit-level
facilites, producing an NSBitmapImageRep result. (Comparable
facilities exist at the CG level, via CGBitmapContextCreate() and
CGBitmapContextCreateImage(), yielding a CGImage result.)
If the content you're drawing into the bitmap is itself an NSImage,
you should also configure the NSImage to keep it from hitting the
image cache (which appears to be the cause of the crash in the
backtrace you provided). [theNSImage setCacheMode:NSImageCacheNever]
will do the trick.
The code:
// 1. Create the NSBitmapImageRep.
outputBitmap = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL pixelsWide:pixelsWide
pixelsHigh:pixelsHigh bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES
isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace bitmapFormat:0
bytesPerRow:0 bitsPerPixel:0];
// 2. Clear the NSBitmapImageRep.
unsigned char *bitmapData = [outputBitmap bitmapData];
if (bitmapData != NULL) {
bzero(bitmapData, [outputBitmap bytesPerRow] *
[outputBitmap pixelsHigh]);
}
// 3. Create an NSGraphicsContext that we can use to draw into
the NSBitmapImageRep, and make it current. Make sure we have a
graphics context before proceeding. (Creation of the bitmap context
should succeed as long as the bitmap is of a supported format though.)
NSGraphicsContext *bitmapContext = [NSGraphicsContext
graphicsContextWithBitmapImageRep:outputBitmap];
if (bitmapContext != nil) {
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:bitmapContext];
// 4. Set the context's interpolation parameter to the
desired value. Since the imageInterpolation isn't part of the
graphics state, and therefore won't be automatically restored to its
previous setting when we invoke [NSGraphicsContext
restoreGraphicsState] below, we save the previous value and explicitly
restore it below after we're done.
NSImageInterpolation previousImageInterpolation =
[bitmapContext imageInterpolation];
[bitmapContext
setImageInterpolation:NSImageInterpolationHigh];
// 5. Draw whatever content you want to put into the
NSBitmapImageRep, using the bitmapped graphics context that we just
created and made current.
// 6. Restore the previous graphics context and image
interpolation setting.
[bitmapContext
setImageInterpolation:previousImageInterpolation];
[NSGraphicsContext restoreGraphicsState];
}
If you need an NSImage, just [[NSImage alloc] initWithSize:...], then -
addRepresentation: the NSBitmapImageRep to it.
Troy
On Nov 15, 2007, at 10:04 AM, Michael B Johnson wrote:
On Nov 15, 2007, at 9:10 AM, Aki Inoue wrote:
Michael,
You can safely use -lockFocus from any threads.
If you're seeing some issues, please file a bug with specific steps
to reproduce.
done. Radar 5602409
Thanks,
Aki
On 2007/11/14, at 22:31, Michael B Johnson wrote:
This is a Leopard only question.
I have a small test app I've been working on that runs on Leopard
in 64 bit that uses NSOperation to do its threading, and am
crashing in code that looks like the following. Unfortunately,
when I run this on several hundred images, it, occasionally (but
consistently) crashes in the drawInRect:.
Now perhaps this has to run in the main thread, but I don't seem
to remember that as a restriction (but I could just be blocking
that info). I know that I could use ImageIO to get the thumbnail
(and probably will), but I have to read the NSImage anyway, since
I'm about to hand this image to QTKit, which only takes an NSImage.
Here's what the stack trace looks like:
#0 0x805e7a3e in objc_msgSend
#1 0x83d980c6 in _NXAllocateImageCache
#2 0x83d97720 in -[NSCachedImageRep
_initWithSize:depth:separate:alpha:allowDeep:]
#3 0x83d9a9e4 in -[NSImage _focusOnCache:creatingWithSizeInPixels:]
#4 0x83d9a3fc in -[NSImage
_cacheRepresentation:toSizeInPixels:stayFocused:]
#5 0x83d9340f in -[NSImage drawInRect:fromRect:operation:fraction:]
and here's the code in the -main of the operation:
NSImage* img = [[NSImage alloc] initWithContentsOfURL:url];
// make a thumbnail:
NSSize fullSize = [img size];
NSRect srcRect = NSMakeRect(0, 0, fullSize.width,
fullSize.height);
NSSize newSize;
CGFloat aspectRatio = fullSize.width / fullSize.height;
if (aspectRatio < 1.0) {
newSize.height = 256;
newSize.width = newSize.height / aspectRatio;
} else {
newSize.width = 256;
newSize.height = newSize.width / aspectRatio;
}
NSRect dstRect = NSMakeRect(0, 0, newSize.width, newSize.height);
NSImage* thumbnail = [[[NSImage alloc] initWithSize:newSize]
autorelease];
[thumbnail lockFocus];
[img drawInRect:dstRect fromRect:srcRect
operation:NSCompositeCopy fraction:1.0f];
[thumbnail unlockFocus];
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden