1
Fork 0

Fix clipping masks

This commit is contained in:
Joshua Goins 2021-09-27 12:23:18 -04:00
parent 7e1ddaf2bf
commit 3c7c1f865a

View file

@ -494,7 +494,7 @@ class Document: NSDocument {
var masterImage = ccgContext?.makeImage()
let context = CIContext()
var previousImage: CGImage?
var previousImage: CGImage? = masterImage
for layer in info.layers.reversed() {
// 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 {
guard let result = previousImage?.toGrayscale() else {
return nil
}
let newImage = layerImage.masking(result)!
if layer.clipped && previousImage != nil {
let result = previousImage!.toGrayscale()
let newImage = layerImage!.masking(result!)
previousImage = newImage
} else if layer.mask != nil {
let maskImage = (maskContext?.makeImage())!
let newImage = layerImage.masking(maskImage)!
let newImage = layerImage!.masking(maskImage)!
previousImage = newImage
} else {
previousImage = layerImage
}
// apply image
let ciImage = CIImage(cgImage: (masterImage)!)
let newCiImage = kernel!.apply(foreground: CIImage(cgImage: previousImage!), background: ciImage, colorSpace: info.colorSpace)
@ -660,76 +657,32 @@ public extension NSImage {
public extension 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
}
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),
height: Int(sourceBuffer.height),
bitsPerPixel: 8) else {
fatalError("Unable to create destination buffers.")
guard let image = CIContext().createCGImage(intermediateImage, from: CGRect(origin: .zero, size: CGSize(width: self.width, height: self.height))) else {
return nil
}
let redCoefficient: Float = 0.2126
let greenCoefficient: Float = 0.7152
let blueCoefficient: Float = 0.0722
let grayColorSpace = CGColorSpaceCreateDeviceGray()
let maskBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue).union(.byteOrder16Big)
let divisor: Int32 = 0x1000
let fDivisor = Float(divisor)
var coefficientsMatrix = [
Int16(redCoefficient * fDivisor),
Int16(greenCoefficient * fDivisor),
Int16(blueCoefficient * fDivisor)
]
let maskContext = CGContext(data: nil, width: self.width, height: self.height, bitsPerComponent: 16, bytesPerRow: 0, space: grayColorSpace, bitmapInfo: maskBitmapInfo.rawValue)
// Use the matrix of coefficients to compute the scalar luminance by
// returning the dot product of each RGB pixel and the coefficients
// matrix.
let preBias: [Int16] = [0, 0, 0, 0]
let postBias: Int32 = 0
maskContext?.setFillColor(.black)
maskContext?.fill(CGRect(origin: .zero, size: CGSize(width: self.width, height: self.height)))
vImageMatrixMultiply_ARGB8888ToPlanar8(&sourceBuffer,
&destinationBuffer,
&coefficientsMatrix,
divisor,
preBias,
postBias,
vImage_Flags(kvImageNoFlags))
maskContext?.draw(image, in: CGRect(origin: .zero, size: CGSize(width: self.width, height: self.height)))
// Create a 1-channel, 8-bit grayscale format that's used to
// 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)
return maskContext?.makeImage()
}
}