Undocumented UIImage resizing
Last week, I was trying to resize an image in the iPhone SDK. Those who don’t know anything about Objective-C and are not interested should stop reading right… here.
Alright. Those who are still with me here know what I’m talking about: there is no easy documented way to resize a UIImage object. Unlike NSImage (on the Mac OSX platform) which supports the message setSize:, UIImage documentation is lacking any such methods.
Oh wait. That exists, though it’s the undocumented message _imageScaledToSize:interpolationQuality:… and unfortunately, what is undocumented from Apple will soon be unsupported or renamed. And it gives a warning about “method not found”, of course, which can be circumvented with the following category:
// WARNING: these methods are not documented, but exist as of SDK version 2.1 @interface UIImage (UndocumentedUIImage) - (UIImage*)_imageScaledToSize:(CGSize)newSize interpolationQuality:(float)aQuality; @end
Nothing new under the sun, it has been documented elsewhere on the net . But how can we build a similar function using only Apple-approved (at this time) code? The answer is quite simple, though
First, we create a small graphic context with the new size we want to give it. Then you draw the image in there, and take it back. We pack it all nicely in a category and hop! instant wootness.
@interface UIImage (INResizeImageAllocator) + (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize; - (UIImage*)scaleImageToSize:(CGSize)newSize; @end @implementation UIImage (INResizeImageAllocator) + (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize; { UIGraphicsBeginImageContext( newSize ); [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)]; UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } - (UIImage*)scaleImageToSize:(CGSize)newSize { return [UIImage imageWithImage:self scaledToSize:newSize]; } @end
Just copy this code somewhere, the @interface part in a .h and the @implementation where it belongs. You have an allocator and a member function that looks close enough to the undocumented way. There is no quality parameter, unfortunately we don’t have control over this anymore.
To be honest, it is probably slower than the unofficial way. It probably use custom code instead of creating and destroying a context, and the quality parameter hints to some optimizations. Also, it is very probably that Apple will include the _imageScaledToSize:interpolationQuality: selector in a future version of the SDK, and rename it.
Until then, this method is the simplest way to go.
Brilliant. Simple and neat solution to a vexing problem. I guess they left the resizing out because most of the time you’ll be using UIImageView, which handles the scaling for you. Unfortunately, the UIImageView for an image on a UITableViewCell isn’t accessible, so you’re stuffed if you don’t manually resize your image to the correct size.
Thanks !
Actually, you can put
UIImageViewon aUITableViewCellby putting it as a subview. Nothing wrong with that. Something along:Should work out of the box. But what I use my solution for mainly is when taking pictures in the image album and then using them in a
CALayer, which cannot take images larger than 1024×1024. Also, managing resources by releasing the original… saves a lot of memory.The solution is great and seems to be working for everyone. But I’ve got a problem here. I need to save a smaller version of an image to file, so I do the following:
The file it creates is of the required size, but blank – just a white rectangle. The undocumented method does just the same. I’m totally noob, so my mistake must be painfully stupid, but I’m stuck here. Any ideas what could be wrong?
Thank you!
I’ve just found out that it works when the initial picture is of PNG format, but it makes blank resized images for JPG. Must be some obvious reason, but I just don’t get it.
PS What is the correct tag for quoting code in here?
Hey Thorny,
The right way to put code here is with the <pre lang=”objc”>. For syntax highlighting, you can change the lang parameter. There is also a way to put line numbers in there. I might change the syntax plugin to use a different tag and put something above the textarea in the theme to list the available tags.
I’m gonna try with a JPG and a PNG to see what could be the problem. I’m as much surprised as you are.
very nice, thanks
[...] also made a post here about how to resize images [...]
[...] Image resizing: http://ofcodeandmen.poltras.com/2008/10/30/undocumented-uiimage-resizing/ [...]
If you don’t like undocumented calls, you can just create a new bitmap graphic context, make it the current context, set up the correct affine transform, draw the source into it with CGContextDrawImage(), and tell it to hand you back the UIImage.
If you don’t need the image handed back, then just set the correct affine transform of the current context, and CGContextDrawImage() the source into it
I’m newbie and curious. Will i be responsible for releasing the image received by the created methods?
@GM: the image is autoreleased. Check out
UIGraphicsGetImageFromCurrentImageContext()documentation for details.@DavidPhillipOster: That’s what I do, but I use drawInRect instead of using bitmap+transform. Your method might be faster, but not by much.
Given that this category contains drawing code, you’ll need to make sure you only resize images on the main thread. (I would get EXEC_BAD_ACCESS errors whenever I resized images on a separate thread while running on the device.)
Thanks. Nitpick: I would have named it -imageByScalingToSize: instead of -scaleImageToSize:, following the Cocoa naming convention of hinting what type will be returned.
Thanks for this post!
Has anyone found a solution for scaling JPEG ?
Thank you!!! This works great.
[...] be skewed so cropping was required. All of the examples I found either focused on cropping only or resizing but I couldn’t find any that did [...]
Awesome, thanks for posting this. Just what I needed.
Does anyone know what the “interpolationQuality:” parameter does? And how to replicate that behavior if you implement it yourself? Thanks,
See CGContextSetInterpolationQuality(bitmap, interpolationQuality);
- (UIImage*)imageWithImage:(UIImage*)image
scaledToSize:(CGSize)newSize
iQ:(double)interpolationQuality;
{
UIGraphicsBeginImageContext( newSize );
CGContextSetInterpolationQuality(UIGraphicsGetCurrentContext(), interpolationQuality);
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}