Skip to content

Instantly share code, notes, and snippets.

@mackoj
Created June 8, 2022 17:58
Show Gist options
  • Save mackoj/3c89ef2c15be92f4936bb8b36f3c113f to your computer and use it in GitHub Desktop.
Save mackoj/3c89ef2c15be92f4936bb8b36f3c113f to your computer and use it in GitHub Desktop.
Codable implémentation for Color, CGColor that respect ColorSpace
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