1
Fork 0

Create toGrayscale function

This commit is contained in:
Joshua Goins 2021-09-21 04:41:05 -04:00
parent 00b655f519
commit 6ad06a1360

View file

@ -143,9 +143,7 @@ class Document: NSDocument {
layer.data.opacity = (dict["opacity"] as? NSNumber)!.doubleValue layer.data.opacity = (dict["opacity"] as? NSNumber)!.doubleValue
layer.data.hidden = (dict["hidden"] as? Bool)! layer.data.hidden = (dict["hidden"] as? Bool)!
layer.clipped = (dict["clipped"] as? Bool)! layer.clipped = (dict["clipped"] as? Bool)!
dump(dict, indent: 2)
if maskClassID != 0 { if maskClassID != 0 {
layer.mask = parseSilicaLayer(archive: archive, dict: maskClass as! NSDictionary, isMask: true)?.data layer.mask = parseSilicaLayer(archive: archive, dict: maskClass as! NSDictionary, isMask: true)?.data
} }
@ -343,7 +341,7 @@ class Document: NSDocument {
parseDocument(archive: archive, dict: propertyList as! NSDictionary) parseDocument(archive: archive, dict: propertyList as! NSDictionary)
} }
func makeComposite() -> NSImage { func makeComposite() -> NSImage? {
// create the final composite output image // create the final composite output image
let rgbColorSpace = CGColorSpaceCreateDeviceRGB() let rgbColorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue).union(.byteOrder32Big) let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue).union(.byteOrder32Big)
@ -355,9 +353,7 @@ class Document: NSDocument {
var previousImage: CGImage? var previousImage: CGImage?
for (index, layer) in info.layers.reversed().enumerated() { for layer in info.layers.reversed() {
dump(layer, indent: 5)
// start by creating a new layer composite image, needed for image masking // start by creating a new layer composite image, needed for image masking
let layerContext = CGContext(data: nil, width: info.width, height: info.height, bitsPerComponent: 8, bytesPerRow: info.width * 4, space: rgbColorSpace, bitmapInfo: bitmapInfo.rawValue) let layerContext = CGContext(data: nil, width: info.width, height: info.height, bitsPerComponent: 8, bytesPerRow: info.width * 4, space: rgbColorSpace, bitmapInfo: bitmapInfo.rawValue)
@ -419,95 +415,12 @@ class Document: NSDocument {
ccgContext?.setBlendMode(.sourceAtop) ccgContext?.setBlendMode(.sourceAtop)
if layer.clipped { if layer.clipped {
let previousLayer = info.layers.reversed()[index - 1] guard let result = previousImage?.toGrayscale() else {
return nil
var format: vImage_CGImageFormat = { }
guard
let format = vImage_CGImageFormat(cgImage: previousImage!) else {
fatalError("Unable to create format.")
}
return format
}()
var sourceBuffer: vImage_Buffer = {
guard
var sourceImageBuffer = try? vImage_Buffer(cgImage: previousImage!,
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
}()
/*
The 1-channel, 8-bit vImage buffer used as the operation destination.
*/
var destinationBuffer: vImage_Buffer = {
guard var destinationBuffer = try? vImage_Buffer(width: Int(sourceBuffer.width),
height: Int(sourceBuffer.height),
bitsPerPixel: 8) else {
fatalError("Unable to create destination buffers.")
}
return destinationBuffer
}()
let redCoefficient: Float = 0.2126
let greenCoefficient: Float = 0.7152
let blueCoefficient: Float = 0.0722
let divisor: Int32 = 0x1000
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
// returning the dot product of each RGB pixel and the coefficients
// matrix.
let preBias: [Int16] = [0, 0, 0, 0]
let postBias: Int32 = 0
vImageMatrixMultiply_ARGB8888ToPlanar8(&sourceBuffer,
&destinationBuffer,
&coefficientsMatrix,
divisor,
preBias,
postBias,
vImage_Flags(kvImageNoFlags))
// 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.
let result = (try? destinationBuffer.createCGImage(format: monoFormat))!
let newImage = layerImage.masking(result)! let newImage = layerImage.masking(result)!
previousImage = newImage previousImage = newImage
ccgContext?.draw(newImage, in: CGRect(x: 0, y: 0, width: info.width, height: info.height)) ccgContext?.draw(newImage, in: CGRect(x: 0, y: 0, width: info.width, height: info.height))
@ -628,3 +541,79 @@ public extension NSImage {
return flipedImage return flipedImage
} }
} }
public extension CGImage {
func toGrayscale() -> CGImage? {
guard let format = vImage_CGImageFormat(cgImage: self) 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.")
}
let redCoefficient: Float = 0.2126
let greenCoefficient: Float = 0.7152
let blueCoefficient: Float = 0.0722
let divisor: Int32 = 0x1000
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
// returning the dot product of each RGB pixel and the coefficients
// matrix.
let preBias: [Int16] = [0, 0, 0, 0]
let postBias: Int32 = 0
vImageMatrixMultiply_ARGB8888ToPlanar8(&sourceBuffer,
&destinationBuffer,
&coefficientsMatrix,
divisor,
preBias,
postBias,
vImage_Flags(kvImageNoFlags))
// 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)
}
}