import CoreGraphics import Foundation import ImageIO import UniformTypeIdentifiers struct FakeArtwork { private let context: CGContext private let space = CGColorSpaceCreateDeviceRGB() private let size: CGFloat private let hue: Double private let spread: Double private var random: SeededGenerator static func png(seed: String, side: Int) -> Data? { guard var artwork = FakeArtwork(seed: seed, side: side) else { return nil } artwork.draw() guard let image = artwork.context.makeImage() else { return nil } let data = NSMutableData() guard let destination = CGImageDestinationCreateWithData(data, UTType.png.identifier as CFString, 1, nil) else { return nil } CGImageDestinationAddImage(destination, image, nil) return CGImageDestinationFinalize(destination) ? data as Data : nil } private init?(seed: String, side: Int) { guard let context = CGContext( data: nil, width: side, height: side, bitsPerComponent: 8, bytesPerRow: 0, space: space, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue ) else { return nil } self.context = context size = CGFloat(side) random = SeededGenerator(seed: seed.utf8.reduce(UInt64(14_695_981_039_346_656_037)) { ($0 ^ UInt64($1)) &* 1_099_511_628_211 }) hue = .random(in: 0 ..< 1, using: &random) spread = .random(in: 0.08 ... 0.45, using: &random) } private mutating func draw() { let isDark = Bool.random(using: &random) let ground = [color(hue, 0.75, isDark ? 0.35 : 0.95), color(hue + spread, 0.8, isDark ? 0.12 : 0.7)] linear(ground, from: CGPoint(x: 0, y: size), to: CGPoint(x: size, y: 0)) switch Int.random(in: 0 ..< 4, using: &random) { case 0: glows() case 1: rings() case 2: sun(horizon: ground[1]) default: blocks() } } private mutating func glows() { for _ in 0 ..< 3 { let center = CGPoint(x: .random(in: 0 ... size, using: &random), y: .random(in: 0 ... size, using: &random)) let tint = color(hue + .random(in: -0.2 ... 0.5, using: &random), 0.7, 1) let radius = size * .random(in: 0.4 ... 0.8, using: &random) guard let clear = tint.copy(alpha: 0), let gradient = CGGradient(colorsSpace: space, colors: [tint, clear] as CFArray, locations: nil) else { continue } context.drawRadialGradient(gradient, startCenter: center, startRadius: 0, endCenter: center, endRadius: radius, options: []) } } private mutating func rings() { let center = CGPoint(x: size * .random(in: 0.3 ... 0.7, using: &random), y: size * .random(in: 0.3 ... 0.7, using: &random)) for ring in (1 ... 7).reversed() { context.setFillColor(color(hue + spread * Double(ring) / 5, 0.65, ring.isMultiple(of: 2) ? 0.95 : 0.25)) let radius = size * 0.09 * CGFloat(ring) context.fillEllipse(in: CGRect(x: center.x - radius, y: center.y - radius, width: radius * 2, height: radius * 2)) } } private func sun(horizon: CGColor) { let radius = size * 0.32 let disc = CGRect(x: size / 2 - radius, y: size * 0.34, width: radius * 2, height: radius * 2) context.saveGState() context.addEllipse(in: disc) context.clip() linear( [color(hue + 0.5, 0.5, 1), color(hue + 0.62, 0.85, 1)], from: CGPoint(x: 0, y: disc.maxY), to: CGPoint(x: 0, y: disc.minY) ) context.restoreGState() context.setFillColor(horizon) for stripe in 0 ..< 5 { let height = size * 0.012 * CGFloat(5 - stripe) context.fill(CGRect(x: 0, y: disc.minY + CGFloat(stripe) * size * 0.06, width: size, height: height)) } } private mutating func blocks() { let cells = Int.random(in: 2 ... 3, using: &random) let cell = size / CGFloat(cells) for row in 0 ..< cells { for column in 0 ..< cells where Bool.random(using: &random) { let rect = CGRect(x: CGFloat(column) * cell, y: CGFloat(row) * cell, width: cell, height: cell) context.setFillColor(color(hue + .random(in: 0 ... 0.6, using: &random), 0.7, .random(in: 0.3 ... 1, using: &random))) if Bool.random(using: &random) { context.fill(rect) } else { context.fillEllipse(in: rect) } } } } private func color(_ hue: Double, _ saturation: Double, _ brightness: Double) -> CGColor { let sector = (hue.truncatingRemainder(dividingBy: 1) + 1).truncatingRemainder(dividingBy: 1) * 6 let chroma = brightness * saturation let second = chroma * (1 - abs(sector.truncatingRemainder(dividingBy: 2) - 1)) let table = [ [chroma, second, 0], [second, chroma, 0], [0, chroma, second], [0, second, chroma], [second, 0, chroma], [chroma, 0, second], ] let rgb = table[min(Int(sector), 5)].map { $0 + brightness - chroma } return CGColor(red: rgb[0], green: rgb[1], blue: rgb[2], alpha: 1) } private func linear(_ colors: [CGColor], from: CGPoint, to: CGPoint) { guard let gradient = CGGradient(colorsSpace: space, colors: colors as CFArray, locations: nil) else { return } context.drawLinearGradient(gradient, start: from, end: to, options: [.drawsBeforeStartLocation, .drawsAfterEndLocation]) } }