I am programmatically creating a CALayer subclass which applies a bit of pixel noise to itself. The code works in that it renders noise in the layer, but there is a strange artifact on the image that I am unable to determine the root cause.
Here is a sample image with the noiseOpacity turned up to make the problem more visible.

The pink box is a UANoisyGradientLayer, a CAGradientLayer subclass with the following bits:
@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);
}
Basically, I create the CIImage in init using a CIRandomGenerator as input to a CIColorMonochrome filter. Then, when it comes time to draw it, I create a CGImageRef out of it using self.bounds (the extent is always infinite or 0), and draw it to the context.
The result is mostly fine, but as you can see in the image, there seems to be some stretching going on. What is happening here?
Although not fixing the original problem, I approached this from a different angle and have duplicated the output. Instead of trying to generate a single image the size of the
self.bounds, I am now generating an image that is only 64×64, then tiling it usingCGContextDrawTiledImage. Because I am now sizing it at a fixed size, I could pull some code out of thedrawInContext:method. And finally, because there was no more image generation done in the draw methods, I was able to make it a static var so it is only ever generated once! Here is the complete class:NOTE:
CIColorMonochromeandCIRandomGeneratorrequire iOS 6 (or newer). Make sure to include the required frameworks (CoreImage.frameworkandQuartzCore.framework).