I am looking to downscale a UIImage
in iOS
.
I have seen other questions below and their approach on how to downscale the image by size.
Resizing Images Objective-C
How to resize the image programmatically in objective-c in iphone
The simplest way to resize an UIImage?
These questions are all based on re-sizing the image to a specific size. In my case I am looking to re-size/downscale the image based on a maximum size.
As an example, I would like to set a maximum NSData
size to be 500 KB. I know that I can get the size of the image like this:// Check the size of the image returned
NSData *imageData = UIImageJPEGRepresentation(image, 0.5);
// Log out the image size
NSLog(@"%lu KB",(imageData.length/1024));
What I would like to do is some form of loop here. If the size is greater than the maximum size that I set, I would like to scale down the image slightly, then check the size. If the size is still too large scale down again slightly then check again, until it is lower than the maximum set size.
I am not sure what the best approach for this is. Ideally I do not want to scale down the image to a specific size all the time, but only slightly scale down the image each time. That way I can have the largest (size w/h) of the image itself and at its maximum size (bytes). If I scale down slightly only at a time, what would be the best way to accomplish this?
EDIT
To confirm, I am looking to re-size the actual image but re-size the image so that it is smaller than the maximum NSData
Length.
For example:
-Check the NSData
Length
-If above the maximum I want to pass the UIImage into a method
-Then loop through this method slightly re-sizing the actual image size each time
-Until it is under the maximum NSData
length, then return the image?
Right now, you have a routine that says:
// Check if the image size is too large
if ((imageData.length/1024) >= 1024) {
while ((imageData.length/1024) >= 1024) {
NSLog(@"While start - The imagedata size is currently: %f KB",roundf((imageData.length/1024)));
// While the imageData is too large scale down the image
// Get the current image size
CGSize currentSize = CGSizeMake(image.size.width, image.size.height);
// Resize the image
image = [image resizedImage:CGSizeMake(roundf(((currentSize.width/100)*80)), roundf(((currentSize.height/100)*80))) interpolationQuality:kMESImageQuality];
// Pass the NSData out again
imageData = UIImageJPEGRepresentation(image, kMESImageQuality);
}
}
I wouldn't advise recursively resizing the image. Every time you resize, you lose some quality (often manifesting itself as a "softening" of the image with loss of detail, with cumulative effects). You always want to go back to original image and resize that smaller and smaller. (As a minor aside, that if
statement is redundant, too.)
I might suggest the following:
NSData *imageData = UIImageJPEGRepresentation(image, kMESImageQuality);
double factor = 1.0;
double adjustment = 1.0 / sqrt(2.0); // or use 0.8 or whatever you want
CGSize size = image.size;
CGSize currentSize = size;
UIImage *currentImage = image;
while (imageData.length >= (1024 * 1024))
{
factor *= adjustment;
currentSize = CGSizeMake(roundf(size.width * factor), roundf(size.height * factor));
currentImage = [image resizedImage:currentSize interpolationQuality:kMESImageQuality];
imageData = UIImageJPEGRepresentation(currentImage, kMESImageQuality);
}
Note, I'm not touching image
, the original image, but rather assigning currentImage
by doing a resize from the original image each time, by a decreasing scale each time.
BTW, if you're wondering about my cryptic 1.0 / sqrt(2.0)
, I was trying to draw a compromise between your iterative 80% factor and my desire to favor resizing by a power of 2 where I can (because a reduction retains more sharpness when done by a power of 2). But use whatever adjustment
factor you want.
Finally, if you're doing this on huge images, you might think about using @autoreleasepool
blocks. You'll want to profile your app in Allocations in Instruments and see where your high water mark is, as in the absence of autorelease pools, this may constitute a fairly aggressive use of memory.