1

This is my image resize code:

CALayer *newCALayer = [[CALayer layer] retain];
NSImage* image = [[NSImage alloc] initWithData:[NSData  dataWithContentsOfFile:path]];
CGImageRef newCGImageFullResolution = [image CGImageForProposedRect:nil context:nil hints:nil];
CGContextRef context = CGBitmapContextCreate(NULL, drawRect.size.width, drawRect.size.height,
                                             CGImageGetBitsPerComponent(newCGImageFullResolution),
                                             CGImageGetBytesPerRow(newCGImageFullResolution),
                                             CGImageGetColorSpace(newCGImageFullResolution),
                                             CGImageGetAlphaInfo(newCGImageFullResolution));
CGContextDrawImage(context, CGRectMake(0, 0, drawRect.size.width, drawRect.size.height), newCGImageFullResolution);
CGImageRef scaledImage = CGBitmapContextCreateImage(context);
newCALayer.contents = (id)scaledImage;
CGImageRelease(scaledImage);
newCALayer.contentsGravity = kCAGravityResizeAspect;
newCALayer.opacity = 0.0;
newCALayer.anchorPoint = CGPointMake(0.0f,0.0f);
newCALayer.frame = CGRectMake( 0.0, 
          0.0, 
          [Singleton sharedSingleton].fullscreenRect.size.width,
          [Singleton sharedSingleton].fullscreenRect.size.height);
[newCALayer setAutoresizingMask:kCALayerWidthSizable | kCALayerHeightSizable];
//CGImageRelease(cgImageFullResolution); (bonus points if you can explain why I can't release this! I mean, I can release the scaled image ok??)
CGContextRelease(context);
[image release];

I am doing all of this from a background thread in order to preload pictures so my GUI feels snappy. It took some work getting synchronization and what not set up so the CALayers ends up in view.

But I believe the term for describing how fast this is would be "it's a dog".

Comparing to IKImageView - that thing flings up thumbnails of images faster than I can scroll.

Does anybody have some suggestions for how to handle this better than I am doing it now?

In other words, my problem is that I want to have a super-fast UX. I believe the way to accomplish this is by preloading things to CALayers (this may be wrong? I tried NSImageView and some IK-stuff, but at least CALayer is better than that).

Jon Schneider
  • 25,758
  • 23
  • 142
  • 170
Torkel
  • 88
  • 6
  • Do you need OS X 10.5 compatibility, or is 10.6-only OK? (The code you've posted already requires 10.6, but would help to clarify). – NSGod Jan 31 '11 at 12:51
  • 10.6 only is fine. The app-store sort of hit "reset" on compatibilities, no? :) – Torkel Jan 31 '11 at 14:49

2 Answers2

2

ImageKit is probably using CGImageSourceCreateThumbnailAtIndex() to quickly get an image appropriate to the destination, rather than reading in the entire image file.

Mike Abdullah
  • 14,933
  • 2
  • 50
  • 75
  • Interesting!! I wanted to use NSImage because it seems to be capable of reading just about every image file format there is. But maybe I could use some test if a file is readable through CGImageSource first and only use NSImage if that fails... Gonna give it a go to compare speed of it. – Torkel Jan 31 '11 at 14:48
  • Make sure you understand what makes `CGImageSourceCreateThumbnailAtIndex()` different. The point is that it saves you having to handle the entirety of a large image. – Mike Abdullah Jan 31 '11 at 15:39
  • Ok, this is the answer. This function is blazingly fast. But I cannot for the life of me make anything but a very blurry image out of it. (I tried to put kCGImageSourceThumbnailMaxPixelSize to a few million - still blurry). Also, thinking about it, iPhoto also takes som .3 seconds or so to load an image. And having now tested just about all possible combinations of ways of loading images, I now believe that's just how much time it takes to load and scale an image. – Torkel Jan 31 '11 at 18:24
1

Here:

NSImage *image = [[[NSImage alloc] initWithContentsOfFile:path] autorelease];
[image setScalesWhenResized:YES]; // *
[image setDataRetained:YES]; // *
[image setSize:desiredNewSize];

Then use the image as it is.

As for why your app is slow, run it under Instruments. That will tell you specifically where you are spending the majority of the processor time you use—it may not be in your scaling code after all.

*Since 10.6, these messages do nothing useful and are deprecated, so you can omit them if you are requiring Snow Leopard or later.

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370
  • Thank you for your reply. I replaced my code with this, but the speed is the same. And for some reason with your way of doing things it seems like the processing isn't done until the view is displayed. (So, when the view is set to visible the first time, there is a huge (30s) delay until it's visible). Gonna try instruments now. – Torkel Jan 31 '11 at 09:03
  • Instruments didn't really give me that much information. Might not be proficient enough user to find out more than that loading images eats my CPUtime... Next up I'm gonna try replacing the CGImage and just use NSImage, as described in another suggestion here. – Torkel Jan 31 '11 at 14:29
  • @Torkel: What do you mean “another suggestion”? That's this suggestion. ☺ – Peter Hosey Jan 31 '11 at 15:15