// // ImageAsset.swift // lottie-swift // // Created by Brandon Withrow on 1/9/19. // import Foundation // MARK: - ImageAsset public final class ImageAsset: Asset { // MARK: Lifecycle required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: ImageAsset.CodingKeys.self) name = try container.decode(String.self, forKey: .name) directory = try container.decode(String.self, forKey: .directory) width = try container.decode(Double.self, forKey: .width) height = try container.decode(Double.self, forKey: .height) try super.init(from: decoder) } required init(dictionary: [String: Any]) throws { name = try dictionary.value(for: CodingKeys.name) directory = try dictionary.value(for: CodingKeys.directory) width = try dictionary.value(for: CodingKeys.width) height = try dictionary.value(for: CodingKeys.height) try super.init(dictionary: dictionary) } // MARK: Public /// Image name public let name: String /// Image Directory public let directory: String /// Image Size public let width: Double public let height: Double override public func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(name, forKey: .name) try container.encode(directory, forKey: .directory) try container.encode(width, forKey: .width) try container.encode(height, forKey: .height) } // MARK: Internal enum CodingKeys: String, CodingKey { case name = "p" case directory = "u" case width = "w" case height = "h" } } extension Data { // MARK: Lifecycle /// Initializes `Data` from an `ImageAsset`. /// /// Returns nil when the input is not recognized as valid Data URL. /// - parameter imageAsset: The image asset that contains Data URL. internal init?(imageAsset: ImageAsset) { self.init(dataString: imageAsset.name) } /// Initializes `Data` from a [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) String. /// /// Returns nil when the input is not recognized as valid Data URL. /// - parameter dataString: The data string to parse. /// - parameter options: Options for the string parsing. Default value is `[]`. internal init?(dataString: String, options: DataURLReadOptions = []) { guard dataString.hasPrefix("data:"), let url = URL(string: dataString) else { return nil } // The code below is needed because Data(contentsOf:) floods logs // with messages since url doesn't have a host. This only fixes flooding logs // when data inside Data URL is base64 encoded. if let base64Range = dataString.range(of: ";base64,"), !options.contains(DataURLReadOptions.legacy) { let encodedString = String(dataString[base64Range.upperBound...]) self.init(base64Encoded: encodedString) } else { try? self.init(contentsOf: url) } } // MARK: Internal internal struct DataURLReadOptions: OptionSet { let rawValue: Int /// Will read Data URL using Data(contentsOf:) static let legacy = DataURLReadOptions(rawValue: 1 << 0) } }