Overhaul blend mode handling
Now we decode a much nicer enum, instead of manually parsing ints on both the PSD and rendering side
This commit is contained in:
parent
590c16da52
commit
981604d68d
2 changed files with 140 additions and 158 deletions
|
@ -47,91 +47,62 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPSDBlendMode(_ layer : SilicaLayer) -> PSDBlendModes {
|
func getPSDBlendMode(_ layer : SilicaLayer) -> PSDBlendModes {
|
||||||
if layer.data.blendMode == 1 {
|
switch(layer.data.blendMode) {
|
||||||
|
case .Normal:
|
||||||
|
return kPSDBlendModeNormal
|
||||||
|
case .Multiply:
|
||||||
return kPSDBlendModeMultiply
|
return kPSDBlendModeMultiply
|
||||||
}
|
case .Screen:
|
||||||
if layer.data.blendMode == 10 {
|
|
||||||
return kPSDBlendModeColorBurn
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 19 {
|
|
||||||
return kPSDBlendModeDarken
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 8 {
|
|
||||||
return kPSDBlendModeLinearBurn
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 4 {
|
|
||||||
return kPSDBlendModeLighten
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 2 {
|
|
||||||
return kPSDBlendModeScreen
|
return kPSDBlendModeScreen
|
||||||
}
|
case .Add:
|
||||||
if layer.data.blendMode == 13 {
|
|
||||||
return kPSDBlendModeColor
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 9 {
|
|
||||||
return kPSDBlendModeColorDodge
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 3 {
|
|
||||||
return kPSDBlendModeAdd
|
return kPSDBlendModeAdd
|
||||||
}
|
case .Lighten:
|
||||||
if layer.data.blendMode == 0 && layer.data.blendMode != layer.data.extendedBlend {
|
return kPSDBlendModeLighten
|
||||||
if layer.data.extendedBlend == 25 {
|
case .Exclusion:
|
||||||
return kPSDBlendModeDarkerColor
|
return kPSDBlendModeExclusion
|
||||||
}
|
case .Difference:
|
||||||
if layer.data.extendedBlend == 24 {
|
return kPSDBlendModeDifference
|
||||||
return kPSDBlendModeLighterColor
|
case .Subtract:
|
||||||
}
|
return kPSDBlendModeSubtract
|
||||||
if layer.data.extendedBlend == 21 {
|
case .LinearBurn:
|
||||||
return kPSDBlendModeVividLight
|
return kPSDBlendModeLinearBurn
|
||||||
}
|
case .ColorDodge:
|
||||||
if layer.data.extendedBlend == 22 {
|
return kPSDBlendModeColorDodge
|
||||||
return kPSdBlendModeLinearLight
|
case .ColorBurn:
|
||||||
}
|
return kPSDBlendModeColorBurn
|
||||||
if layer.data.extendedBlend == 23 {
|
case .Overlay:
|
||||||
return kPSDBlendModePinLight
|
return kPSDBlendModeOverlay
|
||||||
}
|
case .HardLight:
|
||||||
if layer.data.extendedBlend == 20 {
|
return kPSDBlendModeHardLight
|
||||||
|
case .Color:
|
||||||
|
return kPSDBlendModeColor
|
||||||
|
case .Luminosity:
|
||||||
|
return kPSDBlendModeLuminosity
|
||||||
|
case .Hue:
|
||||||
|
return kPSDBlendModeHue
|
||||||
|
case .Saturation:
|
||||||
|
return kPSDBlendModeSaturation
|
||||||
|
case .SoftLight:
|
||||||
|
return kPSDBlendSoftLight
|
||||||
|
case .Darken:
|
||||||
|
return kPSDBlendModeDarken
|
||||||
|
case .HardMix:
|
||||||
return kPSDBlendModeHardMix
|
return kPSDBlendModeHardMix
|
||||||
}
|
case .VividLight:
|
||||||
if layer.data.extendedBlend == 26 {
|
return kPSDBlendModeVividLight
|
||||||
|
case .LinearLight:
|
||||||
|
return kPSdBlendModeLinearLight
|
||||||
|
case .PinLight:
|
||||||
|
return kPSDBlendModePinLight
|
||||||
|
case .LighterColor:
|
||||||
|
return kPSDBlendModeLighterColor
|
||||||
|
case .DarkerColor:
|
||||||
|
return kPSDBlendModeDarkerColor
|
||||||
|
case .Divide:
|
||||||
return kPSDBlendModeDivide
|
return kPSDBlendModeDivide
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if layer.data.blendMode == 11 {
|
|
||||||
return kPSDBlendModeOverlay
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 17 {
|
|
||||||
return kPSDBlendSoftLight
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 12 {
|
|
||||||
return kPSDBlendModeHardLight
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 6 {
|
|
||||||
return kPSDBlendModeDifference
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 5 {
|
|
||||||
return kPSDBlendModeExclusion
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 7 {
|
|
||||||
return kPSDBlendModeSubtract
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 15 {
|
|
||||||
return kPSDBlendModeHue
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 16 {
|
|
||||||
return kPSDBlendModeSaturation
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 13 {
|
|
||||||
return kPSDBlendModeColor
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 14 {
|
|
||||||
return kPSDBlendModeLuminosity
|
|
||||||
}
|
|
||||||
|
|
||||||
return kPSDBlendModeNormal
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBAction func exportAction(_ sender: Any) {
|
@IBAction func exportAction(_ sender: Any) {
|
||||||
let document = NSApplication.shared.keyWindow?.windowController?.document as? Document;
|
let document = NSApplication.shared.keyWindow?.windowController?.document as? Document;
|
||||||
|
|
||||||
|
@ -178,9 +149,11 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations {
|
||||||
|
|
||||||
if(layer.mask != nil) {
|
if(layer.mask != nil) {
|
||||||
writer?.addLayer(with: document!.makeBlendImage(layer), andName: layer.name + " (Mask)", andOpacity: 1.0, andOffset: .zero)
|
writer?.addLayer(with: document!.makeBlendImage(layer), andName: layer.name + " (Mask)", andOpacity: 1.0, andOffset: .zero)
|
||||||
}
|
|
||||||
|
|
||||||
writer?.addLayer(with: finalCgImage, andName: layer.name, andOpacity: Float(layer.data.opacity), andOffset: .zero, andBlendMode: Int(self.getPSDBlendMode(layer).rawValue), andIsNonBaseLayer: layer.clipped)
|
writer?.addLayer(with: finalCgImage, andName: layer.name, andOpacity: Float(layer.data.opacity), andOffset: .zero, andBlendMode: Int(self.getPSDBlendMode(layer).rawValue), andIsNonBaseLayer: layer.clipped, andMaskLayerName: layer.name + " (Mask)")
|
||||||
|
} else {
|
||||||
|
writer?.addLayer(with: finalCgImage, andName: layer.name, andOpacity: Float(layer.data.opacity), andOffset: .zero, andBlendMode: Int(self.getPSDBlendMode(layer).rawValue), andIsNonBaseLayer: layer.clipped, andMaskLayerName: nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = writer?.createPSDData()
|
let data = writer?.createPSDData()
|
||||||
|
|
|
@ -10,9 +10,41 @@ struct SilicaChunk {
|
||||||
var image: CGImage?
|
var image: CGImage?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all supported Procreate blend modes
|
||||||
|
enum BlendMode : Int {
|
||||||
|
case Normal = 0,
|
||||||
|
Multiply = 1,
|
||||||
|
Screen = 2,
|
||||||
|
Add = 3,
|
||||||
|
Lighten = 4,
|
||||||
|
Exclusion = 5,
|
||||||
|
Difference = 6,
|
||||||
|
Subtract = 7,
|
||||||
|
LinearBurn = 8,
|
||||||
|
ColorDodge = 9,
|
||||||
|
ColorBurn = 10,
|
||||||
|
Overlay = 11,
|
||||||
|
HardLight = 12,
|
||||||
|
Color = 13,
|
||||||
|
Luminosity = 14,
|
||||||
|
Hue = 15,
|
||||||
|
Saturation = 16,
|
||||||
|
SoftLight = 17,
|
||||||
|
// what is this mysterious 18?
|
||||||
|
Darken = 19,
|
||||||
|
|
||||||
|
// extended modes
|
||||||
|
HardMix = 20,
|
||||||
|
VividLight = 21,
|
||||||
|
LinearLight = 22,
|
||||||
|
PinLight = 23,
|
||||||
|
LighterColor = 24,
|
||||||
|
DarkerColor = 25,
|
||||||
|
Divide = 26
|
||||||
|
}
|
||||||
|
|
||||||
struct SilicaLayerData {
|
struct SilicaLayerData {
|
||||||
var blendMode: Int = 0
|
var blendMode: BlendMode = .Normal
|
||||||
var extendedBlend: Int = 0
|
|
||||||
var chunks: [SilicaChunk] = []
|
var chunks: [SilicaChunk] = []
|
||||||
var opacity: Double = 1.0
|
var opacity: Double = 1.0
|
||||||
var hidden: Bool = false
|
var hidden: Bool = false
|
||||||
|
@ -193,94 +225,71 @@ class Document: NSDocument {
|
||||||
return NSRect(x: info.tileSize * x, y: info.height - (info.tileSize * y), width: width, height: height)
|
return NSRect(x: info.tileSize * x, y: info.height - (info.tileSize * y), width: width, height: height)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: convert to switch/case
|
func parseRawBlendMode(blendMode: Int, extendedBlend: Int) -> BlendMode? {
|
||||||
func getBlendKernel(_ layer: SilicaLayer) -> CIBlendKernel? {
|
if blendMode == 0 && blendMode != extendedBlend {
|
||||||
if layer.data.blendMode == 1 {
|
return BlendMode(rawValue: extendedBlend)
|
||||||
return .multiply
|
} else {
|
||||||
|
return BlendMode(rawValue: blendMode)
|
||||||
}
|
}
|
||||||
if layer.data.blendMode == 10 {
|
|
||||||
return .colorBurn
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 19 {
|
|
||||||
return .darken
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 8 {
|
|
||||||
return .linearBurn
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 4 {
|
|
||||||
return .lighten
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 2 {
|
|
||||||
return .screen
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 13 {
|
|
||||||
return .color
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 9 {
|
|
||||||
return .colorDodge
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 3 {
|
|
||||||
return .componentAdd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if layer.data.blendMode == 0 && layer.data.blendMode != layer.data.extendedBlend {
|
func getBlendKernel(_ layer: SilicaLayer) -> CIBlendKernel? {
|
||||||
if layer.data.extendedBlend == 25 {
|
switch(layer.data.blendMode) {
|
||||||
return .darkerColor
|
case .Normal:
|
||||||
}
|
return .sourceOver
|
||||||
if layer.data.extendedBlend == 24 {
|
case .Multiply:
|
||||||
return .lighterColor
|
return .multiply
|
||||||
}
|
case .Screen:
|
||||||
if layer.data.extendedBlend == 21 {
|
return .screen
|
||||||
return .vividLight
|
case .Add:
|
||||||
}
|
return .componentAdd
|
||||||
if layer.data.extendedBlend == 22 {
|
case .Lighten:
|
||||||
return .linearLight
|
return .lighten
|
||||||
}
|
case .Exclusion:
|
||||||
if layer.data.extendedBlend == 23 {
|
return .exclusion
|
||||||
return .pinLight
|
case .Difference:
|
||||||
}
|
return .difference
|
||||||
if layer.data.extendedBlend == 20 {
|
case .Subtract:
|
||||||
|
return .subtract
|
||||||
|
case .LinearBurn:
|
||||||
|
return .linearBurn
|
||||||
|
case .ColorDodge:
|
||||||
|
return .colorDodge
|
||||||
|
case .ColorBurn:
|
||||||
|
return .colorBurn
|
||||||
|
case .Overlay:
|
||||||
|
return .overlay
|
||||||
|
case .HardLight:
|
||||||
|
return .hardLight
|
||||||
|
case .Color:
|
||||||
|
return .color
|
||||||
|
case .Luminosity:
|
||||||
|
return .luminosity
|
||||||
|
case .Hue:
|
||||||
|
return .hue
|
||||||
|
case .Saturation:
|
||||||
|
return .saturation
|
||||||
|
case .SoftLight:
|
||||||
|
return .softLight
|
||||||
|
case .Darken:
|
||||||
|
return .darken
|
||||||
|
case .HardMix:
|
||||||
return .hardMix
|
return .hardMix
|
||||||
}
|
case .VividLight:
|
||||||
if layer.data.extendedBlend == 26 {
|
return .vividLight
|
||||||
|
case .LinearLight:
|
||||||
|
return .linearLight
|
||||||
|
case .PinLight:
|
||||||
|
return .pinLight
|
||||||
|
case .LighterColor:
|
||||||
|
return .lighterColor
|
||||||
|
case .DarkerColor:
|
||||||
|
return .darkerColor
|
||||||
|
case .Divide:
|
||||||
return .divide
|
return .divide
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if layer.data.blendMode == 11 {
|
|
||||||
return .overlay
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 17 {
|
|
||||||
return .softLight
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 12 {
|
|
||||||
return .hardLight
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 6 {
|
|
||||||
return .difference
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 5 {
|
|
||||||
return .exclusion
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 7 {
|
|
||||||
return .subtract
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 15 {
|
|
||||||
return .hue
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 16 {
|
|
||||||
return .saturation
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 13 {
|
|
||||||
return .color
|
|
||||||
}
|
|
||||||
if layer.data.blendMode == 14 {
|
|
||||||
return .luminosity
|
|
||||||
}
|
|
||||||
|
|
||||||
return .sourceOver
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseSilicaLayer(archive: Archive, dict: NSDictionary, isMask: Bool) -> SilicaLayer? {
|
func parseSilicaLayer(archive: Archive, dict: NSDictionary, isMask: Bool) -> SilicaLayer? {
|
||||||
let objectsArray = self.dict?["$objects"] as! NSArray
|
let objectsArray = self.dict?["$objects"] as! NSArray
|
||||||
|
|
||||||
|
@ -302,8 +311,8 @@ class Document: NSDocument {
|
||||||
let maskClassID = getClassID(id: maskKey)
|
let maskClassID = getClassID(id: maskKey)
|
||||||
let maskClass = objectsArray[maskClassID]
|
let maskClass = objectsArray[maskClassID]
|
||||||
|
|
||||||
layer.data.blendMode = (dict["blend"] as? NSNumber)!.intValue
|
layer.data.blendMode = parseRawBlendMode(blendMode: (dict["blend"] as? NSNumber)!.intValue, extendedBlend: (dict["extendedBlend"] as? NSNumber)!.intValue)!
|
||||||
layer.data.extendedBlend = (dict["extendedBlend"] as? NSNumber)!.intValue
|
|
||||||
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)!
|
||||||
|
|
Reference in a new issue