我正在以编程方式创建一个CALayer
子类,它将一些像素噪声应用于自身。代码的工作原理是它在图层中呈现噪声,但是图像上有一个奇怪的工件,我无法确定根本原因。
以下是调出noiseOpacity
的示例图片,以使问题更加明显。
粉红色框是UANoisyGradientLayer
,CAGradientLayer
子类,包含以下内容:
@interface UANoisyGradientLayer ()
@property (nonatomic, retain) CIContext *noiseContext;
@property (nonatomic, retain) CIFilter *noiseGenerator;
@property (nonatomic, retain) CIImage *noiseImage;
@end
@implementation UANoisyGradientLayer
@synthesize noiseOpacity = _noiseOpacity, noiseImage;
- (id)init {
self = [super init];
if (self) {
self.noiseOpacity = 0.10;
self.noiseContext = [CIContext contextWithOptions:nil];
self.noiseGenerator = [CIFilter filterWithName:@"CIColorMonochrome"];
[self.noiseGenerator setValue:[[CIFilter filterWithName:@"CIRandomGenerator"] valueForKey:@"outputImage"] forKey:@"inputImage"];
[self.noiseGenerator setDefaults];
self.noiseImage = [self.noiseGenerator outputImage];
}
return self;
}
- (void)drawInContext:(CGContextRef)ctx {
[super drawInContext:ctx];
CGRect extentRect = [self.noiseImage extent];
if (CGRectIsInfinite(extentRect) || CGRectIsEmpty(extentRect)) {
extentRect = self.bounds;
}
CGImageRef cgimg = [self.noiseContext createCGImage:self.noiseImage fromRect:extentRect];
CGContextSetBlendMode(ctx, kCGBlendModeOverlay);
CGContextSetAlpha(ctx, self.noiseOpacity);
CGContextDrawImage(ctx, self.bounds, cgimg);
CGImageRelease(cgimg);
}
基本上,我使用CIImage
作为CIRandomGenerator
过滤器的输入在init中创建CIColorMonochrome
。然后,当需要绘制它时,我使用CGImageRef
创建self.bounds
(范围始终 infinite
或0),并绘制它是在上下文中。
结果大部分都很好,但正如你在图片中看到的那样,似乎正在进行一些拉伸。这里发生了什么?
答案 0 :(得分:8)
虽然没有解决原来的问题,但我从一个不同的角度解决了这个问题并重复了输出。我现在生成的图像仅为64x64,然后使用self.bounds
平铺图像,而不是尝试生成CGContextDrawTiledImage
大小的单个图像。因为我现在正在调整固定大小,我可以从drawInContext:
方法中提取一些代码。最后,因为在绘制方法中没有更多的图像生成,我能够使它成为一个静态var,所以它只生成一次!这是完整的课程:
static CGImageRef __noiseImage = nil;
static CGFloat __noiseImageWidth = 0.0;
static CGFloat __noiseImageHeight = 0.0;
@implementation UANoisyGradientLayer
@synthesize noiseOpacity = _noiseOpacity;
- (id)init {
self = [super init];
if (self) {
self.noiseOpacity = 0.1f;
self.needsDisplayOnBoundsChange = YES;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
CIContext *noiseContext = [CIContext contextWithOptions:nil];
CIFilter *noiseGenerator = [CIFilter filterWithName:@"CIColorMonochrome"];
[noiseGenerator setValue:[[CIFilter filterWithName:@"CIRandomGenerator"] valueForKey:@"outputImage"] forKey:@"inputImage"];
[noiseGenerator setDefaults];
CIImage *ciImage = [noiseGenerator outputImage];
CGRect extentRect = [ciImage extent];
if (CGRectIsInfinite(extentRect) || CGRectIsEmpty(extentRect)) {
extentRect = CGRectMake(0, 0, 64, 64);
}
__noiseImage = [noiseContext createCGImage:ciImage fromRect:extentRect];
__noiseImageWidth = CGImageGetWidth(__noiseImage);
__noiseImageHeight = CGImageGetHeight(__noiseImage);
});
}
return self;
}
- (void)drawInContext:(CGContextRef)ctx {
[super drawInContext:ctx];
if (self.noiseOpacity > 0) {
CGContextSaveGState(ctx);
CGPathRef path = [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.cornerRadius] CGPath];
CGContextAddPath(ctx, path);
CGContextClip(ctx);
CGContextSetBlendMode(ctx, kCGBlendModeOverlay);
CGContextSetAlpha(ctx, self.noiseOpacity);
CGContextDrawTiledImage(ctx, CGRectMake(0, 0, __noiseImageWidth, __noiseImageHeight), __noiseImage);
CGContextRestoreGState(ctx);
}
}
@end
注意:CIColorMonochrome
和CIRandomGenerator
需要 iOS 6 (或更新)。确保包含所需的框架(CoreImage.framework
和QuartzCore.framework
)。