16

Is there an easy way to do this that works in 10.5?

In 10.6 I can use nsImage CGImageForProposedRect: NULL context: NULL hints: NULL

If I'm not using 1b black and white images (Like Group 4 TIFF), I can use bitmaps, but cgbitmaps seem to not like that setup... Is there a general way of doing this?

I need to do this because I have an IKImageView that seems to only want to add CGImages, but all I've got are NSImages. Currently, I'm using a private setImage:(NSImage*) method that I'd REALLY REALLY rather not be using...

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
Brian Postow
  • 11,709
  • 17
  • 81
  • 125
  • Do you know where I can get an example of how to use CGImageForProposedRect: NULL context: NULL hints: NULL. I am supplying a NSRect for the first parameter but I am getting a type mismatch on it. – Brian Jan 14 '11 at 21:26
  • I don't know I never tried it with anything except NULL... possibly a CGRect instead of an NSRect? – Brian Postow Jan 28 '11 at 15:12

6 Answers6

32

Found the following solution on this page:

NSImage* someImage;
// create the image somehow, load from file, draw into it...
CGImageSourceRef source;

source = CGImageSourceCreateWithData((CFDataRef)[someImage TIFFRepresentation], NULL);
CGImageRef maskRef =  CGImageSourceCreateImageAtIndex(source, 0, NULL);

All the methods seem to be 10.4+ so you should be fine.

pheelicks
  • 7,461
  • 2
  • 45
  • 50
  • 7
    Yeah, but don't call `TIFFRepresentation` hundreds of times. Depending on the `NSImage`, it can end up creating a full, uncompressed copy of the image data in memory. – Alex Mar 30 '10 at 21:48
  • interesting. I'll try that and let you know. – Brian Postow Mar 31 '10 at 15:10
  • 2
    This is less good for both performance and predictability than Peter's solution. If the image has multiple representations (e.g. a 16x16 version and a 128x128 version), which do you get this way? Undefined. – Ken Apr 20 '10 at 23:33
18

[This is the long way around. You should only do this if you're still supporting an old version of OS X. If you can require 10.6 or later, just use the CGImage method instead.]

  1. Create a CGBitmapContext.
  2. Create an NSGraphicsContext for the bitmap context.
  3. Set the graphics context as the current context.
  4. Draw the image.
  5. Create the CGImage from the contents of the bitmap context.
  6. Release the bitmap context.
Community
  • 1
  • 1
Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
  • I've tried this, and it either seems to not work with 1 bit B/W images (macs for some reason really don't like to deal with CCITT TIFFs...) or loses resolution... Since I have an NSImage, I'm not sure that I actually can FIND the resolution to figure out how to make a better graphics context... – Brian Postow Mar 31 '10 at 15:09
  • Look in the image's `representations` array. One of them should be a bitmap image rep. You can ask that object for the size in pixels (as opposed to points), among other raster-related facts. – Peter Hosey Mar 31 '10 at 15:45
  • 3
    Peter, you're a member that I've come to admire and trust here on SO. Thank you for all the knowledge and experience that you share, and the thoroughness with which you present it. – MikeyWard Sep 10 '12 at 10:00
  • @MikeyWard: You're welcome, and thank you for the kind words. – Peter Hosey Sep 11 '12 at 00:13
  • instead of links, can you convert this to code? thanks. – Duck Mar 01 '15 at 22:15
16

As of Snow Leopard, you can just ask the image to create a CGImage for you, by sending the NSImage a CGImageForProposedRect:context:hints: message.

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
16

Here's a more detailed answer for using - CGImageForProposedRect:context:hints::

NSImage *image = [NSImage imageNamed:@"image.jpg"];

NSRect imageRect = NSMakeRect(0, 0, image.size.width, image.size.height);

CGImageRef cgImage = [image CGImageForProposedRect:&imageRect context:NULL hints:nil];
Kane Cheshire
  • 1,654
  • 17
  • 20
1

Just did this using CGImageForProposedRect:context:hints:...

NSImage *image; // an image
NSGraphicsContext *context = [NSGraphicsContext currentContext];
CGRect imageCGRect = CGRectMake(0, 0, image.size.width, image.size.height);
NSRect imageRect = NSRectFromCGRect(imageCGRect);
CGImageRef imageRef = [image CGImageForProposedRect:&imageRect context:context hints:nil];
simioliolio
  • 209
  • 3
  • 7
0

As of 2021, CALayers contents can directly be feed with NSImage but you still may get an
[Utility] unsupported surface format: LA08 warning. After a couple of days research and testing around i found out that this Warning is triggered if you created an NSView with backingLayer, aka CALayer and just used an NSImage to feed its contents. This alone is not much of a problem. But if you try to render it via [self.layer renderInContext:ctx], each rendering will trigger the warning again.

To make use simple, i created an NSImage extension to fix this..

@interface NSImage (LA08FIXExtension)
-(id)CGImageRefID;
@end

@implementation NSImage (LA08FIXExtension)

-(id)CGImageRefID {
    NSSize size = [self size];
    NSRect rect = NSMakeRect(0, 0, size.width, size.height);
    CGImageRef ref = [self CGImageForProposedRect:&rect context:[NSGraphicsContext currentContext] hints:NULL];
    return (__bridge id)ref;
}

@end

see how it does not return an CGImageRef directly but a bridged cast to id..! This does the trick.

Now you can use it like..

CALayer *somelayer = [CALayer layer];
somelayer.frame = ... 
somelayer.contents = [NSImage imageWithName:@"SomeImage"].CGImageRefID;

PS: posted her because if you got that problem also, google will lead you to this Thread of answers anyway, and all above answers inspired me for this fix.

Ol Sen
  • 3,163
  • 2
  • 21
  • 30