I have a function where I convert a UIImage
to a vImage
(to be used in some vImage
methods in iOS's Accelerate.framework
.
The method I have is:
-(vImage_Buffer)convertImage:(UIImage *)image {
CGImageRef sourceRef = [image CGImage];
NSUInteger sourceWidth = CGImageGetWidth(sourceRef);
NSUInteger sourceHeight = CGImageGetHeight(sourceRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *sourceData = (unsigned char*)calloc(sourceHeight * sourceWidth * 4, sizeof(unsigned char));
NSUInteger bytesPerPixel = 4;
NSUInteger sourceBytesPerRow = bytesPerPixel * sourceWidth;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(sourceData, sourceWidth, sourceHeight,
bitsPerComponent, sourceBytesPerRow, colorSpace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
CGContextDrawImage(context, CGRectMake(0, 0, sourceWidth, sourceHeight), sourceRef);
CGContextRelease(context);
vImage_Buffer v_image = {
.data = sourceData,
.height = sourceHeight,
.width = sourceWidth,
.rowBytes = sourceBytesPerRow
};
return v_image;
}
I built this by mix and matching a few code snippets on the web.
My question is, I have a calloc
call which allocates the space for sourceData
. But how, and where would I free this memory?
Given that I may call this method many times, it seems like as-is, there would be a huge memory leak. I don't think I would release it here because it supplies the backing .data
for my vImage_Buffer
variable. But then would I release it in my calling function? Or would setting v_image
to nil
(or whatever the returned variable is named in the calling method) ultimately release the memory allocated by the calloc
line?
Does anyone have any pointers?
First of all You also need to release colorSpace
by calling CGColorSpaceRelease(colorSpace)
Memory allocated by calloc
can later be released in calling function using free(v_image.data)
(or whatever the returned variable is named in the calling method).
You can also change Your method implementation to get rid of CGContext
and get bytes from CGImage
using CGDataProviderRef
it would be something like:
-(vImage_Buffer)convertImage:(UIImage *)image
{
CGImageRef sourceRef = [image CGImage];
NSUInteger sourceWidth = CGImageGetWidth(sourceRef);
NSUInteger sourceHeight = CGImageGetHeight(sourceRef);
CGDataProviderRef provider = CGImageGetDataProvider(sourceRef);
CFDataRef bitmapData = CGDataProviderCopyData(provider);
unsigned char *sourceData = (unsigned char*)calloc(sourceHeight * sourceWidth * 4, sizeof(unsigned char));
NSUInteger bytesPerPixel = 4;
NSUInteger sourceBytesPerRow = bytesPerPixel * sourceWidth;
CFDataGetBytes(bitmapData, CFRangeMake(0, CFDataGetLength(bitmapData)), sourceData);
vImage_Buffer v_image = {
.data = (void *)sourceData,
.height = sourceHeight,
.width = sourceWidth,
.rowBytes = sourceBytesPerRow
};
CFRelease(bitmapData);
return v_image;
}
However I didn't check the performance.
I'd also suggest to rename Your method to something like vImageCreateFromImage
. You'll be aware that later You are responsible of cleaning up the memory.