Skip to content

Instantly share code, notes, and snippets.

@bnickel
Created August 7, 2015 15:28
Show Gist options
  • Save bnickel/5f24e6df2e290bef0ddb to your computer and use it in GitHub Desktop.
Save bnickel/5f24e6df2e290bef0ddb to your computer and use it in GitHub Desktop.
Walgreens photo uploaded would only let me crop, but I had a bunch of square photos, so...
#!/usr/bin/swift
// Because sometimes you don't want to crop.
// USAGE: aspect-grow RATIO FILES...
// aspect-grow 4:6 *.jpg
//
// Places all files in an output directory relative to their location, so
// aspect-grow 4:6 *.jpg creates a folder "output" in this directory but
// aspect-grow 4:6 a/b.jpg and b/c.jpg creates folders a/output and b/output.
import Cocoa
struct AspectRatio : CustomStringConvertible {
var width:CGFloat
var height:CGFloat
init?(width:CGFloat, height:CGFloat) {
if width <= 0 || height <= 0 {
return nil
}
self.width = width
self.height = height
}
init?(_ string:String) {
let parts = string.componentsSeparatedByString(":")
if parts.count != 2 {
return nil
}
guard let width = Double(parts[0]), height = Double(parts[1]) else {
return nil
}
self.init(width: CGFloat(width), height: CGFloat(height))
}
var description:String {
return "\(width):\(height)"
}
func rotated() -> AspectRatio {
return AspectRatio(width: height, height: width)!
}
}
extension CGSize {
mutating func grow(aspectRatio:AspectRatio) {
if width < height * aspectRatio.width / aspectRatio.height {
width = height * aspectRatio.width / aspectRatio.height
} else {
height = width * aspectRatio.height / aspectRatio.width
}
}
func grown(aspectRatio:AspectRatio) -> CGSize {
var size = self
size.grow(aspectRatio)
return size
}
var diagonal:CGFloat {
return sqrt(width * width + height * height)
}
func rotated() -> CGSize {
return CGSize(width: height, height: width)
}
}
func bestSizeForImageAtPath(path:String, aspectRatio:AspectRatio) -> CGSize? {
guard let size = NSImage(contentsOfFile: path)?.size else {
return nil
}
var normalSize = size.grown(aspectRatio)
var rotatedSize = size.grown(aspectRatio.rotated())
if normalSize.diagonal < rotatedSize.diagonal {
return normalSize
} else {
return rotatedSize
}
}
func resizeImageAtPath(path:String, aspectRatio:AspectRatio) {
guard let newSize = bestSizeForImageAtPath(path, aspectRatio: aspectRatio) else {
preconditionFailure("Could not determine aspect ratio for file at \(path)")
}
do {
try NSFileManager().createDirectoryAtPath(path.stringByDeletingLastPathComponent.stringByAppendingPathComponent("output"), withIntermediateDirectories: false, attributes: nil)
} catch {
}
let task = NSTask()
task.launchPath = "/usr/local/bin/convert"
task.arguments = [
"-size", "\(Int(newSize.width))x\(Int(newSize.height))",
"xc:white",
path,
"-gravity", "center",
"-composite",
path.stringByDeletingLastPathComponent.stringByAppendingPathComponent("output").stringByAppendingPathComponent(path.lastPathComponent)
]
task.launch()
task.waitUntilExit()
if task.terminationStatus != 0 {
preconditionFailure("ImageMagick failed with arguments: \(task.arguments!)")
}
}
let args = Process.arguments
precondition(args.count >= 3, "USAGE: aspect-grow RATIO FILES...")
guard let aspectRatio = AspectRatio(args[1]) else {
preconditionFailure("Aspect ratio must be of format A:B, e.g. 4:6")
}
for path in args[2..<args.endIndex] {
resizeImageAtPath(path, aspectRatio: aspectRatio)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment