Search code examples
swiftmacosresizensimage

OSX - Loading an image and saving it as a smaller png file using Swift


I am looking for a way to to upload an image file, resize it (in order to reduce the total file size), and then save it as a png. I think there must be a fairly straightforward way of doing this, but hours of searching around have yielded no effective results. I have been able to achieve the desired file size by exporting the image as a compressed JPEG, but I need to preserve transparency. Here is the code I used to get the JPEG:

func chooseImage ()  {
    var image = NSImage()

    //choose image from hard disk
    let panel = NSOpenPanel()
    panel.allowsMultipleSelection = false
    panel.canChooseFiles = true
    panel.canChooseDirectories = false
    panel.runModal()
    panel.allowedFileTypes = ["png", "jpeg", "jpg"]

    let chosenFile = panel.URL

    //convert to NSData and send to Jpeg function
    if chosenFile != nil {
        image = NSImage(contentsOfURL: chosenFile!)!
        let imageData = image.TIFFRepresentation
        self.saveAsJpeg(imageData!, compression: 0.5)
    }
}




func saveAsJpeg (image:NSData, compression:NSNumber)  {
    // make imagerep and define properties
    let imgRep = NSBitmapImageRep(data: image)
    let props = NSDictionary.init(object: compression, forKey: NSImageCompressionFactor)
    let pingy = imgRep?.representationUsingType(NSBitmapImageFileType.NSJPEGFileType, properties: props as! [String : AnyObject])

    //save to disk
    let documentURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
    let folderURL = documentURL.URLByAppendingPathComponent("KKNightlife Data")

    let g = GetUniqueID()
    let fileName = g.getUniqueID() + ".jpeg"

    do {
        try NSFileManager.defaultManager().createDirectoryAtURL(folderURL, withIntermediateDirectories: false, attributes: nil)
    } catch  {
        print("cannot create directory - folder Exists?")
    }
    let url = folderURL.URLByAppendingPathComponent(fileName)

    if let pid = pingy {
        pid.writeToURL(url, atomically: false)
    } else {
        print("error saving image")
    }
}

I attempted to use the following code to scale the image in order to create a smaller .png file, but no matter what values I enter for the size, the resulting file is the same size (both in terms of height/width and overall file size):

func chooseImage (size:String) {
    let panel = NSOpenPanel()
    panel.allowsMultipleSelection = false
    panel.canChooseFiles = true
    panel.canChooseDirectories = false
    panel.runModal()
    panel.allowedFileTypes = ["png", "jpeg", "jpg"]

    let chosenFile = panel.URL

    if chosenFile != nil {
        let image = NSImage(contentsOfURL: chosenFile!)
        self.scaleImage(image!)
    }
}


func scaleImage (image:NSImage) {

    //create resized image
    let newSize = NSSize(width: 10, height: 10)
    var imageRect:CGRect = CGRectMake(0, 0, image.size.width, image.size.height)
    let imageRef = image.CGImageForProposedRect(&imageRect, context: nil, hints: nil)
    let resizedImage = NSImage(CGImage: imageRef!, size: newSize)

    let imageData = resizedImage.TIFFRepresentation

    //make imagerep
    let imgRep = NSBitmapImageRep(data: imageData!)
    let pingy = imgRep?.representationUsingType(NSBitmapImageFileType.NSPNGFileType, properties:  [:])

    //save to disk
    let documentURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
    let g = GetUniqueID()
    let fileName = g.getUniqueID() + ".png"

    let folderURL = documentURL.URLByAppendingPathComponent("KKNightlife Data")
    do {
        try NSFileManager.defaultManager().createDirectoryAtURL(folderURL, withIntermediateDirectories: false, attributes: nil)
    } catch  {
        print("cannot create directory - folder Exists?")
    }
    let url = folderURL.URLByAppendingPathComponent(fileName)
    if let pid = pingy {
        pid.writeToURL(url, atomically: false)
        print("image is at \(documentURL)")
    } else {
        print("error saving image")
    }
}

Any suggestions would be greatly appreciated.


Solution

  • I was finally able to do this using the extensions found here: https://gist.github.com/raphaelhanneken/cb924aa280f4b9dbb480

    This is how I ended up calling them in case anyone encounters similar problems:

    func chooseImage (size:String) {
        let panel = NSOpenPanel()
        panel.allowsMultipleSelection = false
        panel.canChooseFiles = true
        panel.canChooseDirectories = false
        panel.runModal()
        panel.allowedFileTypes = ["png", "jpeg", "jpg"]
    
        let chosenFile = panel.URL
    
        if chosenFile != nil {
            let image = NSImage(contentsOfURL: chosenFile!)
            self.scaleImageUsingExtensions(image!)
        }
    }
    
    func scaleImageUsingExtensions (image:NSImage){
        let size: NSSize = NSMakeSize(10, 10)
        let resizedImage = image.resizeWhileMaintainingAspectRatioToSize(size)
        let documentURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
        let g = GetUniqueID()
        let fileName = g.getUniqueID() + ".png"
    
        let folderURL = documentURL.URLByAppendingPathComponent("KKNightlife Data")
        do {
            try NSFileManager.defaultManager().createDirectoryAtURL(folderURL, withIntermediateDirectories: false, attributes: nil)
        } catch  {
            print("cannot create directory - folder Exists?")
        }
        let url = folderURL.URLByAppendingPathComponent(fileName)
        do {
    
        try resizedImage?.savePNGRepresentationToURL(url)
    
        }
        catch {
            print("error saving file")
        }
    }