is lockFocus main thread specific?

  • 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];
  • On Nov 15, 2007, at 1:31 AM, 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:.

    Are you checking the image you get back from -initWithContentsOfURL:?
    You should check -isValid and the size of the image.  I found that EPS
    images could cause crashes in -lockFocus if you hadn't called -isValid
    on them first.  Images with massive sizes (and possibly NSZeroSize)
    could also cause crashes in -lockFocus.

    -Frank

    ------------------------------------
    Frank M. Midgley
    <knarf...>
    http://homepage.mac.com/knarf/
    Sterling, VA USA
  • Michael,

    You can safely use -lockFocus from any threads.

    If you're seeing some issues, please file a bug with specific steps to
    reproduce.

    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];
  • 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];
  • 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];

  • On Nov 15, 2007, at 3:03 PM, <cocoa-dev-request...> wrote:

    > 9. Re: is lockFocus main thread specific? (Michael B Johnson)

    [NSImage lockFocus] most definitely crashes on 10.5 when called from a
    secondary thread. I have dozens of crash reports from users verifying
    the problem.

    I was unable to reproduce the problem in a small test application,
    though, so the problem is more complicated than just that one call. My
    work-around was to do all NSImage related work on the main thread,
    which is ok in our case but definitely sub-optimal in others.

      -Eric Shapiro
  • On 16 Nov 2007, at 01:50, Eric Shapiro wrote:

    > On Nov 15, 2007, at 3:03 PM, <cocoa-dev-request...> wrote:
    >
    >> 9. Re: is lockFocus main thread specific? (Michael B Johnson)
    >
    >
    > [NSImage lockFocus] most definitely crashes on 10.5 when called from
    > a secondary thread. I have dozens of crash reports from users
    > verifying the problem.
    >
    > I was unable to reproduce the problem in a small test application,
    > though, so the problem is more complicated than just that one call.
    > My work-around was to do all NSImage related work on the main
    > thread, which is ok in our case but definitely sub-optimal in others.
    >
    > -Eric Shapiro
    >

    This reminds me of :
    http://www.cocoabuilder.com/archive/message/cocoa/2005/1/31/127185

    Matt Gough
previous month november 2007 next month
MTWTFSS
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
Go to today