I strongly suggest reading the release notes on NSImage in the Application Kit release notes for Snow Leopard.

it has many, many, changes. These won't translate to the Cocoa Drawing Guide for a bit yet. Sadly.


On Sep 25, 2009, at 7:22 PM, John Horigan wrote:

I have a drawing program that creates an NSBitmapImageRep and an NSImage:

mImage = [[NSImage alloc] initWithSize: size];
mBitmap = [[NSBitmapImageRep alloc]
                          initWithBitmapDataPlanes: NULL
                         pixelsWide: (int)size.width
                         pixelsHigh: (int)size.height
                         bitsPerSample: 8 samplesPerPixel: 4
                         hasAlpha: YES isPlanar: NO
                         colorSpaceName: NSCalibratedRGBColorSpace
                         bytesPerRow: 0 bitsPerPixel: 0];
[mImage addRepresentation: mBitmap];

later I get the pointer to the bitmap data using the bitmapData method and hand it over drawing code (AGG) running in another thread. Periodically the render thread will send a message to the main thread telling it to draw the current image state to my view:

   [mView performSelectorOnMainThread: @selector(redisplayImage:)
           withObject: [NSValue valueWithRect:
           NSMakeRect(cropX(), cropY(), cropWidth(), cropHeight())]
           waitUntilDone: YES];


The redisplayImage method in my view class calls the display method

- (void)redisplayImage:(NSValue*)rectObj
{
   mRenderedRect = [rectObj rectValue];
   [self display];
}

Note that the render thread is waiting for redisplayImage to complete and the redisplayImage method is calling the display method, not the setNeedsDisplay method. The views's drawRect method looks like so:

- (void)drawRect:(NSRect)rect
{
        NSSize fSize = [self frame].size;
        NSSize rSize = [mBitmap size];
        
        float scale;
        if (rSize.width <= fSize.width  &&  rSize.height <= fSize.height) {
                // rendered area fits within frame, center it
                scale = 1.0f;
        }
        else {
                float wScale = fSize.width / rSize.width;
                float hScale = fSize.height / rSize.height;
                scale = (hScale < wScale) ? hScale : wScale;
        }
        
        NSRect dRect;

        // center scaled image rectangle
        dRect.size.width = rSize.width * scale;
        dRect.size.height = rSize.height * scale;
        dRect.origin.x = floorf((fSize.width - dRect.size.width) / 2.0f);
        dRect.origin.y = floorf((fSize.height - dRect.size.height) / 2.0f);

       [[NSColor colorWithDeviceRed: backgroundColor.r
                         green: backgroundColor.g
                         blue: backgroundColor.b
                         alpha: backgroundColor.a ] set];
       [NSBezierPath fillRect: rect];

       [mImage drawInRect: dRect fromRect: NSZeroRect
                        operation: NSCompositeSourceAtop
                        fraction: 1.0];
}

Prior to Snow Leopard this all worked fine. The images drawn onto the bitmap in the rendering thread would be drawn into the view. If the view was resized smaller then the NSImage would be shrunk and centered. If the view was resized larger the NSImage would be centered.

But with Snow Leopard [mImage drawInRect ...] draws from the bitmap only the first time it is called. All subsequent calls to the drawInRect method draw whatever was in the bitmap on the first call, not the current contents of the bitmap. It's as if the NSBitmapImageRep was being cached on the first draw and the cached copy was used from then on.

However, if I resize the window so that the drawing NSRect is smaller than the NSBitmapImageRep (i.e., the bitmap has to be scaled) then the current bitmap is drawn. And then if I expand the window to be larger then it goes back drawing the cached bitmap. Shrinking the window really small seems to reset something in the NSBitmapImageRep, then it draws from the current bitmap whether there is scaling or not.

It seems that under Snow Leopard the NSBitmapImageRep is being cached somewhere (video memory?) and as long as there is no scaling the cached version of the NSBitmapImageRep is being used by drawInRect instead of of the bitmap in system memory. For some reason making the view really small causes drawInRect to use the data in system memory.

Here are some things that I tried:
1) Calling the NSImage recache method: [mImage recache];
2) Getting rid of the NSImage and using the NSImageRep drawInRect method to draw in the view. 3) Call the NSBitmapImageRep bitmapData method before writing to the bitmap data plane in the rendering thread

#1 and #2 has no effect. NSImage-level caching does not appear to be the problem. There appears to be caching by NSBitmapImageRep. #3 was an attempt to get Snow Leopard to invalidate the NSBitmapImageRep cache. It didn't work.

So this is what worked:
4) Keep the bitmap data plane as a separate data structure, owned by the view. The redisplayImage method creates a new NSBitmapImageRep and NSImage every time it is called, using the bitmap data structure that is owned by the view.

While creating new NSImages and NSBitmapImageReps all the time works I hate doing all this object churning. Is there some way to use a single NSImage and NSBitmapImageRep throughout the life of the view?

-- john


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/scott%40cocoadoc.com

This email sent to sc...@cocoadoc.com

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to