import AppKit import CoreGraphics import Foundation // Die Zeichnungen sind weiss gefüllt mit dunklen Linien und Fenstern. Als // Schablone eingefärbt geht beides verloren, weil alles Deckende zur // Tintfarbe wird - übrig bleibt eine massive Fläche. // // Deshalb wird die Helligkeit in Deckkraft übersetzt: dunkle Linien werden // voll deckend, die helle Karosserie nur angedeutet. Eingefärbt ergibt das // eine gefüllte Form, in der die Details erhalten bleiben. let arguments = CommandLine.arguments guard arguments.count >= 3, let source = NSImage(contentsOfFile: arguments[1]), let image = source.cgImage(forProposedRect: nil, context: nil, hints: nil) else { print("Quelle nicht lesbar"); exit(1) } let width = image.width, height = image.height let bytesPerRow = width * 4 var pixels = [UInt8](repeating: 0, count: bytesPerRow * height) guard let context = CGContext(data: &pixels, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { print("Puffer nicht anlegbar"); exit(1) } context.draw(image, in: CGRect(x: 0, y: 0, width: width, height: height)) /// Wie stark die Fläche noch durchscheint. let fill = 0.22 var changed = 0 for index in stride(from: 0, to: pixels.count, by: 4) { let alpha = Double(pixels[index + 3]) / 255 guard alpha > 0.02 else { pixels[index] = 0; pixels[index + 1] = 0; pixels[index + 2] = 0; pixels[index + 3] = 0 continue } // Premultipliziert: erst zurückrechnen, um die echte Helligkeit zu sehen. let r = Double(pixels[index]) / 255 / alpha let g = Double(pixels[index + 1]) / 255 / alpha let b = Double(pixels[index + 2]) / 255 / alpha let brightness = min(1, max(0, 0.299 * r + 0.587 * g + 0.114 * b)) let newAlpha = alpha * (fill + (1 - fill) * (1 - brightness)) // Die Farbe selbst spielt keine Rolle, sie wird ohnehin eingefärbt. let value = UInt8(newAlpha * 255) pixels[index] = value; pixels[index + 1] = value; pixels[index + 2] = value pixels[index + 3] = value changed += 1 } guard let result = context.makeImage() else { print("Bild leer"); exit(1) } let rep = NSBitmapImageRep(cgImage: result) guard let png = rep.representation(using: .png, properties: [:]) else { print("PNG nicht erzeugbar"); exit(1) } try png.write(to: URL(fileURLWithPath: arguments[2])) print("\(arguments[2]): \(changed) Bildpunkte umgesetzt")