Questions tagged [uiimage]

The basic image handling class of Cocoa-Touch on iOS. It is Available in iOS 2.0 and later.

A UIImage object is a high-level way to display image data. You can create images from files, from Quartz image objects, or from raw image data you receive. The UIImage class also offers several options for drawing images to the current graphics context using different blend modes and opacity values.The questions related to this can be tagged using

Image objects are immutable, so you cannot change their properties after creation. This means that you generally specify an image’s properties at initialization time or rely on the image's metadata to provide the property value. In some cases, however, the UIImage class provides convenience methods for obtaining a copy of the image that uses custom values for a property.

In low-memory situations, image data may be purged from a UIImage object to free up memory on the system. This purging behavior affects only the image data stored internally by the UIImage object and not the object itself. When you attempt to draw an image whose data has been purged, the image object automatically reloads the data from its original file. This extra load step, however, may incur a small performance penalty.

The simplest way to load an image is with the imageNamed method, however this loads the data into memory and (generally) doesn't release it, so this is only ideal for small, frequently-used images.

UIImage *bgImage = [UIImage imageNamed:@"background.jpg"];

Use imageWithContentsOfFile to read image data from a file. This method doesn't cache the image to memory.

UIImage *bgImage = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"background" ofType:@"jpg"]]

Resources:


Can I Get To The Original File Representing This Image on the Disk?

As of iOS 4, you can, but it's very annoying. Use the following code to get an AssetsLibrary URL for the image, and then pass the URL to assetForURL:resultBlock:failureBlock:

NSURL *referenceURL = [info objectForKey:UIImagePickerControllerReferenceURL];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:referenceURL resultBlock:^(ALAsset *asset) {
    // code to handle the asset here
} failureBlock:^(NSError *error) {
    // error handling
}];
[library release];

It's annoying because the user is asked if your application can access your current location, which is rather confusing since you are actually trying to access the user's photo library. Unless you're actually trying to get at the EXIF location data, the user is going to be a bit confused.

Make sure to include the AssetsLibrary framework to make this work.

How Can I Look At The Underlying Pixels of the UIImage?

Since the UIImage is immutable, you can't look at the direct pixels. However, you can make a copy. The code to this looks something like this:

UIImage* image = ...; // An image
NSData* pixelData = (NSData*) CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
unsigned char* pixelBytes = (unsigned char *)[pixelData bytes];

// Take away the red pixel, assuming 32-bit RGBA
for(int i = 0; i < [pixelData length]; i += 4) {
        pixelBytes[i] = 0; // red
        pixelBytes[i+1] = pixelBytes[i+1]; // green
        pixelBytes[i+2] = pixelBytes[i+2]; // blue
        pixelBytes[i+3] = pixelBytes[i+3]; // alpha
}

However, note that CGDataProviderCopyData provides you with an "immutable" reference to the data - meaning you can't change it (and you may get a BAD_ACCESS error if you do). Look at the next question if you want to see how you can modify the pixels.

How Do I Modify The Pixels of the UIImage?

The UIImage is immutable, meaning you can't change it. Apple posted a great article on how to get a copy of the pixels and modify them, and rather than copy and paste it here, you should just go read the article.

Once you have the bitmap context as they mention in the article, you can do something similar to this to get a new UIImage with the modified pixels:

CGImageRef ref = CGBitmapContextCreateImage(bitmap);
UIImage* newImage = [UIImage imageWithCGImage:ref];

Do remember to release your references though, otherwise you're going to be leaking quite a bit of memory.

How Do I Resize the Image?

Unfortunately, there is no defined way how to resize an image. Also, it's important to note that when you resize it, you'll get a new image - you're not modifying the old one.

There are a couple of methods to do the resizing. I'll present them both here, and explain the pros and cons of each.

Method 1: Using UIKit

+ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize
{
    // Create a graphics image context
    UIGraphicsBeginImageContext(newSize);

    // Tell the old image to draw in this new context, with the desired
    // new size
    [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];

    // Get the new image from the context
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();

    // End the context
    UIGraphicsEndImageContext();

    // Return the new image.
    return newImage;
}

This method is very simple, and works great. It will also deal with the UIImageOrientation for you, meaning that you don't have to care whether the camera was sideways when the picture was taken. However, this method is not thread safe, and since thumbnailing is a relatively expensive operation (approximately ~2.5s on a 3G for a 1600 x 1200 pixel image), this is very much an operation you may want to do in the background, on a separate thread.

Method 2: Using CoreGraphics

+ (UIImage*)imageWithImage:(UIImage*)sourceImage scaledToSize:(CGSize)newSize;
{
    CGFloat targetWidth = newSize.width;
    CGFloat targetHeight = newSize.height;

    CGImageRef imageRef = [sourceImage CGImage];
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);

    if (bitmapInfo == kCGImageAlphaNone) {
        bitmapInfo = kCGImageAlphaNoneSkipLast;
    }

    CGContextRef bitmap;

    if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) {
        bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    } else {
        bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    }   

    if (sourceImage.imageOrientation == UIImageOrientationLeft) {
        CGContextRotateCTM (bitmap, M_PI_2); // + 90 degrees
        CGContextTranslateCTM (bitmap, 0, -targetHeight);

    } else if (sourceImage.imageOrientation == UIImageOrientationRight) {
        CGContextRotateCTM (bitmap, -M_PI_2); // - 90 degrees
        CGContextTranslateCTM (bitmap, -targetWidth, 0);

    } else if (sourceImage.imageOrientation == UIImageOrientationUp) {
        // NOTHING
    } else if (sourceImage.imageOrientation == UIImageOrientationDown) {
        CGContextTranslateCTM (bitmap, targetWidth, targetHeight);
        CGContextRotateCTM (bitmap, -M_PI); // - 180 degrees
    }

    CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
    UIImage* newImage = [UIImage imageWithCGImage:ref];

    CGContextRelease(bitmap);
    CGImageRelease(ref);

    return newImage; 
}

The benefit of this method is that it is thread-safe, plus it takes care of all the small things (using correct color space and bitmap info, dealing with image orientation) that the UIKit version does.

How Do I Resize and Maintain Aspect Ratio (like the AspectFill option)?

It is very similar to the method above, and it looks like this:

+ (UIImage*)imageWithImage:(UIImage*)sourceImage scaledToSizeWithSameAspectRatio:(CGSize)targetSize;
{  
    CGSize imageSize = sourceImage.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;
    CGFloat targetWidth = targetSize.width;
    CGFloat targetHeight = targetSize.height;
    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetWidth;
    CGFloat scaledHeight = targetHeight;
    CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

    if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;

        if (widthFactor > heightFactor) {
            scaleFactor = widthFactor; // scale to fit height
        }
        else {
            scaleFactor = heightFactor; // scale to fit width
        }

        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;

        // center the image
        if (widthFactor > heightFactor) {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
        }
        else if (widthFactor < heightFactor) {
            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
    }     

    CGImageRef imageRef = [sourceImage CGImage];
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);

    if (bitmapInfo == kCGImageAlphaNone) {
        bitmapInfo = kCGImageAlphaNoneSkipLast;
    }

    CGContextRef bitmap;

    if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) {
        bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    } else {
        bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    }   

    // In the right or left cases, we need to switch scaledWidth and scaledHeight,
    // and also the thumbnail point
    if (sourceImage.imageOrientation == UIImageOrientationLeft) {
        thumbnailPoint = CGPointMake(thumbnailPoint.y, thumbnailPoint.x);
        CGFloat oldScaledWidth = scaledWidth;
        scaledWidth = scaledHeight;
        scaledHeight = oldScaledWidth;

        CGContextRotateCTM (bitmap, M_PI_2); // + 90 degrees
        CGContextTranslateCTM (bitmap, 0, -targetHeight);

    } else if (sourceImage.imageOrientation == UIImageOrientationRight) {
        thumbnailPoint = CGPointMake(thumbnailPoint.y, thumbnailPoint.x);
        CGFloat oldScaledWidth = scaledWidth;
        scaledWidth = scaledHeight;
        scaledHeight = oldScaledWidth;

        CGContextRotateCTM (bitmap, -M_PI_2); // - 90 degrees
        CGContextTranslateCTM (bitmap, -targetWidth, 0);

    } else if (sourceImage.imageOrientation == UIImageOrientationUp) {
        // NOTHING
    } else if (sourceImage.imageOrientation == UIImageOrientationDown) {
        CGContextTranslateCTM (bitmap, targetWidth, targetHeight);
        CGContextRotateCTM (bitmap, -M_PI); // - 180 degrees
    }

    CGContextDrawImage(bitmap, CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledWidth, scaledHeight), imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);
    UIImage* newImage = [UIImage imageWithCGImage:ref];

    CGContextRelease(bitmap);
    CGImageRelease(ref);

    return newImage; 
}

The method we employ here is to create a bitmap with the desired size, but draw an image that is actually larger, thus maintaining the aspect ratio.

So We've Got Our Scaled Images - How Do I Save Them To Disk?

This is pretty simple. Remember that we want to save a compressed version to disk, and not the uncompressed pixels. Apple provides two functions that help us with this (documentation is here):

NSData* UIImagePNGRepresentation(UIImage *image);
NSData* UIImageJPEGRepresentation (UIImage *image, CGFloat compressionQuality);

And if you want to use them, you'd do something like:

UIImage* myThumbnail = ...; // Get some image
NSData* imageData = UIImagePNGRepresentation(myThumbnail);

Now we're ready to save it to disk, which is the final step (say into the documents directory):

// Give a name to the file
NSString* imageName = @"MyImage.png";

// Now, we have to find the documents directory so we can save it
// Note that you might want to save it elsewhere, like the cache directory,
// or something similar.
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];

// Now we get the full path to the file
NSString* fullPathToFile = [documentsDirectory stringByAppendingPathComponent:imageName];

// and then we write it out
[imageData writeToFile:fullPathToFile atomically:NO];

You would repeat this for every version of the image you have.

How Do I Load These Images Back Into Memory?

Just look at the various UIImage initialization methods, such as +imageWithContentsOfFile: in the Apple documentation.


Information sourced from a now deleted Stack Overflow post: UIImagePickerController, UIImage, Memory and More?

9237 questions
3
votes
2 answers

Replace Navigation bar back button without stretching

I'm trying to replace the default nav bar back button image: UIImage *backButtonImage = [UIImage imageNamed:@"back_button"] ; backButtonImage = [backButtonImage resizableImageWithCapInsets:UIEdgeInsetsMake(0, backButtonImage.size.width, 0,…
soleil
  • 12,133
  • 33
  • 112
  • 183
3
votes
3 answers

How to get the size of a UIImage in KB?

Is there a way to get the filesize in KB from a UIImage, without getting that image from didFinishPickingMediaWithInfo? The images that are presented are coming from the photo album. I tried the following code, but this gives the following result:…
Jan
  • 653
  • 1
  • 7
  • 22
3
votes
3 answers

Get the position of a UIImageView

I have an existing UIImageView with variable X and Y coordinates. The picture should move according to the current position difference but I don't know how I get the current position. picture = UIImageView(frame: CGRectMake(corx, cory, 25, 25)) I…
Lukas Köhl
  • 1,569
  • 2
  • 15
  • 28
3
votes
1 answer

SVG String to UIImage for iOS

I try to make an iOS application and use Github API with SDWebImage. Here is the code to get "User Profile Image". [manager GET:@"https://api.github.com/users/(here is your account name)/following?page=1&per_page=100" parameters:nil …
masuhara
  • 179
  • 1
  • 2
  • 9
3
votes
0 answers

UIPasteBoard, Image & Retina Display

I'm generating an image using the following: UIGraphicsBeginImageContextWithOptions(labelView.bounds.size, NO, 2.0); [labelView.layer renderInContext:UIGraphicsGetCurrentContext()]; UIImage *resultingImage =…
KingPolygon
  • 4,753
  • 7
  • 43
  • 72
3
votes
2 answers

How to remove opacity but keep the alpha channel of UIImage?

I have a layer where I want the user to draw a 'mask' for cutting out images. It is semi-opaque so that they can see beneath what they are selecting. How can I process this so that the drawing data has an alpha of 1.0, but retain the alpha channel…
Halpo
  • 2,982
  • 3
  • 25
  • 54
3
votes
1 answer

Creating UIImage from NSData created from buffer returns nil?

I'm trying to darken UIImage by grabbing the CGImage, getting each pixel and subtracting 0xa from it, then saving each pixel to a new buffer. But when I try to load that buffer back as an image, the function [to create a CGImage] returns nil. This…
PopKernel
  • 4,110
  • 5
  • 29
  • 51
3
votes
2 answers

ios 8 UIIMagePickerController showing a black preview screen alternate times in iPhone 6

In my app on click of a UIButton am opening camera.Once the camera is opened a black preview is shown instead of the capturing image,but Retake and Use photos buttons are visible.This back preview is shown for camera in iPhone6 but works fine in…
3
votes
1 answer

Swift fatal error: unexpectedly found nil while unwrapping an Optional value uiimage

I've got an error while assign an UIImage to the property image of UIImageView func connectionDidFinishLoading(connection: NSURLConnection!) { var err: NSError var jsonResult : NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options:…
Mathieu
  • 71
  • 5
3
votes
3 answers

UITableViewCell.ImageView.image Compare UIImage

I am comparing cell.imageView.image with UIImage as below code. Please refer below Code UIImage *imgOne = [UIImage imageNamed:@"One"]; if([customCell.imageView.image isEqual: imgOne]){ NSLog(@"Right Image"); } While…
Er.Shreyansh Shah
  • 1,482
  • 1
  • 9
  • 29
3
votes
3 answers

Setting images in UITableViewCell in Swift

I have a list of reddit posts that I want to display the thumbnail of, if it exists. I have it functioning, but it's very buggy. There are 2 main issues: Images resize on tap Images shuffle on scroll This is the code: override func…
cadlac
  • 2,802
  • 3
  • 18
  • 34
3
votes
1 answer

ios rotate image and zoom, so it fits original frame like in instagram

In instagram when you rotate image it zooms, so you cannot see those angled corners. Thats perfect. This topic is discussed here: https://math.stackexchange.com/questions/61005/resizing-a-rectangle-to-always-fit-into-its-unrotated-space I wonder if…
Miroslav Kuťák
  • 1,875
  • 1
  • 18
  • 24
3
votes
1 answer

imageWithSize Flakey with MPMediaItemArtwork in iOS8

In my app, I display album artwork on a button. On an iPhone 5, the button bounds size is 273x269.5. My code to size the artwork has always been very straightforward and nothing has changed. MPMediaItem *currentItem = [musicPlayer…
JeffB6688
  • 3,782
  • 5
  • 38
  • 58
3
votes
0 answers

Asset Catalog UIImage ImageNamed: was nil

I have 2 Assets Catalogs in my App. One is in the Source Directory of my App and the other one is linked to my Project and Target Membership was set. When i would load an image from the Linked Assetscatalog with [UIImage…
Zeropointer
  • 510
  • 2
  • 7
  • 24
3
votes
5 answers

How can I put an image inline with an NSString on the iPhone?

I know you can do it on Mac OS X with NSAttributedString but I haven't had much luck with that on the iPhone. I'm trying to basically do a string like "$200" except the dollar sign is replaced by a custom symbol.
Wil G
  • 31
  • 2
1 2 3
99
100