#!/usr/bin/env swift // // square_logo.swift // IceGlass // // Usage: square_logo.swift // // Loads an RGBA PNG, trims transparent margins (alpha bounding box), // fits the trimmed content into a target-side × target-side transparent // sRGB square canvas (aspect-preserved, centered), and writes PNG. // // The trim step matters because NHL SVG logos often ship with significant // transparent padding inside the viewBox — without trimming, the visible // logo only occupies a fraction of the thumbnail. // import CoreGraphics import Foundation import ImageIO import UniformTypeIdentifiers guard CommandLine.arguments.count == 4, let targetSize = Int(CommandLine.arguments[3]), targetSize > 0 else { FileHandle.standardError.write( Data("Usage: square_logo.swift \n".utf8) ) exit(2) } let inputURL = URL(fileURLWithPath: CommandLine.arguments[1]) let outputURL = URL(fileURLWithPath: CommandLine.arguments[2]) guard let source = CGImageSourceCreateWithURL(inputURL as CFURL, nil), let srcImage = CGImageSourceCreateImageAtIndex(source, 0, nil) else { FileHandle.standardError.write(Data("failed to load \(inputURL.path)\n".utf8)) exit(1) } // MARK: - Find alpha bounding box /// Read the source image into a premultiplied RGBA8 buffer so we can scan /// pixels directly, then find the tightest rectangle enclosing all alpha /// values above a small threshold. func alphaBoundingBox(_ image: CGImage, alphaThreshold: UInt8 = 8) -> CGRect? { let w = image.width let h = image.height let bytesPerPixel = 4 let bytesPerRow = w * bytesPerPixel var buffer = [UInt8](repeating: 0, count: h * bytesPerRow) let colorSpace = CGColorSpace(name: CGColorSpace.sRGB) ?? CGColorSpaceCreateDeviceRGB() guard let ctx = CGContext( data: &buffer, width: w, height: h, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue ) else { return nil } ctx.draw(image, in: CGRect(x: 0, y: 0, width: w, height: h)) var minX = w, minY = h, maxX = -1, maxY = -1 for y in 0.. alphaThreshold { if x < minX { minX = x } if x > maxX { maxX = x } if y < minY { minY = y } if y > maxY { maxY = y } } } } guard maxX >= minX, maxY >= minY else { return nil } return CGRect(x: minX, y: minY, width: maxX - minX + 1, height: maxY - minY + 1) } let bbox = alphaBoundingBox(srcImage) ?? CGRect(x: 0, y: 0, width: srcImage.width, height: srcImage.height) // MARK: - Crop to bbox, then fit into target square guard let cropped = srcImage.cropping(to: bbox) else { FileHandle.standardError.write(Data("crop failed\n".utf8)) exit(1) } let colorSpace = CGColorSpace(name: CGColorSpace.sRGB) ?? CGColorSpaceCreateDeviceRGB() guard let ctx = CGContext( data: nil, width: targetSize, height: targetSize, bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue ) else { FileHandle.standardError.write(Data("CGContext create failed\n".utf8)) exit(1) } ctx.interpolationQuality = .high ctx.clear(CGRect(x: 0, y: 0, width: targetSize, height: targetSize)) let cw = CGFloat(cropped.width) let ch = CGFloat(cropped.height) let S = CGFloat(targetSize) let scale = min(S / cw, S / ch) let dw = cw * scale let dh = ch * scale let drawRect = CGRect(x: (S - dw) / 2, y: (S - dh) / 2, width: dw, height: dh) ctx.draw(cropped, in: drawRect) guard let final = ctx.makeImage(), let dest = CGImageDestinationCreateWithURL( outputURL as CFURL, UTType.png.identifier as CFString, 1, nil ) else { FileHandle.standardError.write(Data("image/dest create failed\n".utf8)) exit(1) } CGImageDestinationAddImage(dest, final, nil) guard CGImageDestinationFinalize(dest) else { FileHandle.standardError.write(Data("finalize failed\n".utf8)) exit(1) }