Calling exiftool with Process() in Swift

I’m trying to use Process() in Swift to call exiftool and having no success.
I’ve done this many times in Xojo but can’t get it figured out in Swift.

Has anyone here done this or perhaps can offer some advice?

Thanks
_
Phil

I have never done this, but can see a situtino where I might.

Post whatever code you have tried, and what seems to not be right

for macOS or iOS (it could make a huge difference)

I’ve figured out a way to accomplish it.
(For Mac OS)
There may be better ways but I’m new to Swift ant this was what I was able to figure out.

func exiftoolVersion() -> String {

let task = Process()
let pipe = Pipe()

task.standardOutput = pipe
task.arguments = ["-ver"]
task.executableURL = URL(fileURLWithPath: "/usr/local/bin/exiftool")
do {
    try task.run()
    task.waitUntilExit()
}
catch {
    
}

let data = pipe.fileHandleForReading.readDataToEndOfFile()
var output = String(data: data, encoding: .utf8)!

output = output.filter { !$0.isWhitespace }
return output

Have you googled this?
I found dozens of EXIF solutions that DO NOT require an external tool

extension UIImage {

    func getExifData() -> CFDictionary? {
        var exifData: CFDictionary? = nil
        if let data = self.jpegData(compressionQuality: 1.0) {
            data.withUnsafeBytes {
                let bytes = $0.baseAddress?.assumingMemoryBound(to: UInt8.self)
                if let cfData = CFDataCreate(kCFAllocatorDefault, bytes, data.count), 
                    let source = CGImageSourceCreateWithData(cfData, nil) {
                    exifData = CGImageSourceCopyPropertiesAtIndex(source, 0, nil)
                }
            }
        }
        return exifData
    }
}

as an example (I have not yet tried this) and this particular example is iOS

1 Like

I have found a few (I’m looking for Mac OS solutions specifically) but the solutions that I came across to modify exif data directly didn’t appear to allow me to access all of the tags I need to, like some IPTC tags.
I did not, however, come across the sample you posted but perhaps that’s because I narrowed my searches to Mac OS solutions only).

Thanks,
Phil

If you want to do the equivalent of a command line process… try this

func shell(_ command: String) -> String {
    let task = Process()
    let pipe = Pipe()

    task.standardOutput = pipe
    task.arguments = ["-c", command]
    task.launchPath = "/bin/bash"
    task.launch()

    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output = String(data: data, encoding: .utf8)!
    return output
}

Thanks for your post, it gave me some great ideas :slight_smile:

I believe UIImage framework isn’t available for Mac OS. However I think ImageIO is something I should explore.

Thanks,
Phil

P.S. Admittedly new to Swift, I’m finding developer documentation to be rather spotty in places. One things I’ll give Xojo is – although much simpler a tool – the documentation is fairly good.)

it is not, which is why I specified that example was for iOS

If code indicates UIxxx for anything it is for iOS only. but if it has NSxxx it “could” be for either, depending on what the NS item references…

CGImageSource is the way to utilize the built-in OS functionality for accessing image meta data.

I would suggest that you look through the meta data that you get to see if the required information is that or not.

Not only will it be faster than a third party app, but it will be more secure and reduce bloat in your application.

Just in case you’re looking to go down this path, I’ve run into issues trying to port this code into a project.

I developed that code in a playground but when I put it in a project it didn’t work. Evidently using Process() and Pipe() – whether with launch() or run() – doesn’t seem to work as it does in a playground.

(If you’ve found otherwise please let me know.)

I have tested the code I posted above in a non-Playground Swift project and with the little testing I did, experienced no issues

edit : a NON-Sandboxed app

I believe the issue has to do with the process exiftool.

By default new macOS projects are Sandboxed, so to call a helper that’s within a Sanbxoed application, you need to use NSTask, if you haven’t already tried that.

I thought that NSTask was deprecated and replaced by Process(). If using NSTask happens to fix the issue I’m having will it still work when signed and notarized for distribution?

Thanks Sam

Apple docs dont say the entire class is deprecated
Certain methods are marked though

https://developer.apple.com/documentation/foundation/nstask

They DO have a statement saying you should write helpers as XPC services instead though

I use NSTask in our Xojo based applications, so it does still work, just make sure you avoid calling ‘[NSFileHandle WaitForDataInBackgroundAndNotify]’ on the pipe as under Catalina this leaks, taking up 100% CPU usage each time.

You’re welcome.

hmmm…

Which is a whole world of pain. I’ve tried and simply couldn’t get a simple example working correctly. I also found very little documentation, and next to no responses in the (now expunged) Apple Developer forums.

… which is distressing as I’m now wondering it the “safe haven” I’m fleeing Xojo for is more or less as problematic as what I’m already faced with.

Well, by leaving Xojo and going all in with Swift, you’re removing Xojo from the equation, so you’re one level closer to the OS vendor.

But you’re giving up x-plat, which to be honest is something I’d recommend you reconsider.

I still use Xojo, but almost everything I do is direct Apple API, which has locked me into a decaying platform. There are so many problems with Apple’s toolbox at the moment, with very little concern over quality or stability, which just amounts to a really worrying experience.

Most macOS apps (even written by Objective-C devs) are littered with version checks (something Apple says you should never do) simply to work this broken API in this OS, that broken API in that OS, undocumented changes which effectively break this.

If I could do what I want to do with x-plat, I’d seriously wiggle out of Apple exclusivity at the moment.

Apple REALLY needs to do another Snow Leopard that is bug fix & speed improvements ONLY

Yeah, they need to. But I doubt they will until their sales take a serious hit and the stock price crashes. These last few years have proved that enough people don’t care about broken software that Apple ships, cheapening devices or a declining App industry.

Unless… The average consumer does, but a bean counter has found ways of increasing “profit” while sales decline.