EXC_Bad_Access Problems with editable CGImage class
I wrote an editable CGImage class where you can load images, access the pixels and update them to the image. I am getting EXC_Bad_Access exceptions at different locations in my iphone project, especially when loading a new image and getting a new pixel pointer for an already used instance. Maybe there are some wrong alloc/releases? Can someone please review my code if there are any memory leaks. Thanks, Alex
Code:
#import "EditableImage.h"
@implementation EditableImage
- (void) loadImage:(NSString*) name size:(CGSize)size{
[self clearImage];
CGImageRef fullImage = [[UIImage imageNamed:name] CGImage];
int oldwidth=CGImageGetWidth(fullImage);
int oldheight=CGImageGetHeight(fullImage);
int newwidth=size.width;
int newheight=size.height;
int width;
int height;
fitsize(oldwidth, oldheight, newwidth, newheight, &width, &height);
image=[self createScaledCGImageFromCGImage:fullImage toWidth:width andHeight:height];
[self createPixelArray];
}
- (id) init {
self=[super init];
image=0;
return self;
}
- (void) loadImageRef:(CGImageRef) imageRef {
[self clearImage];
int width=CGImageGetWidth(imageRef);
int height=CGImageGetHeight(imageRef);
image=[self createScaledCGImageFromCGImage:imageRef toWidth:width andHeight:height];
// image=CGImageCreateCopy(imageRef);
[self createPixelArray];
}
- (CGImageRef) getImage {
return image;
}
- (void) clearImage {
if (image) {
CGImageRelease(image);image=0;
}
}
- (void) createPixelArray {
data = (NSData *) CGDataProviderCopyData(CGImageGetDataProvider(image));
}
- (void) updateImage:(char *)pixels {
// create a new image from the modified pixel data
CGImageRef imageRef=image;
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
size_t bitsPerPixel = CGImageGetBitsPerPixel(imageRef);
size_t bytesPerRow = CGImageGetBytesPerRow(imageRef);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, [data length], NULL);
// the modified image
[self clearImage];
image = CGImageCreate (
width,
height,
bitsPerComponent,
bitsPerPixel,
bytesPerRow,
colorspace,
bitmapInfo,
provider,
NULL,
false,
kCGRenderingIntentDefault
);
//[self createPixelArray];
// cleanup
//CGImageRelease(imageRef);
CGColorSpaceRelease(colorspace);
CGDataProviderRelease(provider);
//CGImageRelease(newImageRef);
}
- (char *) pixelArray {
return (char *)[data bytes];
}
- (void)dealloc
{
if (data) {
CFRelease(data);data=0; //causes EXC_Bad_Access when this line is moved into clearImage;
}
[self clearImage];
[super dealloc];
}
- (CGImageRef)createScaledCGImageFromCGImage:(CGImageRef)oimage toWidth:(int)width andHeight:(int)height {
CGContextRef context = NULL;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
// Declare the number of bytes per row. Each pixel in the bitmap in this
// example is represented by 4 bytes; 8 bits each of red, green, blue, and
// alpha.
bitmapBytesPerRow = (width * 4);
bitmapByteCount = (bitmapBytesPerRow * height);
// Allocate memory for image data. This is the destination in memory
// where any drawing to the bitmap context will be rendered.
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL)
{
return nil;
}
// Create the bitmap context. We want pre-multiplied ARGB, 8-bits
// per component. Regardless of what the source image format is
// (CMYK, Grayscale, and so on) it will be converted over to the format
// specified here by CGBitmapContextCreate.
CGColorSpaceRef colorspace = CGImageGetColorSpace(oimage);
//CGColorSpaceRef colorspace=CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate (bitmapData,width,height,8,bitmapBytesPerRow,
colorspace,kCGImageAlphaPremultipliedLast);
CFRetain(colorspace);
CGColorSpaceRelease(colorspace);
if (context == NULL)
// error creating context
return nil;
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
// Draw the image to the bitmap context. Once we draw, the memory
// allocated for the context for rendering will then contain the
// raw image data in the specified color space.
CGContextDrawImage(context, CGRectMake(0,0,width, height), oimage);
CGImageRef imgRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
free(bitmapData);
return imgRef;
}
@end