Fix clipping masks
This commit is contained in:
parent
7e1ddaf2bf
commit
3c7c1f865a
1 changed files with 25 additions and 72 deletions
|
@ -494,7 +494,7 @@ class Document: NSDocument {
|
||||||
var masterImage = ccgContext?.makeImage()
|
var masterImage = ccgContext?.makeImage()
|
||||||
let context = CIContext()
|
let context = CIContext()
|
||||||
|
|
||||||
var previousImage: CGImage?
|
var previousImage: CGImage? = masterImage
|
||||||
|
|
||||||
for layer in info.layers.reversed() {
|
for layer in info.layers.reversed() {
|
||||||
// start by creating a new layer composite image, needed for image masking
|
// start by creating a new layer composite image, needed for image masking
|
||||||
|
@ -529,25 +529,22 @@ class Document: NSDocument {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let layerImage = (layerContext?.makeImage())!
|
let layerImage = layerContext?.makeImage()
|
||||||
|
|
||||||
if layer.clipped {
|
if layer.clipped && previousImage != nil {
|
||||||
guard let result = previousImage?.toGrayscale() else {
|
let result = previousImage!.toGrayscale()
|
||||||
return nil
|
let newImage = layerImage!.masking(result!)
|
||||||
}
|
|
||||||
|
|
||||||
let newImage = layerImage.masking(result)!
|
|
||||||
|
|
||||||
previousImage = newImage
|
previousImage = newImage
|
||||||
} else if layer.mask != nil {
|
} else if layer.mask != nil {
|
||||||
let maskImage = (maskContext?.makeImage())!
|
let maskImage = (maskContext?.makeImage())!
|
||||||
let newImage = layerImage.masking(maskImage)!
|
let newImage = layerImage!.masking(maskImage)!
|
||||||
|
|
||||||
previousImage = newImage
|
previousImage = newImage
|
||||||
} else {
|
} else {
|
||||||
previousImage = layerImage
|
previousImage = layerImage
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply image
|
// apply image
|
||||||
let ciImage = CIImage(cgImage: (masterImage)!)
|
let ciImage = CIImage(cgImage: (masterImage)!)
|
||||||
let newCiImage = kernel!.apply(foreground: CIImage(cgImage: previousImage!), background: ciImage, colorSpace: info.colorSpace)
|
let newCiImage = kernel!.apply(foreground: CIImage(cgImage: previousImage!), background: ciImage, colorSpace: info.colorSpace)
|
||||||
|
@ -660,76 +657,32 @@ public extension NSImage {
|
||||||
|
|
||||||
public extension CGImage {
|
public extension CGImage {
|
||||||
func toGrayscale() -> CGImage? {
|
func toGrayscale() -> CGImage? {
|
||||||
guard let format = vImage_CGImageFormat(cgImage: self) else {
|
let ciImage = CIImage(cgImage: self)
|
||||||
|
|
||||||
|
let filter = CIFilter(name: "CIColorControls")
|
||||||
|
filter?.setValue(ciImage, forKey: kCIInputImageKey)
|
||||||
|
filter?.setValue(5.0, forKey: kCIInputBrightnessKey)
|
||||||
|
filter?.setValue(0.0, forKey: kCIInputSaturationKey)
|
||||||
|
filter?.setValue(1.1, forKey: kCIInputContrastKey)
|
||||||
|
|
||||||
|
guard let intermediateImage = filter?.outputImage else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var sourceBuffer: vImage_Buffer = {
|
|
||||||
guard
|
|
||||||
var sourceImageBuffer = try? vImage_Buffer(cgImage: self,
|
|
||||||
format: format),
|
|
||||||
|
|
||||||
var scaledBuffer = try? vImage_Buffer(width: Int(sourceImageBuffer.height / 3),
|
|
||||||
height: Int(sourceImageBuffer.width / 3),
|
|
||||||
bitsPerPixel: format.bitsPerPixel) else {
|
|
||||||
fatalError("Unable to create source buffers.")
|
|
||||||
}
|
|
||||||
|
|
||||||
defer {
|
|
||||||
sourceImageBuffer.free()
|
|
||||||
}
|
|
||||||
|
|
||||||
vImageScale_ARGB8888(&sourceImageBuffer,
|
|
||||||
&scaledBuffer,
|
|
||||||
nil,
|
|
||||||
vImage_Flags(kvImageNoFlags))
|
|
||||||
|
|
||||||
return scaledBuffer
|
|
||||||
}()
|
|
||||||
|
|
||||||
guard var destinationBuffer = try? vImage_Buffer(width: Int(sourceBuffer.width),
|
guard let image = CIContext().createCGImage(intermediateImage, from: CGRect(origin: .zero, size: CGSize(width: self.width, height: self.height))) else {
|
||||||
height: Int(sourceBuffer.height),
|
return nil
|
||||||
bitsPerPixel: 8) else {
|
|
||||||
fatalError("Unable to create destination buffers.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let redCoefficient: Float = 0.2126
|
let grayColorSpace = CGColorSpaceCreateDeviceGray()
|
||||||
let greenCoefficient: Float = 0.7152
|
let maskBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue).union(.byteOrder16Big)
|
||||||
let blueCoefficient: Float = 0.0722
|
|
||||||
|
|
||||||
let divisor: Int32 = 0x1000
|
let maskContext = CGContext(data: nil, width: self.width, height: self.height, bitsPerComponent: 16, bytesPerRow: 0, space: grayColorSpace, bitmapInfo: maskBitmapInfo.rawValue)
|
||||||
let fDivisor = Float(divisor)
|
|
||||||
|
|
||||||
var coefficientsMatrix = [
|
|
||||||
Int16(redCoefficient * fDivisor),
|
|
||||||
Int16(greenCoefficient * fDivisor),
|
|
||||||
Int16(blueCoefficient * fDivisor)
|
|
||||||
]
|
|
||||||
|
|
||||||
// Use the matrix of coefficients to compute the scalar luminance by
|
maskContext?.setFillColor(.black)
|
||||||
// returning the dot product of each RGB pixel and the coefficients
|
maskContext?.fill(CGRect(origin: .zero, size: CGSize(width: self.width, height: self.height)))
|
||||||
// matrix.
|
|
||||||
let preBias: [Int16] = [0, 0, 0, 0]
|
|
||||||
let postBias: Int32 = 0
|
|
||||||
|
|
||||||
vImageMatrixMultiply_ARGB8888ToPlanar8(&sourceBuffer,
|
maskContext?.draw(image, in: CGRect(origin: .zero, size: CGSize(width: self.width, height: self.height)))
|
||||||
&destinationBuffer,
|
|
||||||
&coefficientsMatrix,
|
|
||||||
divisor,
|
|
||||||
preBias,
|
|
||||||
postBias,
|
|
||||||
vImage_Flags(kvImageNoFlags))
|
|
||||||
|
|
||||||
// Create a 1-channel, 8-bit grayscale format that's used to
|
return maskContext?.makeImage()
|
||||||
// generate a displayable image.
|
|
||||||
let monoFormat = vImage_CGImageFormat(
|
|
||||||
bitsPerComponent: 8,
|
|
||||||
bitsPerPixel: 8,
|
|
||||||
colorSpace: CGColorSpaceCreateDeviceGray(),
|
|
||||||
bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue),
|
|
||||||
renderingIntent: .defaultIntent)!
|
|
||||||
|
|
||||||
// Create a Core Graphics image from the grayscale destination buffer.
|
|
||||||
return try? destinationBuffer.createCGImage(format: monoFormat)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue