这是一个奇怪的 - 我甚至不知道如何开始。
我正在使用CIFilter
来模糊图像。以下是代码的本质,作为UIImage
上的类别实现:
- (void)imageByApplyingBlur:(CGFloat)radius completion:(void (^)(UIImage *))completion {
// If no completion, then nothing to do
if (completion == nil) {
return;
}
// If no radius, self is the result
if (radius == 0.0) {
completion(self);
return;
}
UIApplicationState appState = [UIApplication sharedApplication].applicationState;
CIImage *imageToBlur = [CIImage imageWithCGImage:self.CGImage];
CGFloat scale = [UIScreen mainScreen].scale;
// Do the thread-safe CIImage blurring on a high-priority concurrent thread.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSDictionary *contextOptions = nil;
// Always include the kCIContextPriorityRequestLow : @(YES) pair, because
// otherwise, the foreground animation framerate suffers while blurring.
if (appState == UIApplicationStateBackground) {
contextOptions = @{
kCIContextPriorityRequestLow : @(YES),
// If we're not active, force CIContext to use the CPU renderer
// CPU rendering should be allowed even in the background
kCIContextUseSoftwareRenderer : @(YES)
};
} else {
contextOptions = @{
kCIContextPriorityRequestLow : @(YES),
};
}
CIContext *context = [CIContext contextWithOptions:contextOptions];
CIFilter *gaussianBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
[gaussianBlurFilter setValue:imageToBlur forKey:@"inputImage"];
[gaussianBlurFilter setValue:@(radius) forKey:@"inputRadius"];
CIImage *resultImage = [gaussianBlurFilter valueForKey:@"outputImage"];
CGRect cropRect = {
.origin.x = radius,
.origin.y = radius,
.size.width = (imageToBlur.extent.size.width - (2 * radius)),
.size.height = (imageToBlur.extent.size.height - (2 * radius))
};
// Crop transparent edges from blur
resultImage = [resultImage imageByCroppingToRect:cropRect];
// Generate returnable UIImage (important to make the image "from" a CGImage, not a CIImage)
CGImageRef resultCGImage = [context createCGImage:resultImage fromRect:resultImage.extent];
UIImage *resultUIImage = [UIImage imageWithCGImage:resultCGImage
scale:scale
orientation:UIImageOrientationUp];
CGImageRelease(resultCGImage);
// The completion block has to happen on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
completion(resultUIImage);
});
});
}
大约90%的时间,这种方法完美无瑕。但是,有时,它从不向回调块提交有效图像,我看到了一个令人难以置信的错误日志。错误日志很长,所以我会等到问题结束后复制粘贴它。
一些注意事项:
在模糊并发调度队列之前,我同步模糊了。这很慢,但我从未见过这种问题。可能是代码中的某些东西在队列中同时发生并不正常吗?当我的应用程序启动时,它使用此方法提交两个图像模糊,这是我唯一一次注意到该方法无法正常工作。
This question talks about requirements for using CIFilter
from multiple threads safely,但就我所知,我满足了这些要求。理论上我可以为此移动到一个串行队列,但我不明白为什么这一定会有所帮助。
我得到的错误真的奇怪 - 我不太了解CoreImage如何在内部工作,但这看起来像应该编译为在GPU上执行的代码是以某种方式无效。但只有部分时间?我真的很难过。
那么,我的问题是怎么回事?理想情况下,我该如何解决?
当我没有图像时,下面是相关的日志输出:
liblib:3:15: error: :unkown type or function name: 'mix'
3:15: error: unkown type or function name: 'mix'
return mix(y, z, step(0.0,x));
^
return mix(y, z, step(0.0,x));
^
lib:lib:1:16:6:: error : error: non-void function should return a value
non-void function should return a value
vec4 compare (vec4 x, vec4 y, vec4 z)
^
vec4 compare (vec4 x, vec4 y, vec4 z)
^
lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
return tan(x);
^~~
tan_
lib:51:26: error: unkown type or function name: 'max'
return vec4(s.rgb/max(s.a,0.00001), s.a);
^
lib:49:6: error: non-void function should return a value
vec4 unpremultiply (vec4 s)
^
lib:56:28: error: unkown type or function name: 'mix'
s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
^
lib:62:28: error: unkown type or function name: 'mix'
s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
^
filter:4:12: error: unkown type or function name: 'clamp'
x = clamp(min(x, x.yzwx), 0.0, 1.0);
^
filter:1:55: error: unkown type or function name: 'max'
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
^
filter:1:6: error: non-void function should return a value
lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
return tan(x);
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
^
^~~
tan_
filter:3:26: error: unkown type or function name: 'mix'
lib:51:26: error: unkown type or function name: 'max'
s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
^
return vec4(s.rgb/max(s.a,0.00001), s.a);
^
lib:49:6: error: non-void function should return a value
vec4 unpremultiply (vec4 s)
^
lib:56:28: error: unkown type or function name: 'mix'
s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
^
lib:62:28: error: unkown type or function name: 'mix'
s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
^
lib:3:15: error: unkown type or function name: 'mix'
return mix(y, z, step(0.0,x));
^
lib:1:6: error: non-void function should return a value
vec4 compare (vec4 x, vec4 y, vec4 z)
^
filter:4:12: error: unkown type or function name: 'clamp'
x = clamp(min(x, x.yzwx), 0.0, 1.0);
^
lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
filter:1: return tan(x);
55: ^~~
tan_error
: unkown type or function name: 'max'
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
^
libfilter::511::266:: errorerror: : unkown type or function name: 'max'
non-void function should return a value
return vec4(s.rgb/max(s.a,0.00001), s.a);
^
lib:49:vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }6
: ^
error: non-void function should return a value
vec4 unpremultiply (vec4 s)
^
filter:3:26: error: unkown type or function name: 'mix'
lib:56:28: error: unkown type or function name: 'mix'
s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
^
s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
^
lib:62:28: error: unkown type or function name: 'mix'
s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
^
lib:3:15: error: unkown type or function name: 'mix'
return mix(y, z, step(0.0,x));
^
filter:lib1:1:6::55: error : error: unkown type or function name: 'max'non-void function should return a value
vec4 compare (vec4 x, vec4 y, vec4 z)
^
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
^
filter:1:6: error: non-void function should return a value
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
^
filter:3:26: error: unkown type or function name: 'mix'
lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb))); return tan(x);
^
^~~
tan_
filter:1:47: error: unkown type or function name: 'clamp'
lib:51:26: errorvec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
^
filter:1:6: error: non-void function should return a value
: unkown type or function name: 'max'
vec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
^
return vec4(s.rgb/max(s.a,0.00001), s.a);
^
lib:49:6: error: non-void function should return a value
vec4 unpremultiply (vec4 s)
^
lib:56:28: error: unkown type or function name: 'mix'
s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
^
lib:62:28: error: unkown type or function name: 'mix'
s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
^
filter:1:55: error: unkown type or function name: 'max'
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
^
filter:1:6: error: non-void function should return a value
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
^
filter:3:26: error: unkown type or function name: 'mix'
s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
^
filter:1:47: error: unkown type or function name: 'clamp'
vec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
^
filter:1:6: error: non-void function should return a value
vec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
^
ERROR - could not find uniform for argument 0
ERROR - could not find uniform for argument 0
ERROR - could not find uniform for argument 1
ERROR - could not find uniform for argument 1
ERROR - could not find uniform for argument 2
ERROR - could not find uniform for argument 2
ERROR - could not find uniform for argument 3
ERROR - could not find uniform for argument 3
答案 0 :(得分:0)
这与您的主要问题无关,但有一种更好的方法可以“从模糊中裁剪透明边缘”。试试这个:
CGRect originalExtent = img.extent;
img = [img imageByClampingToExtent:originalExtent];
img = [img imageByApplyingFilter:@"CIGaussianBlur"
params:@{@"inputRadius" : @(radius)}];
img = [imageByCroppingToRect:originalExtent]
答案 1 :(得分:-1)
虽然它不是错误的解决方案,但我绝对推荐GPUImage
用于GPU绑定图像操作,其中包括非常快速的高斯模糊滤镜。