Created
June 8, 2022 17:58
-
-
Save mackoj/3c89ef2c15be92f4936bb8b36f3c113f to your computer and use it in GitHub Desktop.
Codable implémentation for Color, CGColor that respect ColorSpace
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import CoreFoundation | |
import CoreGraphics | |
import Foundation | |
import SwiftUI | |
public let defaultBadColor = Color.green | |
public let defaultGoodColor = Color.red | |
public struct SerializableCGColorError: Error, LocalizedError { | |
let error: String | |
public var errorDescription: String? { error } | |
} | |
public struct SerializableCGColor: Codable { | |
var components: [CGFloat] | |
var colorSpace: Data | |
var cgColor: CGColor? { | |
let out = CFPropertyListCreateWithData( | |
kCFAllocatorDefault, | |
colorSpace as? CFData, | |
CFPropertyListMutabilityOptions.mutableContainers.rawValue, | |
nil, | |
nil | |
).takeRetainedValue() | |
guard let colorSpace = CGColorSpace(propertyListPlist: out) else { return nil } | |
return CGColor( | |
colorSpace: colorSpace, | |
components: components | |
) | |
} | |
} | |
extension CGColor { | |
var serialized: SerializableCGColor? { | |
guard | |
let components = self.components, | |
let colorSpaceProperties = self.colorSpace?.copyPropertyList() | |
else { return nil } | |
let out = CFPropertyListCreateData( | |
kCFAllocatorDefault, | |
colorSpaceProperties, | |
.binaryFormat_v1_0, | |
0, | |
nil | |
).takeRetainedValue() | |
guard let data = out as? Data else { return nil } | |
return SerializableCGColor( | |
components: components, | |
colorSpace: data | |
) | |
} | |
public func encodeToString() throws -> String { | |
guard let serialized = self.serialized else { throw(SerializableCGColorError(error: "Fail to encode CGColor")) } | |
let data = try JSONEncoder().encode(serialized) | |
return data.base64EncodedString() | |
} | |
static public func loadFromString(_ input: String) throws -> CGColor { | |
guard let data = Data(base64Encoded: input) else { throw(SerializableCGColorError(error: "Fail to decode data")) } | |
let output = try JSONDecoder().decode(SerializableCGColor.self, from: data) | |
if let cg = output.cgColor { return cg } | |
throw(SerializableCGColorError(error: "Fail to decode CGColor")) | |
} | |
} | |
extension Color { | |
public func encodeToString() -> String { | |
let color = try? UIColor(self).cgColor.save() | |
return color ?? defaultBadColor | |
} | |
static public func loadFromString(_ input: String) -> Color { | |
do { | |
let color = Color(cgColor: try CGColor.load(input)) | |
return color | |
} catch { | |
#if DEBUG | |
fatalError(error.localizedDescription) | |
#else | |
dump(error) | |
return defaultBadColor | |
#endif | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment