Created
December 13, 2010 15:54
-
-
Save PaulSolt/739132 to your computer and use it in GitHub Desktop.
A simple UIImage to RGBA8 conversion function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* The MIT License | |
* | |
* Copyright (c) 2011 Paul Solt, [email protected] | |
* | |
* https://github.com/PaulSolt/UIImage-Conversion/blob/master/MITLicense.txt | |
* | |
*/ | |
#import <Foundation/Foundation.h> | |
@interface ImageHelper : NSObject { | |
} | |
/** Converts a UIImage to RGBA8 bitmap. | |
@param image - a UIImage to be converted | |
@return a RGBA8 bitmap, or NULL if any memory allocation issues. Cleanup memory with free() when done. | |
*/ | |
+ (unsigned char *) convertUIImageToBitmapRGBA8:(UIImage *)image; | |
/** A helper routine used to convert a RGBA8 to UIImage | |
@return a new context that is owned by the caller | |
*/ | |
+ (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef)image; | |
/** Converts a RGBA8 bitmap to a UIImage. | |
@param buffer - the RGBA8 unsigned char * bitmap | |
@param width - the number of pixels wide | |
@param height - the number of pixels tall | |
@return a UIImage that is autoreleased or nil if memory allocation issues | |
*/ | |
+ (UIImage *) convertBitmapRGBA8ToUIImage:(unsigned char *)buffer | |
withWidth:(int)width | |
withHeight:(int)height; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* The MIT License | |
* | |
* Copyright (c) 2011 Paul Solt, [email protected] | |
* | |
* https://github.com/PaulSolt/UIImage-Conversion/blob/master/MITLicense.txt | |
* | |
*/ | |
#import "ImageHelper.h" | |
@implementation ImageHelper | |
+ (unsigned char *) convertUIImageToBitmapRGBA8:(UIImage *) image { | |
CGImageRef imageRef = image.CGImage; | |
// Create a bitmap context to draw the uiimage into | |
CGContextRef context = [self newBitmapRGBA8ContextFromImage:imageRef]; | |
if(!context) { | |
return NULL; | |
} | |
size_t width = CGImageGetWidth(imageRef); | |
size_t height = CGImageGetHeight(imageRef); | |
CGRect rect = CGRectMake(0, 0, width, height); | |
// Draw image into the context to get the raw image data | |
CGContextDrawImage(context, rect, imageRef); | |
// Get a pointer to the data | |
unsigned char *bitmapData = (unsigned char *)CGBitmapContextGetData(context); | |
// Copy the data and release the memory (return memory allocated with new) | |
size_t bytesPerRow = CGBitmapContextGetBytesPerRow(context); | |
size_t bufferLength = bytesPerRow * height; | |
unsigned char *newBitmap = NULL; | |
if(bitmapData) { | |
newBitmap = (unsigned char *)malloc(sizeof(unsigned char) * bytesPerRow * height); | |
if(newBitmap) { // Copy the data | |
for(int i = 0; i < bufferLength; ++i) { | |
newBitmap[i] = bitmapData[i]; | |
} | |
} | |
free(bitmapData); | |
} else { | |
NSLog(@"Error getting bitmap pixel data\n"); | |
} | |
CGContextRelease(context); | |
return newBitmap; | |
} | |
+ (CGContextRef) newBitmapRGBA8ContextFromImage:(CGImageRef) image { | |
CGContextRef context = NULL; | |
CGColorSpaceRef colorSpace; | |
uint32_t *bitmapData; | |
size_t bitsPerPixel = 32; | |
size_t bitsPerComponent = 8; | |
size_t bytesPerPixel = bitsPerPixel / bitsPerComponent; | |
size_t width = CGImageGetWidth(image); | |
size_t height = CGImageGetHeight(image); | |
size_t bytesPerRow = width * bytesPerPixel; | |
size_t bufferLength = bytesPerRow * height; | |
colorSpace = CGColorSpaceCreateDeviceRGB(); | |
if(!colorSpace) { | |
NSLog(@"Error allocating color space RGB\n"); | |
return NULL; | |
} | |
// Allocate memory for image data | |
bitmapData = (uint32_t *)malloc(bufferLength); | |
if(!bitmapData) { | |
NSLog(@"Error allocating memory for bitmap\n"); | |
CGColorSpaceRelease(colorSpace); | |
return NULL; | |
} | |
//Create bitmap context | |
context = CGBitmapContextCreate(bitmapData, | |
width, | |
height, | |
bitsPerComponent, | |
bytesPerRow, | |
colorSpace, | |
kCGImageAlphaPremultipliedLast); // RGBA | |
if(!context) { | |
free(bitmapData); | |
NSLog(@"Bitmap context not created"); | |
} | |
CGColorSpaceRelease(colorSpace); | |
return context; | |
} | |
+ (UIImage *) convertBitmapRGBA8ToUIImage:(unsigned char *) buffer | |
withWidth:(int) width | |
withHeight:(int) height { | |
size_t bufferLength = width * height * 4; | |
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, bufferLength, NULL); | |
size_t bitsPerComponent = 8; | |
size_t bitsPerPixel = 32; | |
size_t bytesPerRow = 4 * width; | |
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); | |
if(colorSpaceRef == NULL) { | |
NSLog(@"Error allocating color space"); | |
CGDataProviderRelease(provider); | |
return nil; | |
} | |
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast; | |
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; | |
CGImageRef iref = CGImageCreate(width, | |
height, | |
bitsPerComponent, | |
bitsPerPixel, | |
bytesPerRow, | |
colorSpaceRef, | |
bitmapInfo, | |
provider, // data provider | |
NULL, // decode | |
YES, // should interpolate | |
renderingIntent); | |
uint32_t* pixels = (uint32_t*)malloc(bufferLength); | |
if(pixels == NULL) { | |
NSLog(@"Error: Memory not allocated for bitmap"); | |
CGDataProviderRelease(provider); | |
CGColorSpaceRelease(colorSpaceRef); | |
CGImageRelease(iref); | |
return nil; | |
} | |
CGContextRef context = CGBitmapContextCreate(pixels, | |
width, | |
height, | |
bitsPerComponent, | |
bytesPerRow, | |
colorSpaceRef, | |
bitmapInfo); | |
if(context == NULL) { | |
NSLog(@"Error context not created"); | |
free(pixels); | |
} | |
UIImage *image = nil; | |
if(context) { | |
CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), iref); | |
CGImageRef imageRef = CGBitmapContextCreateImage(context); | |
// Support both iPad 3.2 and iPhone 4 Retina displays with the correct scale | |
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]; | |
} | |
CGImageRelease(imageRef); | |
CGContextRelease(context); | |
} | |
CGColorSpaceRelease(colorSpaceRef); | |
CGImageRelease(iref); | |
CGDataProviderRelease(provider); | |
if(pixels) { | |
free(pixels); | |
} | |
return image; | |
} | |
@end |
@trsa74 What is your input buffer?
The function is based on the assumption that your source buffer is a RGBA format that is 32 bits per pixel, so 8 bits per color channel with alpha.
Your crash is on the input buffer on line 14 in your screenshot.
If your input format needs to be different, you'll need to extend the logic to not be hard coded to the RGBA 32-bit format.
+ (UIImage *) convertBitmapRGBA8ToUIImage:(unsigned char *) buffer
withWidth:(int) width
withHeight:(int) height {
size_t bufferLength = width * height * 4; /// Assumes 4 channels (RGBA)
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, bufferLength, NULL);
size_t bitsPerComponent = 8;
size_t bitsPerPixel = 32;
size_t bytesPerRow = 4 * width; /// Assumes 4 channels
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
By the way, I tweaked it a little as follows:
ImageHelper.h line 21
+ (unsigned char *) convertUIImageToBitmapARGB8:(UIImage *)image OutLength:(size_t*)length;
ImageHelper.m implementation for the function changed to
This helped me by allowing
Otherwise I had no byte length and could not create the data object easily.
I am not sure this is the best approach, so putting it up here.