1
Fork 0

Prevent a bunch of unnecessary CG->NS<-CI image conversions

This commit is contained in:
Joshua Goins 2021-09-29 13:02:32 -04:00
parent 3c7c1f865a
commit 8a83dbc25b

View file

@ -6,7 +6,7 @@ import Accelerate
struct SilicaChunk { struct SilicaChunk {
var x: Int = 0 var x: Int = 0
var y: Int = 0 var y: Int = 0
var image: NSImage = NSImage() var image: CGImage?
} }
struct SilicaLayerData { struct SilicaLayerData {
@ -103,7 +103,7 @@ class Document: NSDocument {
/* /*
Returns the correct tile size, taking into account the remainder between tile size and image size. Returns the correct tile size, taking into account the remainder between tile size and image size.
*/ */
func getTileSize(x: Int, y: Int) -> (Int, Int) { func getTileSize(_ x: Int, _ y: Int) -> (Int, Int) {
var width: Int = info.tileSize var width: Int = info.tileSize
var height: Int = info.tileSize var height: Int = info.tileSize
@ -146,7 +146,7 @@ class Document: NSDocument {
let x = chunk.x let x = chunk.x
var y = chunk.y var y = chunk.y
let (width, height) = getTileSize(x: x, y: y) let (width, height) = getTileSize(x, y)
if y == rows { if y == rows {
y = 0 y = 0
@ -240,7 +240,7 @@ class Document: NSDocument {
return .luminosity return .luminosity
} }
return .sourceOver; return .sourceAtop
} }
func parseSilicaLayer(archive: Archive, dict: NSDictionary, isMask: Bool) -> SilicaLayer? { func parseSilicaLayer(archive: Archive, dict: NSDictionary, isMask: Bool) -> SilicaLayer? {
@ -288,7 +288,7 @@ class Document: NSDocument {
let queue = DispatchQueue(label: "imageWork") let queue = DispatchQueue(label: "imageWork")
DispatchQueue.concurrentPerform(iterations: chunkPaths.count) { (i: Int) in DispatchQueue.concurrentPerform(iterations: chunkPaths.count) { (i: Int) in
guard let threadArchive = Archive(data: self.data!, accessMode: Archive.AccessMode.read) else { guard let threadArchive = Archive(data: self.data!, accessMode: .read) else {
return return
} }
@ -298,7 +298,7 @@ class Document: NSDocument {
return return
} }
let (width, height) = getTileSize(x: x, y: y) let (width, height) = getTileSize(x, y)
let numChannels = isMask ? 1 : 4 let numChannels = isMask ? 1 : 4
let byteSize = width * height * numChannels let byteSize = width * height * numChannels
@ -327,10 +327,8 @@ class Document: NSDocument {
return return
} }
let image = NSImage(cgImage: cgimage, size: NSZeroSize)
queue.async(group: dispatchGroup) { queue.async(group: dispatchGroup) {
layer.data.chunks[i].image = image layer.data.chunks[i].image = cgimage
layer.data.chunks[i].x = x layer.data.chunks[i].x = x
layer.data.chunks[i].y = y layer.data.chunks[i].y = y
} }
@ -491,41 +489,44 @@ class Document: NSDocument {
ccgContext?.setFillColor(info.backgroundColor) ccgContext?.setFillColor(info.backgroundColor)
ccgContext?.fill(info.cgRect) ccgContext?.fill(info.cgRect)
var masterImage = ccgContext?.makeImage()
let context = CIContext() let context = CIContext()
var masterImage = CIImage(cgImage: (ccgContext?.makeImage())!)
var previousImage: CGImage? = masterImage var previousImage: CGImage? = nil
for layer in info.layers.reversed() { for layer in info.layers.reversed() {
if !layer.data.hidden {
// 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: info.colorSpace, bitmapInfo: bitmapInfo.rawValue) let layerContext = CGContext(data: nil, width: info.width, height: info.height, bitsPerComponent: 8, bytesPerRow: info.width * 4, space: info.colorSpace, bitmapInfo: bitmapInfo.rawValue)
let graphicsContext = NSGraphicsContext(cgContext: layerContext!, flipped: false) layerContext?.clear(info.cgRect)
var maskContext: CGContext?
let kernel = getBlendKernel(layer)
Swift.print(layer.name + " is " + kernel!.name)
if layer.mask != nil {
let grayColorSpace = CGColorSpaceCreateDeviceGray() let grayColorSpace = CGColorSpaceCreateDeviceGray()
let maskBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue).union(.byteOrder16Big) let maskBitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue).union(.byteOrder16Big)
let maskContext = CGContext(data: nil, width: info.width, height: info.height, bitsPerComponent: 16, bytesPerRow: 0, space: grayColorSpace, bitmapInfo: maskBitmapInfo.rawValue) maskContext = CGContext(data: nil, width: info.width, height: info.height, bitsPerComponent: 16, bytesPerRow: 0, space: grayColorSpace, bitmapInfo: maskBitmapInfo.rawValue)
maskContext?.setFillColor(.white) maskContext?.setFillColor(.white)
maskContext?.fill(info.cgRect) maskContext?.fill(info.cgRect)
let kernel = getBlendKernel(layer)
if layer.mask != nil {
for chunk in layer.mask!.chunks { for chunk in layer.mask!.chunks {
if !layer.data.hidden { maskContext?.draw(chunk.image!, in: getChunkRect(chunk))
maskContext?.draw(chunk.image.cgImage(forProposedRect: nil, context: graphicsContext, hints: nil)!, in: getChunkRect(chunk))
}
} }
} }
for chunk in layer.data.chunks { for chunk in layer.data.chunks {
layerContext?.setAlpha(CGFloat(layer.data.opacity)) layerContext?.setAlpha(CGFloat(layer.data.opacity))
layerContext?.setBlendMode(.copy) layerContext?.setBlendMode(.normal)
if !layer.data.hidden { if !layer.data.hidden {
layerContext?.draw(chunk.image.cgImage(forProposedRect: nil, context: graphicsContext, hints: nil)!, in: getChunkRect(chunk)) layerContext?.draw(chunk.image!, in: getChunkRect(chunk))
} }
} }
@ -536,7 +537,7 @@ class Document: NSDocument {
let newImage = layerImage!.masking(result!) let newImage = layerImage!.masking(result!)
previousImage = newImage previousImage = newImage
} else if layer.mask != nil { } else if layer.mask != nil && maskContext != nil {
let maskImage = (maskContext?.makeImage())! let maskImage = (maskContext?.makeImage())!
let newImage = layerImage!.masking(maskImage)! let newImage = layerImage!.masking(maskImage)!
@ -546,13 +547,12 @@ class Document: NSDocument {
} }
// apply image // apply image
let ciImage = CIImage(cgImage: (masterImage)!) masterImage = kernel!.apply(foreground: CIImage(cgImage: previousImage!), background: masterImage, colorSpace: info.colorSpace)!
let newCiImage = kernel!.apply(foreground: CIImage(cgImage: previousImage!), background: ciImage, colorSpace: info.colorSpace) }
masterImage = context.createCGImage(newCiImage!, from: info.cgRect, format: .RGBA8, colorSpace: info.colorSpace)!
} }
var image = NSImage(cgImage: masterImage!, size: info.nsSize) let cgImage = context.createCGImage(masterImage, from: info.cgRect, format: .RGBA8, colorSpace: info.colorSpace)!
var image = NSImage(cgImage: cgImage, size: info.nsSize)
if info.orientation == 3 { if info.orientation == 3 {
image = image.imageRotatedByDegreess(degrees: 90) image = image.imageRotatedByDegreess(degrees: 90)