Create toGrayscale function
This commit is contained in:
parent
00b655f519
commit
6ad06a1360
1 changed files with 83 additions and 94 deletions
|
@ -144,8 +144,6 @@ class Document: NSDocument {
|
||||||
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,92 +415,9 @@ 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)!
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in a new issue