3

一开始我需要做一个快速的实时图像模糊。找到了一个有用的教程Perform a blur using vImage。

这是代码示例

-(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;
}

问题是该函数在某些图像上引发异常。我只找到一张图片“损坏的图片”(它是 JPEG,不是 PNG)。

有例外

<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

我开始用谷歌搜索它。找到了几个解决方案。经过一段时间的调试,我发现CGImageGetBytesPerRow“损坏的图像”返回错误的值。它适合原始图像宽度,而不是超出它应该的四倍。

我尝试手动更改rowBytesCGBitmapContextCreate但图像上开始出现很多伪影。关键是这个bug很神秘,它时而出现,但仍然存在。

我如何在不检查rowBytes缓冲区的情况下解决它?我可以对值进行一些预检查rowBytes并返回原始图像,但它看起来像 hack。又是如何发生的,一些图像,比如我们的图像,返回错误的rowBytes值?

4

1 回答 1

0

你看过 vImageBuffer_InitWithCGImage / vImageCreateCGImageFromBuffer 吗?

vImage_Buffer buf = {0};
vImage_CGImageFormat fmt = {
    .bitsPerComponent = 8,
    .bitsPerPixel = 32,
    .colorSpace = CGImageGetColorSpace(image),
    .bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrderDefault
};

vImage_Error err = vImageBuffer_InitWithCGImage( &buf, &fmt, NULL, image, kvImageNoFlags ); // allocates buf.data 

vImage_Buffer outBuffer;
vImageBuffer_Init( &outBuffer, buf.height, buf.width, fmt.bitsPerPixel, kvImageNoFlags);
vImageBoxConvolve_ARGB8888(&buf, &outBuffer, ...);
free(buf.data);

CGImageRef newImage = vImageCreateCGImageFromBuffer( &outBuffer, &fmt, NULL, NULL, kvImageNoAllocate, &err );  // outBuffer.data will be freed when the CGImageRef is released.
于 2014-09-09T22:02:42.167 回答