我正在制作一个iOS应用程序,其中有一个用多个UIImageViews切换大量图片的过程(用一堆图像设置UIImageView的图像属性的循环)。有时一些图像需要一些图形效果,比如乘法。
最简单的方法是使用CIFilter来做这件事,但问题是iOS上的CALayer不支持“filters”属性,因此您需要在设置“image”属性之前将效果应用于图像。但是当你经常刷新屏幕时,这实在太慢了。
接下来我尝试直接使用Core Graphics与UIGraphics上下文和kCGBlendModeMultiply进行乘法运算。这实际上比使用CIFilter快得多,但由于您必须在渲染图像之前应用乘法,因此在尝试渲染具有乘法效果的图像时,您仍然可以感觉程序运行速度慢于渲染普通图像。
我的猜测是这两种方法的基本问题是你必须用GPU处理图像效果,然后用CPU得到结果图像,最后用GPU渲染结果图像,这意味着数据CPU和GPU之间的转移浪费了很多时间,因此我尝试将超类从UIImageView更改为UIView并将CGGraphics上下文代码实现为drawRect方法,然后当我设置“image”属性时,我在didSet中调用setNeedsDisplay方法。但是这不能很好地工作......实际上每次调用setNeedsDisplay时程序变得比使用CIFilter慢得多,可能是因为有几个视图显示。
我想这可能是我可以用OpenGL解决这个问题,但我想知道我是否只能用UIKit解决这个问题?
答案 0 :(得分:0)
据我了解,您必须对不同的图像进行相同的更改。因此,初始初始化的时间对您来说并不重要,但应尽快处理每个图像。首先,在后台队列/线程中生成新图像是 critical 。 快速处理/生成图像有两种好方法:
使用CoreImage中的CIFilter
使用GPUImage库
如果您使用CoreImage,请检查您是否正确使用了CIFilter和CIContext。 CIContext创建需要花费很多时间,但在不同的CIF过滤器和图像之间可能是 SHARED - 所以你应该只创建一次CIContext! CIFilter在不同的图像之间也可能 SHARED ,但由于它不是线程安全的,因此每个线程都应该有一个单独的CIFilter。
在我的代码中,我有以下内容:
+ (UIImage*)roundShadowImageForImage:(UIImage*)image {
static CIFilter *_filter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
NSLog(@"CIContext and CIFilter generating...");
_context = [CIContext contextWithOptions:@{ kCIContextUseSoftwareRenderer: @NO,
kCIContextWorkingColorSpace : [NSNull null] }];
CIImage *roundShadowImage = [CIImage imageWithCGImage:[[self class] roundShadowImage].CGImage];
CIImage *maskImage = [CIImage imageWithCGImage:[[self class] roundWhiteImage].CGImage];
_filter = [CIFilter filterWithName:@"CIBlendWithAlphaMask"
keysAndValues:
kCIInputBackgroundImageKey, roundShadowImage,
kCIInputMaskImageKey, maskImage, nil];
NSLog(@"CIContext and CIFilter are generated");
});
if (image == nil) {
return nil;
}
NSAssert(_filter, @"Error: CIFilter for cover images is not generated");
CGSize imageSize = CGSizeMake(image.size.width * image.scale, image.size.height * image.scale);
// CIContext and CIImage objects are immutable, which means each can be shared safely among threads
CIFilter *filterForThread = [_filter copy]; // CIFilter could not be shared between different threads.
CGAffineTransform imageTransform = CGAffineTransformIdentity;
if (!CGSizeEqualToSize(imageSize, coverSize)) {
NSLog(@"Cover image. Resizing image %@ to required size %@", NSStringFromCGSize(imageSize), NSStringFromCGSize(coverSize));
CGFloat scaleFactor = MAX(coverSide / imageSize.width, coverSide / imageSize.height);
imageTransform = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
}
imageTransform = CGAffineTransformTranslate(imageTransform, extraBorder, extraBorder);
CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
ciImage = [ciImage imageByApplyingTransform:imageTransform];
if (image.hasAlpha) {
CIImage *ciWhiteImage = [CIImage imageWithCGImage:[self whiteImage].CGImage];
CIFilter *filter = [CIFilter filterWithName:@"CISourceOverCompositing"
keysAndValues:
kCIInputBackgroundImageKey, ciWhiteImage,
kCIInputImageKey, ciImage, nil];
[filterForThread setValue:filter.outputImage forKey:kCIInputImageKey];
}
else
{
[filterForThread setValue:ciImage forKey:kCIInputImageKey];
}
CIImage *outputCIImage = [filterForThread outputImage];
CGImageRef cgimg = [_context createCGImage:outputCIImage fromRect:[outputCIImage extent]];
UIImage *newImage = [UIImage imageWithCGImage:cgimg];
CGImageRelease(cgimg);
return newImage;
}
如果你对速度仍不满意,试试GPUImage这是一个非常好的库,它也非常快,因为它使用OpenGL进行图像生成。