Reputation: 17882
I have a UIImage that the user has uploaded.
If the image data is more than 10Mb how can I resize it to a maximum of 10 Mb? So far the closest thing I've found for data resizing is this:
NSData *imageData = UIImageJPEGRepresentation(theUploadedImage.image, 0.5f);
But I don't seem to have control over the Mb of file size... just over the second parameter in the JPG representation (image quality float)
Upvotes: 4
Views: 3543
Reputation: 17882
Had to create my own function that compresses an image as small as it can get, and if it's still over my "max size" then it resizes, reserves and begins the compression iteration again. This does a fairly good job of getting the image as close as possible to target "max image file size" if it's over the file size. Also includes a failsafe after 1024 iterations. (Which should never last longer than a minute (but that's a scenario that would never occour... who uses images that are gigabytes on an iPhone? Haha))...
-(void)shrinkImage {
//IMPORTANT!!! THIS CODE WAS CREATED WITH "ARC" IN MIND... DO NOT USE WITHOUT ARC UNLESS YOU ALTER THIS CODE TO MANAGE MEMORY
float compressionVal = 1.0;
float maxVal = 9.7;//MB
UIImage *compressedImage = theUploadedImage.image; //get UIImage from imageView
int iterations = 0;
int totalIterations = 0;
float initialCompressionVal = 0.00000000f;
while (((((float)(UIImageJPEGRepresentation(compressedImage, compressionVal).length))/(1048576.000000000f)) > maxVal) && (totalIterations < 1024)) {
NSLog(@"Image is %f MB", (float)(((float)(UIImageJPEGRepresentation(compressedImage, compressionVal)).length)/(1048576.000000f)));//converts bytes to MB
compressionVal = (((compressionVal)+((compressionVal)*((float)(((float)maxVal)/((float)(((float)(UIImageJPEGRepresentation(compressedImage, compressionVal).length))/(1048576.000000000f)))))))/(2));
compressionVal *= 0.97;//subtracts 3% of it's current value just incase above algorithm limits at just above MaxVal and while loop becomes infinite.
if (initialCompressionVal == 0.00000000f) {
initialCompressionVal = compressionVal;
}
iterations ++;
if ((iterations >= 3) || (compressionVal < 0.1)) {
iterations = 0;
NSLog(@"%f", compressionVal);
compressionVal = 1.0f;
compressedImage = [UIImage imageWithData:UIImageJPEGRepresentation(compressedImage, compressionVal)];
float resizeAmount = 1.0f;
resizeAmount = (resizeAmount+initialCompressionVal)/(2);//percentage
resizeAmount *= 0.97;//3% boost just incase image compression algorithm reaches a limit.
resizeAmount = 1/(resizeAmount);//value
initialCompressionVal = 0.00000000f;
UIView *imageHolder = [[UIView alloc] initWithFrame:CGRectMake(0,0,(int)floorf((float)(compressedImage.size.width/(resizeAmount))), (int)floorf((float)(compressedImage.size.height/(resizeAmount))))];//round down to ensure frame isnt larger than image itself
UIImageView *theResizedImage = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,(int)ceilf((float)(compressedImage.size.width/(resizeAmount))), (int)ceilf((float)(compressedImage.size.height/(resizeAmount))))];//round up to ensure image fits
theResizedImage.image = compressedImage;
[imageHolder addSubview:theResizedImage];
UIGraphicsBeginImageContextWithOptions(CGSizeMake(imageHolder.frame.size.width, imageHolder.frame.size.height), YES, 1.0f);
CGContextRef resize_context = UIGraphicsGetCurrentContext();
[imageHolder.layer renderInContext:resize_context];
compressedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//after 3 compressions, if we still haven't shrunk down to maxVal size, apply the maximum compression we can, then resize the image (90%?), then re-start the process, this time compressing the compressed version of the image we were checking.
NSLog(@"resize");
}
totalIterations ++;
}
if (totalIterations >= 1024) {
NSLog(@"Image was too big, gave up on trying to re-size");//too many iterations failsafe. Gave up on trying to resize.
} else {
NSData *imageData = UIImageJPEGRepresentation(compressedImage, compressionVal);
NSLog(@"FINAL Image is %f MB ... iterations: %i", (float)(((float)imageData.length)/(1048576.000000f)), totalIterations);//converts bytes to MB
theUploadedImage.image = [UIImage imageWithData:imageData];//save new image to UIImageView.
}
}
Upvotes: 2