iOS: Converting UIImage to RGBA8 Bitmaps and Back

Edited 8/24/11: Fixed a bug with alpha transparency not being preserved. Thanks for the tip Scott! Updated the gist and github project to test transparent images.

Edited 12/13/10: Updated the code on github/gist to fix static analyzer warnings. Changed a function name to conform to the Apple standard.

When I started working with iPhone I was working with Objective-C and C++. I created a library in C++ and needed access to a bitmap array so that I could perform image processing. In order to do so I had to create some helper functions to convert between UIImage objects and the RGBA8 bitmap arrays.

Here are the updated routines that should work on iPhone 4.1 and iPad 3.2. The iPhone 4 has a high resolution screen requires setting a scaling factor for high resolution images. I've added support to set the scaling factor based on the devices mainScreen scaling factor

UPDATE: 9/23/10 My code to work with the Retina display was incorrect, it ran fine on iPad with 3.2, but it didn't do anything "high-res" on iPhone 4. I was using the following:

__IPHONE_OS_VERSION_MAX_ALLOWED >= 30200

but it isn't safe, when I run it for a universal App 4.1/3.2 it will always return 40100, and the expression didn't make sense. (Side Note) I took this check from Apple's website when iPad 3.2 was actually ahead of iPhone 3.1.X, but that doesn't help with iPhone 4.1 being ahead of iPad 3.2.

The issue with iPad is that the imageWithCGImage:scale:orientation: selector doesn't exist on iOS 3.2, most likely it will on iOS 4.2, so the following code should be safe. Some methods in iOS 4.1 don't exist in iOS 3.2, so you need to check to see if a newer method exists before trying to execute it. There are two methods you can use depending on the class/instance (+/-) modifier on the function definition.

+ (BOOL)respondsToSelector:(SEL)aSelector   // (+) Class method check
+ (BOOL)instancesRespondToSelector:(SEL)aSelector   // (-) Instance method check

imageWithCGImage:scale:orientation is a class method, so we need to use respondsToSelector: The correct code to scale the CGImage is below:

if([UIImage respondsToSelector:@selector(imageWithCGImage:scale:orientation:)]) {
	float scale = [[UIScreen mainScreen] scale];
	image = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
} else {
	image = [UIImage imageWithCGImage:imageRef];
}

[ad#Large Box]

It might help if there was some images to explain what's happening if you don't use this imageWithCGImage:scale:orientation: on the iPhone 4 with the correct scale factor. It should be 2.0 on Retina displays (iPhone 4 or the new iPod Touch) and 1.0 on the 3G, 3GS, and iPad. float scale = [[UIScreen mainScreen] scale]; will provide the correct scale factor for the device. The first image has jaggies in it, while the second does not. The third image, an iPhone 3G/3GS, also does not have jaggies.

[caption id="attachment_697" align="aligncenter" width="451" caption="iPhone 4 with default scale of 1.0 causes the image to be enlarged and with jaggies."][/caption]

[caption id="attachment_698" align="aligncenter" width="451" caption="iPhone 4 with scaling of 2.0 makes the image half the size and removes the jaggies"][/caption]

[caption id="attachment_692" align="aligncenter" width="414" caption="iPhone 3G/3GS with scaling set to 1.0"][/caption]

I hope it helps other people with image processing on the iPhone/iPad. It's based on some previous tutorials using OpenGL, which I fixed (memory leaks) and modified to work with unsigned char arrays (bitmap).

[ad#Link Banner]

Grab the two files here or the sample Universal iOS App project:

Example Usage:

NSString *path = (NSString*)[[NSBundle mainBundle] pathForResource:@"Icon4" ofType:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
int width = image.size.width;
int height = image.size.height;

    // Create a bitmap
unsigned char *bitmap = [ImageHelper convertUIImageToBitmapRGBA8:image];

    // Create a UIImage using the bitmap
UIImage *imageCopy = [ImageHelper convertBitmapRGBA8ToUIImage:bitmap withWidth:width withHeight:height];

    // Display the image copy on the GUI
UIImageView *imageView = [[UIImageView alloc] initWithImage:imageCopy];

    // Cleanup
free(bitmap);

Below is the full source code for converting between bitmap and UIImage:

ImageHelper.h

ImageHelper.m

[ad#Large Box]

GLUT Object Oriented Framework on Github

In 2009 I took a Computer Animation course at @RIT I created an object-oriented C++ wrapper for GLUT. The idea was to create a set of classes that could be reused for each of the separate project submissions. The main class wraps around the GLUT C-style functions and provides a class that can be inherited from, to provide application specific functionality. The idea was to make the boiler plate code disappear and make it easier for novice programmers to get an animated graphics window in as few lines as possible. Only four lines of code are needed to get the window running at 60 frames per second. You can subclass the framework and implement your own OpenGL animation or game project.

Edit (8/22/10): You don't need to use pointers, I've updated the code example with working code.

// main.cpp
#include "GlutFramework.h"
using namespace glutFramework;
int main(int argc, char *argv[]) {
	GlutFramework framework;
	framework.startFramework(argc, argv);
        return 0;
}

[ad#Large Box]

The code uses a cross-platform (Windows/Mac tested) timer to create a constant frame-rate, which is necessary for animation projects. It's under the MIT License, so feel free to use it as you see fit. http://github.com/PaulSolt/GLUT-Object-Oriented-Framework

An Xcode 3.1 and Visual Studio 2010 project is hosted on github to support Mac and Windows. There is no setup on the Mac, but Windows users will need to configure GLUT. I plan on posted tutorials on how to get setup on both platforms. For now, look at the resources section below.

[caption id="attachment_617" align="aligncenter" width="504" caption="Animated teapot"][/caption]

Resources:

[ad#Large Box]