62 lines
2.5 KiB
Swift
62 lines
2.5 KiB
Swift
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")
|