2012-07-04 36 views
1

我正在編程創建一個CALayer子類,它將自己的像素噪聲應用到位。該代碼的工作原理是它在圖層中呈現噪點,但圖像上有一個奇怪的工件,我無法確定根本原因。使用Core Image呈現隨機噪聲CALayer會產生奇怪的僞像

下面是一個帶有noiseOpacity的示例圖像,使問題更加明顯。

enter image description here

粉紅色框是一個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); 
} 

基本上,我使用CIRandomGenerator作爲輸入提供給CIColorMonochrome濾波器創建在初始化的CIImage。然後,當它繪製它時,我使用self.bounds(範圍是總是或0)創建一個CGImageRef,並將其繪製到上下文中。

結果大部分都很好,但正如您在圖片中看到的那樣,似乎正在進行一些延伸。這裏發生了什麼?

+0

這有點晚,但是您發佈的代碼與圖片不符。在我的iPad Mini和模擬器中,這個類可以達到預期的效果:隨機噪聲層。請張貼實際重現錯誤的代碼。 – alecail

+0

它在發佈時做過。您可能正在使用不同的操作系統或SDK。請參閱下面的解決方案 – coneybeare

回答

7

雖然沒有解決原來的問題,但我從不同的角度處理了這個問題,並重復了輸出。我現在生成的圖像只有64x64,然後使用CGContextDrawTiledImage將其平鋪,而不是嘗試生成大小爲self.bounds的單個圖像。因爲我現在正在調整大小,我可以從drawInContext:方法中抽取一些代碼。最後,因爲在繪圖方法中沒有更多的圖像生成功能,所以我可以將它變成一個靜態變量,因此它只能生成一次!下面是完整的類:

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 

注意CIColorMonochromeCIRandomGenerator需要的iOS 6(或更新版本)。確保包含所需的框架(CoreImage.frameworkQuartzCore.framework)。

+0

感謝您的支持!只是我在找什麼。 –