Как мне использовать Accelerate Framework с основной графикой?
У меня есть проект. Он в основном берет фотографию с камеры iPhone и применяет некоторые эффекты к фотографии. Прежде чем применить эффект, я использую основную графику для масштабирования изображения до соответствующего размера. После масштабирования и поворота изображения я использую Accelerate framework(vImage), чтобы создать эффект. Моя проблема в том, что после применения эффекта получается какое-то синеватое изображение. Однако, если я не масштабирую изображение с основной графикой, этого синеватого вида не произойдет.
Масштабный код, который я использую, взят из этого поста.
А вот мой код, который применяет эффект:
- (UIImage *)applyFiltertoImage:(UIImage *)img
{
CGImageRef image = img.CGImage;
vImage_Buffer inBuffer, outBuffer;
void *pixelBuffer;
CGDataProviderRef inProvider = CGImageGetDataProvider(image);
CFDataRef inBitmapData = CGDataProviderCopyData(inProvider);
inBuffer.width = CGImageGetWidth(image);
inBuffer.height = CGImageGetHeight(image);
inBuffer.rowBytes = CGImageGetBytesPerRow(image);
inBuffer.data = (void *)CFDataGetBytePtr(inBitmapData);
pixelBuffer = malloc(CGImageGetBytesPerRow(image) * CGImageGetHeight(image));
if (pixelBuffer == NULL) {
NSLog(@"No buffer");
}
outBuffer.data = pixelBuffer;
outBuffer.width = CGImageGetWidth(image);
outBuffer.height = CGImageGetHeight(image);
outBuffer.rowBytes = CGImageGetBytesPerRow(image);
vImageConvolve_ARGB8888(&inBuffer, &outBuffer, NULL, 0, 0, self.kernel, self.size, self.size, self.divisor, NULL, kvImageEdgeExtend);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(outBuffer.data,
outBuffer.width,
outBuffer.height,
8,
outBuffer.rowBytes,
colorSpace,
kCGImageAlphaNoneSkipLast);
CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
UIImage *blurredImage = [UIImage imageWithCGImage:imageRef];
CGContextRelease(ctx);
CGColorSpaceRelease(colorSpace);
free(pixelBuffer);
CFRelease(inBitmapData);
CGImageRelease(imageRef);
return blurredImage;
}
2 ответа
Избегать ручного переопределения CGContext
Попробуйте позволить vImage инициализировать значения для вас. vImageBuffer_InitWithCGImage
может помочь вам избежать боли.
Прямая версия
- (UIImage *)applyFiltertoImage:(UIImage *)image
CGImageRef originalImageRef = image.CGImage;
CGColorSpaceRef originalColorSpace = CGColorSpaceRetain(CGImageGetColorSpace(originalImageRef));
if (_pixelBuffer == NULL) {
_pixelBuffer = malloc(CGImageGetBytesPerRow(originalImageRef) * CGImageGetHeight(originalImageRef));
}
vImage_CGImageFormat inputImageFormat =
{
.bitsPerComponent = (uint32_t) CGImageGetBitsPerComponent(originalImageRef),
.bitsPerPixel = (uint32_t) CGImageGetBitsPerComponent(originalImageRef) * (uint32_t)(CGColorSpaceGetNumberOfComponents(originalColorSpace) + (kCGImageAlphaNone != CGImageGetAlphaInfo(originalImageRef))),
.colorSpace = originalColorSpace,
.bitmapInfo = CGImageGetBitmapInfo(originalImageRef),
.version = 0,
.decode = NULL,
.renderingIntent = kCGRenderingIntentDefault
};
vImage_Buffer inputImageBuffer;
vImageBuffer_InitWithCGImage(&inputImageBuffer, &inputImageFormat, NULL, originalImageRef, kvImageNoFlags);
vImage_Buffer outputImageBuffer = {
.data = _pixelBuffer,
.width = CGImageGetWidth(originalImageRef),
.height = CGImageGetHeight(originalImageRef),
.rowBytes = CGImageGetBytesPerRow(originalImageRef)
};
vImage_Error error;
error = vImageConvolve_ARGB8888(&inputImageBuffer,
&outputImageBuffer,
NULL,
0,
0,
self.kernel,
self.size,
self.divisor,
NULL,
kvImageEdgeExtend);
if (error) {
NSLog(@"vImage error %zd", error);
}
free(inputImageBuffer.data);
vImage_CGImageFormat outFormat =
{
.bitsPerComponent = (uint32_t) CGImageGetBitsPerComponent(originalImageRef),
.bitsPerPixel = (uint32_t) CGImageGetBitsPerComponent(originalImageRef) * (uint32_t)(CGColorSpaceGetNumberOfComponents(originalColorSpace) + (kCGImageAlphaNone != CGImageGetAlphaInfo(originalImageRef))),
.colorSpace = originalColorSpace,
.bitmapInfo = CGImageGetBitmapInfo(originalImageRef),
.version = 0,
.decode = NULL,
.renderingIntent = kCGRenderingIntentDefault
};
CGImageRef modifiedImageRef = vImageCreateCGImageFromBuffer(&outputImageBuffer,
&outFormat,
NULL,
NULL,
kvImageNoFlags,
&error);
CGColorSpaceRelease(originalColorSpace);
UIImage *returnImage = [UIImage imageWithCGImage:modifiedImageRef];
CGImageRelease(modifiedImageRef);
return returnImage;
}
Высокоэффективное издание
Создайте _inputImageBuffer, _outputImageBuffer и _outputImageFormat по одному разу для каждого изображения, а затем просто повторно примените фильтр к исходному изображению. После того, как vImage нагреется, он начнет сбривать на несколько миллисекунд от вызова.
- (UIImage *)applyFilter
vImage_Error error;
error = vImageConvolve_ARGB8888(&_inputImageBuffer,
&_outputImageBuffer,
NULL,
0,
0,
self.kernel,
self.size,
self.divisor,
NULL,
kvImageEdgeExtend);
if (error) {
NSLog(@"vImage error %zd", error);
}
CGImageRef modifiedImageRef = vImageCreateCGImageFromBuffer(&_outputImageBuffer,
&_outputImageFormat,
NULL,
NULL,
kvImageNoFlags,
&error);
UIImage *returnImage = [UIImage imageWithCGImage:modifiedImageRef];
CGImageRelease(modifiedImageRef);
return returnImage;
}
Обычно сильный цветовой оттенок означает, что порядок цветовых каналов был потерян при переводе где-то по пути, например, вы создали CG-изображение с данными BGRA, но на самом деле это был ARGB.
Вы смотрели на vImage_Utilities.h?