简体   繁体   中英

Swift on MacOS - How to save NSImage to disk

I have the following code working:

let myImage = NSImage(named: "my-image.png")

filter.setValue(myImage, forKey: kCIInputImageKey)
filter.setValue(0.5, forKey: kCIInputIntensityKey)

let resultImage = filter.outputImage

How can I save the filtered image (as a PNG) to disk? Please note that this is a MacOS version where UIImage is not available (Xcode throws: No such module 'UIImage' when trying to import)

You can create a Core Image Context and createCGImage from your ciimage filter result. You can do it as follow:

import Cocoa

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let context = CIContext()
        let desktopURL = FileManager.default.urls(for: .desktopDirectory, in: .userDomainMask).first!
        guard
            let filter = CIFilter(name: "CISepiaTone"),
            let imageURL = Bundle.main.url(forResource: "my-image", withExtension: "png"),
            let ciImage = CIImage(contentsOf: imageURL)
        else { return }

        filter.setValue(ciImage, forKey: kCIInputImageKey)
        filter.setValue(0.5, forKey: kCIInputIntensityKey)

        guard let result = filter.outputImage, let cgImage = context.createCGImage(result, from: result.extent)
        else { return }

        let destinationURL = desktopURL.appendingPathComponent("my-image.png")
        let nsImage = NSImage(cgImage: cgImage, size: ciImage.extent.size)
        if nsImage.pngWrite(to: destinationURL, options: .withoutOverwriting) {
            print("File saved")
        }
    }
}

You will need those extensions to get the png representation data to write the resulting image to disk:

extension NSImage {
    var pngData: Data? {
        guard let tiffRepresentation = tiffRepresentation, let bitmapImage = NSBitmapImageRep(data: tiffRepresentation) else { return nil }
        return bitmapImage.representation(using: .png, properties: [:])
    }
    func pngWrite(to url: URL, options: Data.WritingOptions = .atomic) -> Bool {
        do {
            try pngData?.write(to: url, options: options)
            return true
        } catch {
            print(error)
            return false
        }
    }
}

2021 | Swift 5

This extension:

public extension NSImage {
    func save(to url: URL, format: NSBitmapImageRep.FileType, props: [NSBitmapImageRep.PropertyKey : Any] ) -> Result<URL, Error> {
        return self.representations.first
            .asNonOptional
            .map { $0 as? NSBitmapImageRep }
            .flatMap { data -> R<NSBitmapImageRep> in data.asNonOptional }
            .map { $0.representation(using: .jpeg, properties: props) }
            .flatMap{ $0.asNonOptional }
            .map { try? $0.write(to: url) }
            .map { $0.asNonOptional }
            .map { _ in url}
    }
}

public extension Optional {
    var asNonOptional : R<Wrapped> {
        if let val = self {
            return .success(val)
        } else {
            return .failure(CustomError("nil for optional value of type <\(Wrapped.self)>"))
        }
    }
}

public func CustomError(_ msg: String, code: Int = 0) -> Error {
    NSError(code: code, message: msg)
}

works with most needed file formats and supports of any needed properties.

usage:

_ = someImage.write(to: url, format: .png, props: [.compressionFactor : NSNumber(floatLiteral: 1.0)])

_ = someImage.write(to: url, format: .jpeg, props: [.compressionFactor : NSNumber(floatLiteral: 1.0)])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM