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
1 answer

Open Instagram only in UIDocumentInteractionController

My application required to post an image to Instagram, I used UIDocumentInteractionController to open image file saved in the Documents directory with an extension .igo. Set com.instagram.exclusivegram as the UIDocumentInteractionController's UTI…
Sudheesh
  • 483
  • 6
  • 20
3
votes
1 answer

Transparent Tile Overlay with GMSSyncTileLayer in iOS

I am using the Google Maps API. I am creating an overlay on top of the existing map. The overlay uses UIImages, which are taken from .png images that have transparent regions. The .PNG files are perfectly fine, and they are transparent everywhere…
Nightsd01
  • 216
  • 2
  • 7
3
votes
4 answers

UIImage imageNamed not autoreleasing correctly

For some reason, the retain/release behavior in the following code has me completely baffled. selectedImage = [UIImage imageNamed:@"icon_72.png"]; [selectedImage release]; This should break but does not. Why? I thought imageNamed autoreleased…
MrHen
  • 2,420
  • 2
  • 25
  • 39
3
votes
2 answers

How can I make a composite image consisting of two images in Swift?

I want to create a new UIImage that is a composite of one UIImage overlaid on top of another. How can I achieve this?
clearlight
  • 12,255
  • 11
  • 57
  • 75
3
votes
1 answer

How can I control UIImage size in UIPastboard?

I am copying an image to pasteboard the following way: let image = UIImage(named: "my_image") UIPasteboard.generalPasteboard().image = image When I paste the following image into an iMessage it looks like the image size isn't taken into account.…
Zoli
  • 41
  • 1
  • 7
3
votes
1 answer

How to make Image page viewer for images swift ios

I wanna display a couple of images from the assets folders, into my application. so I wanna make a page view. First, images will be inside collection view, then on click, the image will be full screen. Then the user can slide between the images by…
MBH
  • 16,271
  • 19
  • 99
  • 149
3
votes
2 answers

Save image with the correct orientation - Swift & Core Image

I'm using Core Image in Swift for editing photos and I have a problem when I save the photo. I'm not saving it with correct orientation. When I get the picture from the Photo Library I'm saving the orientation in a variable as UIImageOrientation but…
benLIVE
  • 597
  • 3
  • 14
  • 29
3
votes
3 answers

How to Save UIImage to a Transparent PNG?

I'm not sure where I'm doing the mistake, that's why I'd like to paste here some block of codes in order to find out what went wrong. I have some PNG images that have transparent background and with using the block of codes below I'm trying save the…
Yusuf
  • 63
  • 2
  • 11
3
votes
0 answers

UIKit: why would UIGraphicsGetImageFromCurrentImageContext use much less memory than -[UIImage imageWithContentsOfFile]?

My app displays a bunch of images in a UICollectionView. When I call: [UIImage imageWithContentsOfFile:thumbnailPath]; my app uses around 60mb of RAM for my test set of images. However, when I then do the following: UIImage* image = [UIImage…
Taylor
  • 5,871
  • 2
  • 30
  • 64
3
votes
1 answer

Custom animation background

I need to create animated background like this one. What is the best way to achieve this?
Lipatov Eugen
  • 407
  • 3
  • 10
3
votes
1 answer

Fatsest way to edit alpha of CGImage (or UIImage) with touch and then display?

I have two image views, one on top of the another, with two different images. As the user touches the image and moves his/her finger, the top image should become transparent along the touch points with a fixed radius. (Like the PhotoChop…
Abix
  • 260
  • 2
  • 16
3
votes
3 answers

snapshotViewAfterScreenUpdates creating a blank image

I'm trying to create some composite UIImage objects with this code: someImageView.image = [ImageMaker coolImage]; ImageMaker: - (UIImage*)coolImage { UIView *composite = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 400, 400)]; UIImageView…
soleil
  • 12,133
  • 33
  • 112
  • 183
3
votes
5 answers

iOS7 Autolayout and UIImageview oversized

Please see my answer below, where I have a working solution I have rewritten the code completely so it is much smaller and neater and achieves the same results. Update: It looks like the intrinsic content size of the UIImageView is being adjusted…
matfin
  • 499
  • 4
  • 15
3
votes
2 answers

UIImageView autolayout issue in UICollectionViewCell on iOS7 but on iOS8 it's ok

Have problem with reducing image size in ImageView. In the CollectionViewCell have ImageView with constraints: two horizontal and two vertical spaces. First screen is iOS7 and second screen is iOS8. ImageURL it's custom class for load image by…
Iraklii
  • 1,295
  • 13
  • 30
3
votes
2 answers

stretch image's both sides but not center for uibutton

I got an image,which is shorter than button's width, so I want to stretch the image's both sides to fit button's width but not stretch its center because there is text in center. What should I do to achieve that? Appreciate your suggestion!
John
  • 525
  • 3
  • 14
1 2 3
99
100