2012-07-04 5 views
1

저는 픽셀 노이즈를 자체적으로 적용하는 CALayer 서브 클래스를 프로그래밍 방식으로 만듭니다. 이 코드는 레이어에 노이즈를 렌더링한다는 점에서 작동하지만 근본 원인을 결정할 수없는 이미지에 이상한 아티팩트가 있습니다.랜덤 노이즈 랜더링 CALayer가 Core Image로 이상한 아티팩트를 생성하고 있습니다.

여기에 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); 
} 

, I는 CIColorMonochrome 필터 입력으로 CIRandomGenerator를 사용 INIT에서 CIImage를 생성한다. 그런 다음 그림을 그릴 때가되면 self.bounds (범위는 항상infinite 또는 0 임)을 사용하여 그 중 CGImageRef을 만들고 상황에 맞게 그립니다.

결과는 대부분 괜찮지 만 이미지에서 볼 수 있듯이 약간의 스트레칭이있는 것 같습니다. 여기서 무슨 일이 일어나고있는거야?

+0

조금 늦었지만 게시 한 코드가 사진과 일치하지 않습니다. 내 iPad Mini 및 시뮬레이터에서이 클래스는 예상 한대로 작동합니다. 임의의 노이즈가있는 레이어입니다. 실제로 오류를 재현하는 코드를 게시하십시오. – alecail

+0

게시 당시에 했어. 다른 운영 체제 또는 SDK를 사용 중일 수 있습니다. 아래 내 솔루션을 참조하십시오. – coneybeare

답변

7

원래 문제는 수정하지 않았지만 다른 각도에서이 문제에 접근하여 출력을 복제했습니다. self.bounds 크기의 단일 이미지를 생성하는 대신 이제는 64x64 이미지 만 생성 한 다음 CGContextDrawTiledImage을 사용하여 이미지를 타일링합니다. 이제 고정 크기로 크기를 조정하기 때문에 drawInContext: 메서드에서 일부 코드를 가져올 수 있습니다. 마지막으로 드로잉 메서드에서 더 이상의 이미지 생성 작업을 수행하지 않아 정적 var로 만들 수 있었기 때문에 한 번만 생성되었습니다. CIColorMonochromeCIRandomGenerator 아이폰 OS 6 (이상) 이 필요합니다

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 

참고 : 여기에 전체 클래스입니다. 필수 프레임 워크 (CoreImage.frameworkQuartzCore.framework)를 포함해야합니다.

+0

감사합니다. 내가 찾고있는 것. –