Resize NSImage Proportionally (Swift)

I wanted a simple function to resize an image to a desired height, while keeping proportions. Here’s what I came up with (based on Marco implementation):

extension NSImage {


    func resizedImageTo(sourceImage: NSImage, newSize: NSSize) -> NSImage?{

        if sourceImage.isValid == false {

            return nil


        let representation = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(newSize.width), pixelsHigh: Int(newSize.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .calibratedRGB, bytesPerRow: 0, bitsPerPixel: 0)

        representation?.size = newSize



        NSGraphicsContext.current = NSGraphicsContext.init(bitmapImageRep: representation!)

        sourceImage.draw(in: NSRect(x: 0, y: 0, width: newSize.width, height: newSize.height), from: NSZeroRect, operation: .copy, fraction: 1.0)



        let newImage = NSImage(size: newSize)



        return newImage






Questions / comments / suggestions? I’m at @MarcMasVi 


Updated after I discovered the great implementation Marco Arment suggested. 

NSImageView Aspect Fill

Setting an image to use AspectFill in iOS is trivial, you can set it by code or directly in storyboard. 

But how do you do it in macOS? In Cocoa/App Kit there is no property for that, you may scale it , but there is no option for AspectFill (or AspectFit for that matter). So, how do we do it?

Once you find the way is quite easy actually. We’ll create a subclass of NSImageView and we’ll override the image property, then, we’ll place the image in a CALayer; and finally we’ll use this CALayer to resize it with the desired AspectFill. 

import Cocoa


class ImageAspectFillView: NSImageView {


    override var image: NSImage? {

        set {

            self.layer = CALayer()

            self.layer?.contentsGravity = kCAGravityResizeAspectFill

            self.layer?.contents = newValue

            self.wantsLayer = true


            super.image = newValue



        get {

            return super.image







And that’s it! I hope it helped, took me quite a while to find this solution but works like a charm. Questions, comments? I’m at @MarcMasVi