Dhiru
Dhiru

Reputation: 3060

How to compress NSImage in Swift 4

I am developing application for Mac OS , i am not able to find any method for compressing NSImage and Converting them to base64 encoded string for Swift 4 .

Hardly i found Swift3 code

 func compressUnderMegaBytes(megabytes: CGFloat) -> NSImage? {
        var compressionRatio = 1.0
        var imageRep = NSBitmapImageRep(data: self.tiffRepresentation!)
        var options = NSDictionary(object: NSNumber(floatLiteral: compressionRatio), forKey: NSBitmapImageRep.PropertyKey.compressionFactor as NSCopying)
        var compressedData: Data? = imageRep?.representation(using: .jpeg, properties: options as! [NSBitmapImageRep.PropertyKey : Any])
        while compressedData?.length > (megabytes * 1024 * 1024) {
            compressionRatio = compressionRatio * 0.9
            options = NSDictionary(object: NSNumber(floatLiteral:compressionRatio), forKey: NSBitmapImageRep.PropertyKey.compressionFactor as NSCopying)
            compressedData = imageRep?.representation(using:.png, properties: options as! [NSBitmapImageRep.PropertyKey : Any])
            if compressionRatio <= 0.4 {
                break
            }
        }
        return NSImage(data: compressedData!)
    }

but after converting to Swift 4 getting following error

enter image description here

Upvotes: 1

Views: 1335

Answers (1)

vadian
vadian

Reputation: 285290

The translated code is quite cumbersome. The NSDictionary detour is not necessary in Swift 4.

length has been renamed to count

extension NSImage {
    func compressUnderMegaBytes(megabytes: CGFloat) -> NSImage? {

        var compressionRatio = 1.0
        guard let tiff = self.tiffRepresentation, let imageRep = NSBitmapImageRep(data: tiff) else { return nil }
        var compressedData = imageRep.representation(using: .jpeg, properties: [.compressionFactor : compressionRatio])!
        while CGFloat(compressedData.count) > megabytes * 1024 * 1024 {
            compressionRatio = compressionRatio * 0.9
            compressedData = imageRep.representation(using: .png, properties:  [.compressionFactor : compressionRatio])!
            if compressionRatio <= 0.4 {
                break
            }
        }
        return NSImage(data: compressedData)
    }
}

Or without unsafe unwrapped optionals

extension NSImage {
    func compressUnderMegaBytes(megabytes: CGFloat) -> NSImage? {

        var compressionRatio = 1.0
        guard let tiff = self.tiffRepresentation, let imageRep = NSBitmapImageRep(data: tiff) else { return nil }
        var compressedData = imageRep.representation(using: .jpeg, properties: [.compressionFactor : compressionRatio])
        if compressedData == nil { return self }
        while CGFloat(compressedData!.count) > megabytes * 1024 * 1024 {
            compressionRatio = compressionRatio * 0.9
            let newCompressedData = imageRep.representation(using: .png, properties:  [.compressionFactor : compressionRatio])
            if compressionRatio <= 0.4 || newCompressedData == nil {
                break
            }
            compressedData = newCompressedData
        }
        return NSImage(data: compressedData!)
    }
}

Note: Is it intended to compress the first time as jpg and then as png?

Upvotes: 2

Related Questions