76

I'm currently uploading an image to a server using Imgur on iOS with the following code:

NSData* imageData = UIImagePNGRepresentation(image);
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* fullPathToFile = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"SBTempImage.png"];
[imageData writeToFile:fullPathToFile atomically:NO];

[uploadRequest setFile:fullPathToFile forKey:@"image"];

The code works fine when run in the simulator and uploading a file from the simulator's photo library because I'm on a fast ethernet connection. However, the same code times out on the iPhone when selecting an image taken with the iPhone. So, I tried it by saving a small image from the web and attempting to upload that, which worked.

This leads me to believe the large images taken by the iPhone are timing out over the somewhat slow 3G network. Is there any way to compress/resize the image from the iPhone before sending it?

Cœur
  • 37,241
  • 25
  • 195
  • 267
joshholat
  • 3,371
  • 9
  • 39
  • 48

13 Answers13

203

This snippet will resize the image:

UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

The variable newSize is a CGSize and can be defined like so:

CGSize newSize = CGSizeMake(100.0f, 100.0f);
JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Tuan Nguyen
  • 2,146
  • 2
  • 13
  • 7
38

A self-contained solution:

- (UIImage *)compressForUpload:(UIImage *)original scale:(CGFloat)scale
{
    // Calculate new size given scale factor.
    CGSize originalSize = original.size;
    CGSize newSize = CGSizeMake(originalSize.width * scale, originalSize.height * scale);

    // Scale the original image to match the new size.
    UIGraphicsBeginImageContext(newSize);
    [original drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *compressedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return compressedImage;
}

Thanks to @Tuan Nguyen.

Zorayr
  • 23,770
  • 8
  • 136
  • 129
16

To complement @Tuan Nguyen, this is maybe the fastest and most elegant way to do that.

To link to John Muchow's post at iphonedevelopertips.com , adding a category to a UIImage is a very very handy way to scale in a very fast fashion. Just calling

    UIImage *_image = [[[UIImage alloc] initWithData:SOME_NSDATA] scaleToSize:CGSizeMake(640.0,480.0)];

returns you a 640x480 representation image of your NSDATA ( that could be an online image ) without any more line of code.

nont
  • 9,322
  • 7
  • 62
  • 82
nembleton
  • 2,392
  • 1
  • 18
  • 20
  • 1
    It actually scales down the pixels. So it also reduces the size that the pic is taking. But it doesn't do a "recompression" per se. If that's what you are mentioning here. – nembleton Jun 07 '13 at 03:41
7

Matt Gemmell's MGImageUtilities are very nice, resizing efficiently and with some effort-reducing methods.

Matthew Frederick
  • 22,245
  • 10
  • 71
  • 97
6

In this code 0.5 means 50% ...

UIImage *original = image;
UIImage *compressedImage = UIImageJPEGRepresentation(original, 0.5f);
Jagandeep Singh
  • 364
  • 4
  • 8
5

use this simple method NSData *data = UIImageJPEGRepresentation(chosenImage, 0.2f);

3

Swift implementation of Zorayr's function (with a bit of a change to include height or width constraints by actual units not scale):

class func compressForUpload(original:UIImage, withHeightLimit heightLimit:CGFloat, andWidthLimit widthLimit:CGFloat)->UIImage{

    let originalSize = original.size
    var newSize = originalSize

    if originalSize.width > widthLimit && originalSize.width > originalSize.height {

        newSize.width = widthLimit
        newSize.height = originalSize.height*(widthLimit/originalSize.width)
    }else if originalSize.height > heightLimit && originalSize.height > originalSize.width {

        newSize.height = heightLimit
        newSize.width = originalSize.width*(heightLimit/originalSize.height)
    }

    // Scale the original image to match the new size.
    UIGraphicsBeginImageContext(newSize)
    original.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))
    let compressedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return compressedImage
}
PJeremyMalouf
  • 613
  • 6
  • 15
  • 2
    this solution is nice, but it does not work for square images. because of originalSize.width > originalSize.height and originalSize.height > originalSize.width so better change one to >= :-) – rcpfuchs Apr 25 '16 at 12:56
0
#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>

+ (UIImage *)resizeImage:(UIImage *)image toResolution:(int)resolution {
NSData *imageData = UIImagePNGRepresentation(image);
CGImageSourceRef src = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
CFDictionaryRef options = (__bridge CFDictionaryRef) @{
                                                       (id) kCGImageSourceCreateThumbnailWithTransform : @YES,
                                                       (id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
                                                       (id) kCGImageSourceThumbnailMaxPixelSize : @(resolution)
                                                       };
CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options);
CFRelease(src);
UIImage *img = [[UIImage alloc]initWithCGImage:thumbnail];
return img;
}
Shaik Riyaz
  • 11,204
  • 7
  • 53
  • 70
Vineet Ravi
  • 1,457
  • 2
  • 12
  • 26
0

Swift 2.0 version of Jagandeep Singh method but need to convert data to image because NSData? is not converted UIImage automatically.

let orginalImage:UIImage = image

let compressedData = UIImageJPEGRepresentation(orginalImage, 0.5)
let compressedImage = UIImage(data: compressedData!)
CodeOverRide
  • 4,431
  • 43
  • 36
0
NsData *data=UiImageJPEGRepresentation(Img.image,0.2f);
iOS Lifee
  • 2,091
  • 23
  • 32
  • 1
    It is usually helpful to elaborate on answers like this. Providing links to documentation, quotes from that documentation, as well as an explanation of why your code answers the question. – Chad Apr 03 '16 at 17:04
0
UIImage *image = [UIImage imageNamed:@"image.png"];
NSData *imgData1 = UIImageJPEGRepresentation(image, 1);
NSLog(@"Original --- Size of Image(bytes):%d",[imgData1 length]);

NSData *imgData2 = UIImageJPEGRepresentation(image, 0.5);
NSLog(@"After --- Size of Image(bytes):%d",[imgData2 length]);
image = [UIImage imageWithData:imgData2];
imgTest.image = image;

try to convert JPG by scaling factor. Here I am using 0.5 In my case: Original --- Size of Image(bytes): 85KB & After --- Size of Image(bytes): 23KB

-1
-(UIImage *) resizeImage:(UIImage *)orginalImage resizeSize:(CGSize)size
{
CGFloat actualHeight = orginalImage.size.height;
CGFloat actualWidth = orginalImage.size.width;
//  if(actualWidth <= size.width && actualHeight<=size.height)
//  {
//      return orginalImage;
//  }
float oldRatio = actualWidth/actualHeight;
float newRatio = size.width/size.height;
if(oldRatio < newRatio)
{
    oldRatio = size.height/actualHeight;
    actualWidth = oldRatio * actualWidth;
    actualHeight = size.height;
}
else
{
    oldRatio = size.width/actualWidth;
    actualHeight = oldRatio * actualHeight;
    actualWidth = size.width;
}

CGRect rect = CGRectMake(0.0,0.0,actualWidth,actualHeight);
UIGraphicsBeginImageContext(rect.size);
[orginalImage drawInRect:rect];
orginalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return orginalImage;
 }

This is the method calling

 UIImage *compimage=[appdel resizeImage:imagemain resizeSize:CGSizeMake(40,40)];      

it returns image this image u can display any where...........

Nazik
  • 8,696
  • 27
  • 77
  • 123
mahesh chowdary
  • 432
  • 5
  • 13
-36

You should be able to make a smaller image by doing something like

UIImage *small = [UIImage imageWithCGImage:original.CGImage scale:0.25 orientation:original.imageOrientation];

(for a quarter-size image) then convert the smaller image to a PNG or whatever format you need.

jjxtra
  • 20,415
  • 16
  • 100
  • 140
TerryH
  • 258
  • 2
  • 5
  • 52
    This changes the reported size of the scaled image, but does not actually change the image data. The data length of the NSData generated on the original and the scaled image is virtually identical. – Joshua Sullivan Mar 15 '12 at 16:43
  • 13
    This doesn't work! This shouldn't be the accepted answer! I just implemented it in my app only to find out that the image compressed to 25% of the original image size still has the same size in bytes than the original. I have no idea why there are so many upvotes or this non-working answer! – Michael Feb 18 '13 at 17:16
  • doesn't work. scales the image, but leaves the data full size. – nont Sep 20 '13 at 15:59
  • Again, does not work. Please remove/update this answer to not waste more time. – Zorayr Dec 26 '13 at 21:14
  • It doesn't change the file size because the Deep copy of an UIImage is a CGImage and resizing does not change the image. See the apple docs, to change the file size you create a new image with the scaled version. Learn what a pointer is. Let it also be known that scaling down then up will causing loss of the image and if you're using it for anything important it will look fuzzy later on. Compress it and using JPegCompress or whatever the function is called and send that. – Nick Turner Apr 16 '15 at 14:12
  • @FahimParkar +38 -70 LOL – Ver Nick Jan 18 '19 at 20:55