1
Fork 0

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:
Joshua Goins 2022-06-14 11:17:58 -04:00
parent 590c16da52
commit 981604d68d
2 changed files with 140 additions and 158 deletions

View file

@ -47,89 +47,60 @@ 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
}
if layer.data.extendedBlend == 24 {
return kPSDBlendModeLighterColor
}
if layer.data.extendedBlend == 21 {
return kPSDBlendModeVividLight
}
if layer.data.extendedBlend == 22 {
return kPSdBlendModeLinearLight
}
if layer.data.extendedBlend == 23 {
return kPSDBlendModePinLight
}
if layer.data.extendedBlend == 20 {
return kPSDBlendModeHardMix
}
if layer.data.extendedBlend == 26 {
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 return kPSDBlendModeExclusion
} case .Difference:
if layer.data.blendMode == 7 { return kPSDBlendModeDifference
case .Subtract:
return kPSDBlendModeSubtract return kPSDBlendModeSubtract
} case .LinearBurn:
if layer.data.blendMode == 15 { return kPSDBlendModeLinearBurn
return kPSDBlendModeHue case .ColorDodge:
} return kPSDBlendModeColorDodge
if layer.data.blendMode == 16 { case .ColorBurn:
return kPSDBlendModeSaturation return kPSDBlendModeColorBurn
} case .Overlay:
if layer.data.blendMode == 13 { return kPSDBlendModeOverlay
case .HardLight:
return kPSDBlendModeHardLight
case .Color:
return kPSDBlendModeColor return kPSDBlendModeColor
} case .Luminosity:
if layer.data.blendMode == 14 {
return kPSDBlendModeLuminosity return kPSDBlendModeLuminosity
case .Hue:
return kPSDBlendModeHue
case .Saturation:
return kPSDBlendModeSaturation
case .SoftLight:
return kPSDBlendSoftLight
case .Darken:
return kPSDBlendModeDarken
case .HardMix:
return kPSDBlendModeHardMix
case .VividLight:
return kPSDBlendModeVividLight
case .LinearLight:
return kPSdBlendModeLinearLight
case .PinLight:
return kPSDBlendModePinLight
case .LighterColor:
return kPSDBlendModeLighterColor
case .DarkerColor:
return kPSDBlendModeDarkerColor
case .Divide:
return kPSDBlendModeDivide
} }
return kPSDBlendModeNormal
} }
@IBAction func exportAction(_ sender: Any) { @IBAction func exportAction(_ sender: Any) {
@ -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, 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)
} }
writer?.addLayer(with: finalCgImage, andName: layer.name, andOpacity: Float(layer.data.opacity), andOffset: .zero, andBlendMode: Int(self.getPSDBlendMode(layer).rawValue), andIsNonBaseLayer: layer.clipped)
} }
let data = writer?.createPSDData() let data = writer?.createPSDData()

View file

@ -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,92 +225,69 @@ 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? {
if blendMode == 0 && blendMode != extendedBlend {
return BlendMode(rawValue: extendedBlend)
} else {
return BlendMode(rawValue: blendMode)
}
}
func getBlendKernel(_ layer: SilicaLayer) -> CIBlendKernel? { func getBlendKernel(_ layer: SilicaLayer) -> CIBlendKernel? {
if layer.data.blendMode == 1 { switch(layer.data.blendMode) {
case .Normal:
return .sourceOver
case .Multiply:
return .multiply return .multiply
} case .Screen:
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 return .screen
} case .Add:
if layer.data.blendMode == 13 {
return .color
}
if layer.data.blendMode == 9 {
return .colorDodge
}
if layer.data.blendMode == 3 {
return .componentAdd return .componentAdd
} case .Lighten:
return .lighten
if layer.data.blendMode == 0 && layer.data.blendMode != layer.data.extendedBlend { case .Exclusion:
if layer.data.extendedBlend == 25 {
return .darkerColor
}
if layer.data.extendedBlend == 24 {
return .lighterColor
}
if layer.data.extendedBlend == 21 {
return .vividLight
}
if layer.data.extendedBlend == 22 {
return .linearLight
}
if layer.data.extendedBlend == 23 {
return .pinLight
}
if layer.data.extendedBlend == 20 {
return .hardMix
}
if layer.data.extendedBlend == 26 {
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 return .exclusion
} case .Difference:
if layer.data.blendMode == 7 { return .difference
case .Subtract:
return .subtract return .subtract
} case .LinearBurn:
if layer.data.blendMode == 15 { return .linearBurn
return .hue case .ColorDodge:
} return .colorDodge
if layer.data.blendMode == 16 { case .ColorBurn:
return .saturation return .colorBurn
} case .Overlay:
if layer.data.blendMode == 13 { return .overlay
case .HardLight:
return .hardLight
case .Color:
return .color return .color
} case .Luminosity:
if layer.data.blendMode == 14 {
return .luminosity return .luminosity
case .Hue:
return .hue
case .Saturation:
return .saturation
case .SoftLight:
return .softLight
case .Darken:
return .darken
case .HardMix:
return .hardMix
case .VividLight:
return .vividLight
case .LinearLight:
return .linearLight
case .PinLight:
return .pinLight
case .LighterColor:
return .lighterColor
case .DarkerColor:
return .darkerColor
case .Divide:
return .divide
} }
return .sourceOver
} }
func parseSilicaLayer(archive: Archive, dict: NSDictionary, isMask: Bool) -> SilicaLayer? { func parseSilicaLayer(archive: Archive, dict: NSDictionary, isMask: Bool) -> SilicaLayer? {
@ -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)!