Mar 30

Recently there have been some interesting developer news related to working with images on the iPhone.

  • First there is Chris Greening’s open source project simple-iphone-image-processing, that provides a set of common image processing tasks .
  • Today I listened to the Mobile Orchard’s podcast Interview with Paul Cantrell, and the discussion was about UIKit, views, layers, etc. This was the most enlightening information I’ve come across on this topic ever. Highly recommended.

So, I thought I’d contribute a few UIImage routines that I’ve found useful.

Combine two UIImages

To add two UIImages together you need to make use of Graphics Context.

- (UIImage *)addImage:(UIImage *)image1 toImage:(UIImage *)image2 {
	UIGraphicsBeginImageContext(image1.size);

	// Draw image1
	[image1 drawInRect:CGRectMake(0, 0, image1.size.width, image1.size.height)];

	// Draw image2
	[image2 drawInRect:CGRectMake(0, 0, image2.size.width, image2.size.height)];

	UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();

	UIGraphicsEndImageContext();

	return resultingImage;
}

Create a UIImage from a part of another UIImage

This requires a round-trip to Core Graphics land:

- (UIImage *)imageFromImage:(UIImage *)image inRect:(CGRect)rect {
	CGImageRef sourceImageRef = [image CGImage];
	CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, rect);
	UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
	CGImageRelease(newImageRef);
	return newImage;
}

Save UIImage to Photo Album

This is just a one-liner:

UIImageWriteToSavedPhotosAlbum(image, self, @selector(imageSavedToPhotosAlbum: didFinishSavingWithError: contextInfo:), context);

And to know if the save was successful:

- (void)imageSavedToPhotosAlbum:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
	NSString *message;
	NSString *title;
	if (!error) {
		title = NSLocalizedString(@"SaveSuccessTitle", @"");
		message = NSLocalizedString(@"SaveSuccessMessage", @"");
	} else {
		title = NSLocalizedString(@"SaveFailedTitle", @"");
		message = [error description];
	}
	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
													message:message
												   delegate:nil
										  cancelButtonTitle:NSLocalizedString(@"ButtonOK", @"")
										  otherButtonTitles:nil];
	[alert show];
	[alert release];
}

written by Nick \\ tags: , , , , ,

26 Responses to “Image Processing Tricks”

  1. Paul Cantrell Says:

    Thanks for UIGraphicsBeginImageContext()! Somehow I’d never discovered it. Very useful indeed.

    Glad you liked the podcast!

  2. Johnny Bynum Says:

    Nice blog.. thanks for the info! What are you using to display the code snippets in your blog?

  3. Nick Says:

    @Johnny: Thanks for the feedback! For displaying code snippets I’m using this WP plugin: Google Syntax Highlighter for WordPress which in turn is built upon this open source project: Google Syntax Highlighter.

  4. MPY Says:

    Thanks for posting this. But you have any idea why if use UIGraphicsBeginImageContext it will not work unless I set the last 3 options to nil? If I use your code, it just crashes simulator.

  5. Nick Says:

    @MPY: I’m not sure what you mean. UIGraphicsBeginImageContext only takes one parameter, a CGSize.

  6. Vishal Says:

    These are really good tricks. Can we draw a rectangle on the image and then display on screen? I have image on which I want to draw rectangle and then display on scree.

  7. Nick Says:

    @Vishal: Yes, you should be able to draw a rect in between UIGraphicsBeginImageContext() and UIGraphicsEndImageContext(). And then render the resulting image to the screen.

  8. jeff Says:

    how do you do image effects like blurring, bumping, and distortions/warping?

    can you use Core Image Filters? If not, what else can you try? Thanks.

  9. Nick Says:

    @jeff: I have not developed any iPhone apps with that type of image effects, so I don’t know what the best way to do this is.

  10. Forrest Says:

    thanks for providing source codes for simple image processing based on iPhone.

    I have one question here , do you have try to use the opencv to iPhone ? I have searched that there are a lot people tried to compiler opencv based on iPhone, but never see one real application which use opencv to do image processing.

    Thanks

  11. Nick Says:

    @Forrest: Sorry, I have not used opencv.

  12. Forrest Says:

    @Nick,
    actually if you can make full use of opencv based on iPhone, that will be wonderful !
    Opencv is so powerful that you do not need to write any image processing algorithm. Just use them from OpenCV.
    Welcome for discussing on this topic with me , my contact is :
    SKYPE : forrest.shi
    EMAIL : forrest.shi@gmail.com

  13. Art Says:

    Hi,

    It is interesting indeed but I’m having trouble adding the source to my project.
    I’ve downloaded the sample program and my understading is that the wrapper comes in 2 files : Image.mm and Image.h

    When I add those two files, it expects it to be Objective-C code but it’s not.
    I tried to compare the target settings on the 2 projects and I still don’t have a clue.

    Could someone explain to me how to do this ??

    Thanks

  14. Nick Says:

    @Art: A file with the extension .mm is typically used for C++. That may be why Xcode gets confused.

  15. Paul Michael Says:

    Thanks for the merge image tip! Appreciate it. 🙂

  16. Shiki Says:

    Thanks for the info on handling UIImageWriteToSavedPhotosAlbum.

  17. Rikza Azriyan Says:

    Nica share….
    Btw, i ever compile opencv on the iphone simulator. It was wonderfull, but lil bit confusing me to convert betwen UIImage to Iplimage and vice versa, and some of the rule of instant method parameter. So i tried to find another way to did it..
    I have one question, can use CGImage Class to do image processing in realtime like opencv did?
    Thx b4

  18. Oded Ben Dov Says:

    There’s a project that achieves fast image processing from the video camera, that is open source. It can help start anyone in the right direction –
    http://www.hatzlaha.co.il/150842/FAST-Corner-V2

    Thanks! 🙂

  19. Sal Aguinaga Says:

    Regarding: `UIImageWriteToSavedPhotosAlbum(image, self, @selector(imageSavedToPhotosAlbum: didFinishSavingWithError: contextInfo:), context);`
    I’ve seen many examples showing: `UIImageWriteToSavedPhotosAlbum(imageCopy, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);`

    so I replaced `image` with `imageSavedToPhotosAlbum`, but it complained that `context`, which is at the end of your line, is an undeclared identifier. If I replace it with nil, the app crashes returning the following error: *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘+[NSInvocation invocationWithMethodSignature:]: method signature argument cannot be nil’ I’m using ios 4.3.3 and Xcode 4.0.2. Any suggestions?

  20. Nick Says:

    @Sal: The method name “imageSavedToPhotosAlbum:” is arbitrary, but it must exist in your code because this method will be called when UIImageWriteToSavedPhotosAlbum completes. Other code examples may use the method name “image:”. This is just as valid. I just happen to like very long, descriptive method names.
    The context parameter is only passed back to your method defined in the @selector. You can pass in the name of the image saved or some other information that might be useful in the called method. If you don’t want any such information to be passed back to your code, then pass nil to the UIImageWriteToSavedPhotosAlbum function.

  21. Hakimo Says:

    Hi, I’m not sure I understand how to combine the two images. I tried testing the code in my method file but how to I call the resulting image? Is there an xcode example for this?

    Thanks

  22. Nick Says:

    @Hakimo: The resulting image is returned from the addImage: method. You can use this in any way that you would normally use an UIImage object.

  23. Mark Says:

    Great tips! Regarding the function

    – (UIImage *)addImage:(UIImage *)image1 toImage:(UIImage *)image2

    It seems like this works perfectly on simulator and 320×480 screens, but if you jump to 640×960, image2’s dimensions are calculated at 320×480 sizes (even if you have the @2x file ready). This is only happening for image2; image1 is calculated at the correct Retina size. Curious.

  24. Jason TEPOORTEN Says:

    Hi Mark,

    Here is an adaptation of the routine that can be used for @2x images.

    I have written it based on the sources I make reference to, including this page; thus please note the URL REF comments.

    // BEGIN CODE

    – (UIImage*) mergeTwoImages : (UIImage*) topImage : (UIImage*) bottomImage {
    // URL REF: http://iphoneincubator.com/blog/windows-views/image-processing-tricks
    // URL REF: http://stackoverflow.com/questions/1309757/blend-two-uiimages?answertab=active#tab-top
    // URL REF: http://www.waterworld.com.hk/en/blog/uigraphicsbeginimagecontext-and-retina-display

    int width = bottomImage.size.width;
    int height = bottomImage.size.height;

    CGSize newSize = CGSizeMake(width, height);
    static CGFloat scale = -1.0;
    if (scale= 4.0) {
    scale = [screen scale];
    }
    else {
    scale = 0.0; // Use the standard API
    }
    }
    if (scale>0.0) {
    UIGraphicsBeginImageContextWithOptions(newSize, NO, scale);
    }
    else {
    UIGraphicsBeginImageContext(newSize);
    }

    [bottomImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
    [topImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height) blendMode:kCGBlendModeNormal alpha:1.0];

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
    }

    // END CODE

  25. bob Says:

    i want to allow the app user, to add his face on famous celebrities bodies, and then save the image to camera roll?how can i do that? any ideas?

  26. Ken Says:

    I am at the end of my app now and for whatever reason I am drawing a blank. I decided to implement your code into my app. Well I pasted it in and then renamed some of the UIImage variables and I get a “Use of undeclared identifier” error. I know I am forgetting something, but for the life of me, every combination that I try, I get wrong. Can you mention the additional missing code that is not here please?

    Thanks

Leave a Reply