96 lines
3.6 KiB
Swift
96 lines
3.6 KiB
Swift
#!/usr/bin/env swift
|
|
// Generates the G-ART app icon (a gradient tile with a white waveform)
|
|
// and writes AppIcon.icns. Run from the repo root:
|
|
// swift MacApp/make_icon.swift
|
|
import AppKit
|
|
import CoreGraphics
|
|
import Foundation
|
|
|
|
let size: CGFloat = 1024
|
|
let image = NSImage(size: NSSize(width: size, height: size))
|
|
image.lockFocus()
|
|
|
|
guard let ctx = NSGraphicsContext.current?.cgContext else {
|
|
print("no ctx"); exit(1)
|
|
}
|
|
|
|
// Background: vertical gradient blue → indigo.
|
|
let colors = [
|
|
NSColor(calibratedRed: 0.0, green: 0.48, blue: 1.0, alpha: 1).cgColor,
|
|
NSColor(calibratedRed: 0.30, green: 0.20, blue: 0.85, alpha: 1).cgColor,
|
|
]
|
|
let space = CGColorSpaceCreateDeviceRGB()
|
|
if let grad = CGGradient(colorsSpace: space, colors: colors as CFArray, locations: [0, 1]) {
|
|
ctx.drawLinearGradient(grad, start: CGPoint(x: 0, y: size),
|
|
end: CGPoint(x: size, y: 0), options: [])
|
|
}
|
|
|
|
// Rounded-corner mask (squircle-ish).
|
|
let rect = CGRect(x: 0, y: 0, width: size, height: size)
|
|
let corner: CGFloat = 230
|
|
let path = CGPath(roundedRect: rect, cornerWidth: corner, cornerHeight: corner, transform: nil)
|
|
ctx.addPath(path)
|
|
ctx.clip()
|
|
|
|
// White waveform: several vertical bars of varying height.
|
|
ctx.setFillColor(NSColor.white.cgColor)
|
|
let barW: CGFloat = 70
|
|
let gap: CGFloat = 45
|
|
let totalW = 5 * barW + 4 * gap
|
|
let startX = (size - totalW) / 2
|
|
let heights: [CGFloat] = [240, 500, 700, 500, 240]
|
|
let baseY = (size - 700) / 2
|
|
for (i, h) in heights.enumerated() {
|
|
let x = startX + CGFloat(i) * (barW + gap)
|
|
let bar = CGRect(x: x, y: baseY, width: barW, height: h)
|
|
let barPath = CGPath(roundedRect: bar, cornerWidth: barW / 2, cornerHeight: barW / 2, transform: nil)
|
|
ctx.addPath(barPath)
|
|
ctx.fillPath()
|
|
}
|
|
|
|
image.unlockFocus()
|
|
|
|
// Convert to 1024 PNG temp, then build .icns via iconutil.
|
|
let outDir = FileManager.default.temporaryDirectory.appendingPathComponent("gart_icon")
|
|
try? FileManager.default.removeItem(at: outDir)
|
|
try FileManager.default.createDirectory(at: outDir, withIntermediateDirectories: true)
|
|
|
|
let pngSizes = [16, 32, 64, 128, 256, 512, 1024]
|
|
let iconset = outDir.appendingPathComponent("AppIcon.iconset")
|
|
try FileManager.default.createDirectory(at: iconset, withIntermediateDirectories: true)
|
|
|
|
func write(_ size: Int, _ name: String) throws {
|
|
let w = NSSize(width: size, height: size)
|
|
let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: size, pixelsHigh: size,
|
|
bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true,
|
|
isPlanar: false, colorSpaceName: .deviceRGB,
|
|
bytesPerRow: 0, bitsPerPixel: 0)!
|
|
rep.size = w
|
|
NSGraphicsContext.saveGraphicsState()
|
|
NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: rep)
|
|
image.draw(in: NSRect(origin: .zero, size: w),
|
|
from: .zero, operation: .sourceOver, fraction: 1)
|
|
NSGraphicsContext.restoreGraphicsState()
|
|
let data = rep.representation(using: .png, properties: [:])!
|
|
try data.write(to: iconset.appendingPathComponent(name))
|
|
}
|
|
|
|
try write(16, "icon_16x16.png")
|
|
try write(32, "icon_16x16@2x.png")
|
|
try write(32, "icon_32x32.png")
|
|
try write(64, "icon_32x32@2x.png")
|
|
try write(128, "icon_128x128.png")
|
|
try write(256, "icon_128x128@2x.png")
|
|
try write(256, "icon_256x256.png")
|
|
try write(512, "icon_256x256@2x.png")
|
|
try write(512, "icon_512x512.png")
|
|
try write(1024, "icon_512x512@2x.png")
|
|
|
|
let process = Process()
|
|
process.executableURL = URL(fileURLWithPath: "/usr/bin/iconutil")
|
|
process.arguments = ["-c", "icns", iconset.path, "-o", "MacApp/Assets/AppIcon.icns"]
|
|
try process.run()
|
|
process.waitUntilExit()
|
|
|
|
print("Icon written to MacApp/Assets/AppIcon.icns")
|