-
-
Save PaulSolt/739132 to your computer and use it in GitHub Desktop.
/* | |
* 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 |
/* | |
* 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 |
hi,
i need to convert rgb data to uiimage.
using your class always producing
EXC_BAD_ACCESS at CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), iref); in line 173.
any ideas?
thx
I also ran into same problem that @visualication did.
Getting EXC_BAD_ACCESS code=1
Many suggestions point to releasing resources prematurely, but this code seems to release everything after this CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), iref);
It still crashes at the line, so it can't be the problem with premature release of resources.
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
+ (unsigned char *) convertUIImageToBitmapARGB8:(UIImage *) image OutLength:(size_t*)length{
CGImageRef imageRef = image.CGImage;
// Create a bitmap context to draw the uiimage into
CGContextRef context = [self newBitmapARGB8ContextFromImage:imageRef];
if(!context) {
*length=0;
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;
size_t argb8Length=0;
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];
argb8Length++;
}
}
free(bitmapData);
} else {
NSLog(@"Error getting bitmap pixel data\n");
}
CGContextRelease(context);
*length = argb8Length;
return newBitmap;
}
This helped me by allowing
size_t length=0;
NSData *bitmapARGB8Data = [
NSData dataWithBytes:[
ImageHelper convertUIImageToBitmapARGB8:compimage
OutLength:&length
]
length:length
];
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.
@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
Fixed the issue with alpha transparency not being preserved.