At start I need to do a fast real-time image blur. Found a useful tutorial Perform a blur using vImage.
Here is the code sample
-(UIImage *)boxblurImage:(UIImage *)image boxSize:(int)boxSize {
CGImageRef img = image.CGImage;
vImage_Buffer inBuffer, outBuffer;
vImage_Error error;
void *pixelBuffer;
//create vImage_Buffer with data from CGImageRef
CGDataProviderRef inProvider = CGImageGetDataProvider(img);
CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
inBuffer.width = CGImageGetWidth(img);
inBuffer.height = CGImageGetHeight(img);
inBuffer.rowBytes = CGImageGetBytesPerRow(img);
inBuffer.data = (void*)CFDataGetBytePtr(inBitmapData);
//create vImage_Buffer for output
pixelBuffer = malloc(CGImageGetBytesPerRow(img) * CGImageGetHeight(img));
if(pixelBuffer == NULL)
NSLog(@"No pixelbuffer");
outBuffer.data = pixelBuffer;
outBuffer.width = CGImageGetWidth(img);
outBuffer.height = CGImageGetHeight(img);
outBuffer.rowBytes = CGImageGetBytesPerRow(img);
//perform convolution
error = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
if (error) {
NSLog(@"error from convolution %ld", error);
}
//create CGImageRef from vImage_Buffer output
//1 - CGBitmapContextCreateImage -
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(outBuffer.data,
outBuffer.width,
outBuffer.height,
8,
outBuffer.rowBytes,
colorSpace,
kCGImageAlphaNoneSkipLast);
CGImageRef imageRef = CGBitmapContextCreateImage (ctx);
UIImage *returnImage = [UIImage imageWithCGImage:imageRef];
//clean up
CGContextRelease(ctx);
CGColorSpaceRelease(colorSpace);
free(pixelBuffer);
CFRelease(inBitmapData);
CGImageRelease(imageRef);
return returnImage;
}
The problem is that function throw an exception on some images. I found only one image "Broken image" (it is JPEG, not PNG).
There is the exception
<Error>: CGBitmapContextCreate: unsupported parameter combination: 8 integer bits/component; 32 bits/pixel; 3-component color space; kCGImageAlphaNoneSkipLast; 538 bytes/row.
<Error>: CGBitmapContextCreateImage: invalid context 0x0
I started to google it. Found couple of solutions.
After some time spent debugging, i found that CGImageGetBytesPerRow
return wrong value for "broken image". It fits to original image width, instead of exceed it four times as it should.
I tried to change rowBytes
in CGBitmapContextCreate
manually, but there are a lot of artifacts beginning to appear on image. The point is that bug is mysterious, its appear from times to times, but still.
How i can resolve it without of checking the rowBytes
of the buffers? I can do some precheck of rowBytes
value and return original image, but it looks like hack. And how happended so that some of the images, like our one, returns wrong rowBytes
value?
Have you looked at vImageBuffer_InitWithCGImage / vImageCreateCGImageFromBuffer?