2016-12-17 13 views
2

CIFilterCALayer에 적용하려면 사각형 조합을 제외한 영역을 사용해야합니다. 작동하지 않는 코드를 게시합니다. 정확히 반대입니다. 즉, 필터는 사각형이 아닌 외부에만 적용됩니다. CALayer에서 필터링 (사각형 일 필요는 없습니다) 사각형을 제외한 모양

func refreshTheFrameWithEffect() { 
    self.layer!.masksToBounds = true 
    self.layerUsesCoreImageFilters = true 
    self.layer!.needsDisplayOnBoundsChange = true 

    let filter = CIFilter(name: "CICircleSplashDistortion") 
    filter!.setDefaults() 
    self.layer!.backgroundFilters = [filter!] 

    var excludedRects: [CGRect] = [] //INITIALISE THEM HOW YOU PREFER 

    let maskLayer = CAShapeLayer() 
    maskLayer.frame = self.bounds 
    self.layer!.fillMode = kCAFillRuleEvenOdd 
    var maskPath = NSBezierPath() 
    for rect in excludedRects { 
     maskPath.append(NSBezierPath(rect: rect)) 
    } 

    maskLayer.path = maskPath.CGPath 
    self.layer!.mask = maskLayer 
    self.layer!.needsDisplay() 
} 

다음 NSBezierPath 이후 인터넷에서 다음 코드 UIBezierPath 달리 속성 CGPath을 가지고 있지 않습니다

.

public var CGPath: CGPath { 
    let path = CGMutablePath() 
    var points = [CGPoint](repeating: .zero, count: 3) 
    for i in 0 ..< self.elementCount { 
     let type = self.element(at: i, associatedPoints: &points) 
     switch type { 
     case .moveToBezierPathElement: path.move(to: CGPoint(x: points[0].x, y: points[0].y)) 
     case .lineToBezierPathElement: path.addLine(to: CGPoint(x: points[0].x, y: points[0].y)) 
     case .curveToBezierPathElement: path.addCurve(  to: CGPoint(x: points[2].x, y: points[2].y), 
                  control1: CGPoint(x: points[0].x, y: points[0].y), 
                  control2: CGPoint(x: points[1].x, y: points[1].y)) 
     case .closePathBezierPathElement: path.closeSubpath() 
     } 
    } 
    return path 
} 

답변

1

AFAIK, 경로의 역으로 ​​레이어를 마스킹 할 수 없습니다.

관찰의 커플 :

  1. 그냥, 당신이 할 수있는 전경 내부의 경로를 노크하려고 한 경우 그 전체 CGRect 더한 구성 경로를 만드는 트릭 다양한 실내 경로 및 짝수/홀수 권선/채우기 규칙을 활용하지만 내부 경로가 서로 겹치면 작동하지 않습니다.

  2. 이미지를 패스의 반대 방향으로 마스크 할 수 있지만 (별도의 "이미지 마스크"를 만들어 냄) 동적 마스크 CALayer 마스킹에서는 작동하지 않습니다. NSImage 마스킹에 사용됩니다. 따라서보기의 필터링 된 부분에 대한 스냅 샷을 사용하여 정상적인 경우 옵션입니다.

    이미지 마스크를 사용하는 예는 아래 코드 스 니펫을 참조하십시오.

  3. 또 다른 접근법은 전체보기에 필터를 적용하고 스냅 샷을 찍은 다음 문제의보기 아래에 스냅 샷을 놓은 다음 최상위 레벨보기를 내부 경로로가립니다. 사실상 필터링되지 않은 뷰를 내부 경로로 가린 다음 그 아래에 뷰의 필터링 된 스냅 샷을 표시합니다.

  4. 그러나 접근 방법은 모든 내부 경로의 통합에 대한 개요를 나타내는 경로를 만드는 것입니다. 경로가 단순한 경우 (예 : 회전하지 않은 사각형) 매우 쉽습니다. 경로가 복잡하면 (일부는 회전되고, 일부는 직사각형이 아닌 경로 등), 이것은 털이 있습니다. 그러나 사소한 시나리오는 그렇게 나쁘지 않습니다. 어쨌든, 그렇게한다면, 그 이상한 트릭으로 돌아갈 수 있습니다.

이러한 접근 방식 중 일부는 전적으로 만족스럽지 않지만 찾고자하는 것을 성취 할 수있는 다른 방법은 없습니다. 희망을 갖고 누군가가이 문제를 해결할 수있는 더 좋은 방법을 제안 할 것입니다.


(아마도 중복, 몇 가지 경로를 그려 만든 이미지 마스크를 사용) 옵션 2에 확장하려면, 스위프트 3 당신은 같은 작업을 수행 할 수 있습니다

private func maskImageWithPaths(image: NSImage, size: CGSize) -> NSImage { 
    // define parameters for two overlapping paths 

    let center1 = CGPoint(x: size.width * 0.40, y: size.height/2) 
    let radius1 = size.width * 0.20 

    let center2 = CGPoint(x: size.width * 0.60 , y: size.height/2) 
    let radius2 = size.width * 0.20 

    // create these two overlapping paths 

    let path = CGMutablePath() 
    path.move(to: center1) 
    path.addArc(center: center1, radius: radius1, startAngle: -.pi/2, endAngle: .pi * 3/2, clockwise: false) 
    path.move(to: center2) 
    path.addArc(center: center2, radius: radius2, startAngle: -.pi/2, endAngle: .pi * 3/2, clockwise: false) 

    // create image from these paths 

    let imageRep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(size.width), pixelsHigh: Int(size.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSDeviceRGBColorSpace, bitmapFormat: .alphaFirst, bytesPerRow: 4 * Int(size.width), bitsPerPixel: 32)! 
    let context = NSGraphicsContext(bitmapImageRep: imageRep)! 

    context.cgContext.addPath(path) 
    context.cgContext.setFillColor(NSColor.blue.cgColor) 
    context.cgContext.fillPath() 
    let maskImage = context.cgContext.makeImage()! 

    let mask = CGImage(maskWidth: Int(size.width), height: Int(size.height), bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: 4 * Int(size.width), provider: maskImage.dataProvider!, decode: nil, shouldInterpolate: true)! 

    let finalImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil)!.masking(mask)! 
    return NSImage(cgImage: finalImage, size: size) 
} 

그 수율 :

masked image

이렇게하면 그려진 패스가 마스크됩니다.

+0

필터에서 제외하려는 배경 뷰는 CGImage에서 가져옵니다. 그래서 저는 제외시키고 자하는 모든 직사각형에 대해 CGImage를 잘라내어 코드가 필터와 관련된 뷰 위의 뷰에 배치되도록 코드를 관리했습니다.더 정확하게 각 사각형에 대해 CGImage 자르기, NSImage 만들기, CALayer 만들기 및 NSImage와 같은 레이어 내용 설정, 레이어의 프레임을 NSImage 크기와 같게 설정하고 추가합니다 뷰의 레이어의 서브 레이어로서의 레이어. 모든 작업은 코드가 너무 느립니다. 빨리 코드를 작성할 수 있습니까? – Nisba

+0

@LucaMarconato - 글쎄, 이미지를 마스크하고 싶다면'let maskImage = CGImage (maskWidth : ...)'와'someCgImage.masking (maskImage)'를 사용할 수있다. 첨부 된 코드 스 니펫을 참조하십시오. 그러나 그것은 CGImage를 마스킹하기위한 것이지 마스킹 레이어가 아닙니다. 위의 예를 참조하십시오. 하지만 짝수/홀수 풀기/채우기 규칙을 사용하여 겹치는 경로와 관련된 기이함을 해결합니다. – Rob