// Zeichnet den Hintergrund des Installationsfensters. // // Gezeichnet statt mitgeliefert: ein Bild im Verzeichnis wäre eine Datei, die // niemand mehr anfasst und die bei jeder Farbänderung veraltet. So steht das // Aussehen im selben Werkzeugkasten wie der Rest — und die Onyx-Farben stehen // hier genau einmal. // // Aufruf: dmg-background // Erzeugt .png und @2x.png. import AppKit let arguments = CommandLine.arguments guard arguments.count == 2 else { FileHandle.standardError.write(Data("Aufruf: dmg-background \n".utf8)) exit(1) } let target = arguments[1] // Maße des Fensters in Punkten. Die Symbole setzt das Skript an dieselben // Stellen — ändert sich hier etwas, muss es dort mitwandern. let width: CGFloat = 640 let height: CGFloat = 400 let iconY: CGFloat = 196 // Mitte der Symbolreihe, von oben let leftIcon: CGFloat = 170 let rightIcon: CGFloat = 470 func draw(scale: CGFloat, to path: String) { let pixelWidth = Int(width * scale) let pixelHeight = Int(height * scale) guard let context = CGContext(data: nil, width: pixelWidth, height: pixelHeight, bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpace(name: CGColorSpace.sRGB)!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { exit(1) } context.scaleBy(x: scale, y: scale) // Von oben nach unten rechnen wie im Fenster; Core Graphics fängt unten an. context.translateBy(x: 0, y: height) context.scaleBy(x: 1, y: -1) let graphics = NSGraphicsContext(cgContext: context, flipped: true) NSGraphicsContext.current = graphics // Grundfläche: derselbe flache Verlauf wie im Panel. Zwei Prozent Weiß oben, // nichts unten — mehr wirkt billig. let surface = NSColor(srgbRed: 0.043, green: 0.043, blue: 0.051, alpha: 1) let elevated = NSColor(srgbRed: 0.078, green: 0.078, blue: 0.090, alpha: 1) NSGradient(colors: [elevated, surface])? .draw(in: NSRect(x: 0, y: 0, width: width, height: height), angle: -90) // Die Haarlinie unter dem Kopf — der halbe „edle" Effekt steckt darin. NSColor(white: 1, alpha: 0.08).setFill() NSRect(x: 40, y: 118, width: width - 80, height: 1).fill() let title = "Onyx" let titleAttributes: [NSAttributedString.Key: Any] = [ .font: NSFont.systemFont(ofSize: 30, weight: .semibold), .foregroundColor: NSColor(srgbRed: 0.949, green: 0.949, blue: 0.957, alpha: 1), .kern: -0.5, ] let titleSize = title.size(withAttributes: titleAttributes) title.draw(at: NSPoint(x: (width - titleSize.width) / 2, y: 48), withAttributes: titleAttributes) let subtitle = "Zum Installieren nach „Programme“ ziehen" let subtitleAttributes: [NSAttributedString.Key: Any] = [ .font: NSFont.systemFont(ofSize: 12, weight: .regular), .foregroundColor: NSColor(white: 1, alpha: 0.58), ] let subtitleSize = subtitle.size(withAttributes: subtitleAttributes) subtitle.draw(at: NSPoint(x: (width - subtitleSize.width) / 2, y: 88), withAttributes: subtitleAttributes) // Der Pfeil zwischen den beiden Symbolen: er sagt in einem Bild, was der // Satz darüber in sieben Wörtern sagt. let accent = NSColor(srgbRed: 0.498, green: 0.659, blue: 1.0, alpha: 0.55) accent.setStroke() let shaft = NSBezierPath() let from = leftIcon + 92 let to = rightIcon - 92 shaft.move(to: NSPoint(x: from, y: iconY)) shaft.line(to: NSPoint(x: to - 10, y: iconY)) shaft.lineWidth = 3 shaft.lineCapStyle = .round shaft.stroke() let head = NSBezierPath() head.move(to: NSPoint(x: to - 18, y: iconY - 9)) head.line(to: NSPoint(x: to, y: iconY)) head.line(to: NSPoint(x: to - 18, y: iconY + 9)) head.lineWidth = 3 head.lineCapStyle = .round head.lineJoinStyle = .round head.stroke() // Fußzeile: die Fassung gehört sichtbar dazu, damit man später weiß, was // man da eigentlich installiert hat. let version = ProcessInfo.processInfo.environment["ONYX_VERSION"] ?? "" if !version.isEmpty { let footer = "Fassung \(version)" let footerAttributes: [NSAttributedString.Key: Any] = [ .font: NSFont.systemFont(ofSize: 10, weight: .regular), .foregroundColor: NSColor(white: 1, alpha: 0.34), ] let footerSize = footer.size(withAttributes: footerAttributes) footer.draw(at: NSPoint(x: (width - footerSize.width) / 2, y: height - 34), withAttributes: footerAttributes) } NSGraphicsContext.current = nil guard let image = context.makeImage(), let destination = CGImageDestinationCreateWithURL( URL(fileURLWithPath: path) as CFURL, "public.png" as CFString, 1, nil) else { exit(1) } CGImageDestinationAddImage(destination, image, nil) CGImageDestinationFinalize(destination) } import ImageIO draw(scale: 1, to: target + ".png") draw(scale: 2, to: target + "@2x.png")