开发者

Display NSImage on a CALayer

开发者 https://www.devze.com 2023-02-10 02:43 出处:网络
I\'ve been trying to display a NSImage on a CALayer. Then I realised I need to convert it to a CGImage apparently, then display it...

I've been trying to display a NSImage on a CALayer. Then I realised I need to convert it to a CGImage apparently, then display it...

I have this code which doesn't seem to be working

CALayer *layer = [CALayer layer];

    NSImage *finderIcon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kFinderIcon)];
    [finderIcon setSize:(NSSize){ 128.0f, 128.0f }];

    CGImageSourceRef source;
    source = CGImageSourceCreateWithData((CFDataRef)finderIcon, NULL);
    CGImageRef finalIcon =  CGImageSourceCreateImageAtIndex(source, 0, NULL);

    layer.bounds = CGRectMake(128.0f, 128.0f, 4, 4);
    layer.position = CGPointMake(128.0f, 128.0f);
    layer.contents = finalIcon;

        // Insert the layer into the root layer
    [开发者_运维技巧mainLayer addSublayer:layer];

Why? How can I get this to work?


From the comments: Actually, if you're on 10.6, you can also just set the CALayer's contents to an NSImage rather than a CGImageRef...


If you're on OS X 10.6 or later, take a look at NSImage's CGImageForProposedRect:context:hints: method.

If you're not, I've got this in a category on NSImage:

-(CGImageRef)CGImage
{
    CGContextRef bitmapCtx = CGBitmapContextCreate(NULL/*data - pass NULL to let CG allocate the memory*/, 
                                                   [self size].width,  
                                                   [self size].height, 
                                                   8 /*bitsPerComponent*/, 
                                                   0 /*bytesPerRow - CG will calculate it for you if it's allocating the data.  This might get padded out a bit for better alignment*/, 
                                                   [[NSColorSpace genericRGBColorSpace] CGColorSpace], 
                                                   kCGBitmapByteOrder32Host|kCGImageAlphaPremultipliedFirst);

    [NSGraphicsContext saveGraphicsState];
    [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:bitmapCtx flipped:NO]];
    [self drawInRect:NSMakeRect(0,0, [self size].width, [self size].height) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
    [NSGraphicsContext restoreGraphicsState];

    CGImageRef cgImage = CGBitmapContextCreateImage(bitmapCtx);
    CGContextRelease(bitmapCtx);

    return (CGImageRef)[(id)cgImage autorelease];
}

I think I wrote this myself. But it's entirely possible that I ripped it off from somewhere else like Stack Overflow. It's an older personal project and I don't really remember.


Here's some code which may help you - I sure hope the formatting of this does not get all messed up like it appears is going to happen - all I can offer is that this works for me.

// -------------------------------------------------------------------------------------

- (void)awakeFromNib
    {
    // setup our main window 'contentWindow' to use layers
    [[contentWindow contentView] setWantsLayer:YES];    // NSWindow*

    // create a root layer to contain all of our layers
    CALayer *root = [[contentWindow contentView] layer];
    // use constraint layout to allow sublayers to center themselves
    root.layoutManager = [CAConstraintLayoutManager layoutManager];

    // create a new layer which will contain ALL our sublayers
    // -------------------------------------------------------
    mContainer      = [CALayer layer];
    mContainer.bounds   = root.bounds;
    mContainer.frame    = root.frame;
    mContainer.position = CGPointMake(root.bounds.size.width  * 0.5, 
                      root.bounds.size.height * 0.5);

    // insert layer on the bottom of the stack so it is behind the controls
    [root insertSublayer:mContainer atIndex:0];

    // make it resize when its superlayer does 
    root.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;

    // make it resize when its superlayer does 
    mContainer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
    }

// -------------------------------------------------------------------------------------

- (void) loadMyImage:(NSString*) path 
           n:(NSInteger) num
           x:(NSInteger) xpos 
           y:(NSInteger) ypos 
           h:(NSInteger) hgt 
           w:(NSInteger) wid
           b:(NSString*) blendstr
    {
    #ifdef __DEBUG_LOGGING__
    NSLog(@"loadMyImage - ENTER [%@] num[%d] x[%d] y[%d] h[%d] w[%d] b[%@]", 
                                   path, num, xpos, ypos, hgt, wid, blendstr);
    #endif

    NSInteger xoffset = ((wid / 2) + xpos); // use CORNER versus CENTER for location
    NSInteger yoffset = ((hgt / 2) + ypos); 
    CIFilter* filter  = nil;

    CGRect cgrect = CGRectMake((CGFloat) xoffset, (CGFloat) yoffset, 
                                   (CGFloat) wid, (CGFloat) hgt);

    if(nil != blendstr) // would be equivalent to @"CIMultiplyBlendMode" or similar
        {
        filter = [CIFilter filterWithName:blendstr];    
        }

        // read image file via supplied path
    NSImage* theimage = [[NSImage alloc] initWithContentsOfFile:path]; 

    if(nil != theimage)
        {
        [self setMyImageLayer:[CALayer layer]];    // create layer
        myImageLayer.frame = cgrect;           // locate & size image
        myImageLayer.compositingFilter = filter;   // nil is OK if no filter
        [myImageLayer setContents:(id) theimage];  // deposit image into layer
                // add new layer into our main layer [see awakeFromNib above]
        [mContainer insertSublayer:myImageLayer atIndex:0]; 
        [theimage release];
        }
    else
        {
        NSLog(@"ERROR loadMyImage - no such image [%@]", path);
        }
    }


+ (CGImageRef) getCachedImage:(NSString *) imageName
{
    NSGraphicsContext *context = [[NSGraphicsContext currentContext] graphicsPort];

    NSImage *img =  [NSImage imageNamed:imageName];

    NSRect rect = NSMakeRect(0, 0, [img size].width, [img size].height);
    return [img CGImageForProposedRect:&rect context:context hints:NULL];
}


+ (CGImageRef) getImage:(NSString *) imageName withExtension:(NSString *) extension
{
    NSGraphicsContext *context = [[NSGraphicsContext currentContext] graphicsPort];

    NSString* imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:extension];
    NSImage* img = [[NSImage alloc] initWithContentsOfFile:imagePath];

    NSRect rect = NSMakeRect(0, 0, [img size].width, [img size].height);
    CGImageRef imgRef = [img CGImageForProposedRect:&rect context:context hints:NULL];

    [img release];

    return imgRef;
}

then you can set it:

yourLayer.contents = (id)[self getCachedImage:@"myImage.png"];

or

yourLayer.contents = (id)[self getImage:@"myImage" withExtension:@"png"];

0

精彩评论

暂无评论...
验证码 换一张
取 消