From 13d2ff115ba094380a25de50aa4e760a8f839103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Eric=20Janouch?= Date: Mon, 4 Sep 2023 06:11:58 +0200 Subject: xM: improve the bundle icon a bit --- xM/gen-icon.swift | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/xM/gen-icon.swift b/xM/gen-icon.swift index 5e29016..712e9e6 100644 --- a/xM/gen-icon.swift +++ b/xM/gen-icon.swift @@ -1,4 +1,4 @@ -// gen-icon.awk: generate a program icon for xM in the Apple icon format +// gen-icon.swift: generate a program icon for xM in the Apple icon format // // Copyright (c) 2023, Přemysl Eric Janouch // SPDX-License-Identifier: 0BSD @@ -10,24 +10,17 @@ import Foundation import ImageIO import UniformTypeIdentifiers -// XXX: Not even AppKit provides real superelliptic squircles; screw it. -func drawSquircle(context: CGContext, bounds: CGRect, radius: CGFloat) { - context.move(to: CGPointMake(bounds.minX, bounds.maxY - radius)) - context.addArc( - center: CGPointMake(bounds.minX + radius, bounds.maxY - radius), - radius: radius, startAngle: .pi, endAngle: .pi / 2, clockwise: true) - context.addLine(to: CGPointMake(bounds.maxX - radius, bounds.maxY)) - context.addArc( - center: CGPointMake(bounds.maxX - radius, bounds.maxY - radius), - radius: radius, startAngle: .pi / 2, endAngle: 0, clockwise: true) - context.addLine(to: CGPointMake(bounds.maxX, bounds.maxY - radius)) - context.addArc( - center: CGPointMake(bounds.maxX - radius, bounds.minY + radius), - radius: radius, startAngle: 0, endAngle: .pi / -2, clockwise: true) - context.addLine(to: CGPointMake(bounds.minX + radius, bounds.minY)) - context.addArc( - center: CGPointMake(bounds.minX + radius, bounds.minY + radius), - radius: radius, startAngle: .pi / -2, endAngle: .pi, clockwise: true) +// Apple uses something that's close to a "quintic superellipse" in their icons, +// but doesn't quite match. Either way, it looks better than rounded rectangles. +func addSquircle(context: CGContext, bounds: CGRect) { + context.move(to: CGPoint(x: bounds.maxX, y: bounds.midY)) + for theta in stride(from: 0.0, to: .pi * 2, by: .pi / 1e4) { + let x = pow(abs(cos(theta)), 2 / 5.0) * bounds.width / 2 + * CGFloat(signOf: cos(theta), magnitudeOf: 1) + bounds.midX + let y = pow(abs(sin(theta)), 2 / 5.0) * bounds.height / 2 + * CGFloat(signOf: sin(theta), magnitudeOf: 1) + bounds.midY + context.addLine(to: CGPoint(x: x, y: y)) + } context.closePath() } @@ -42,8 +35,7 @@ func drawIcon(scale: CGFloat) -> CGImage? { context.scaleBy(x: scale, y: scale) let bounds = CGRectMake(100, 100, size.width - 200, size.height - 200) - // The radius was something like size.{width,height}/6.4, at least for iOS. - drawSquircle(context: context, bounds: bounds, radius: 180) + addSquircle(context: context, bounds: bounds) let squircle = context.path! // Gradients don't draw shadows, so draw it separately. -- cgit v1.2.3