# Calling exiftool with Process() in Swift

**URL:** <https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631>\
**Category:** General Programming\
**Created:** [15 June 2020 03:17 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631 "2020-06-15T03:17:00Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![psb87](https://ifnotnil.com/letter_avatar_proxy/v4/letter/p/fbc32d/32.png) [@psb87](https://ifnotnil.com/u/psb87)\
**Post date:** [15 June 2020 03:17 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/1 "2020-06-15T03:17:00Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![DaveS](https://ifnotnil.com/user_avatar/ifnotnil.com/daves/32/79_2.png) [@DaveS](https://ifnotnil.com/u/DaveS)\
**Post date:** [15 June 2020 13:59 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/2 "2020-06-15T13:59:48Z")

</div>

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)

---

<div class="post-metadata">

**Author:** ![psb87](https://ifnotnil.com/letter_avatar_proxy/v4/letter/p/fbc32d/32.png) [@psb87](https://ifnotnil.com/u/psb87)\
**Post date:** [15 June 2020 14:32 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/3 "2020-06-15T14:32:43Z")

</div>

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
```

---

<div class="post-metadata">

**Author:** ![DaveS](https://ifnotnil.com/user_avatar/ifnotnil.com/daves/32/79_2.png) [@DaveS](https://ifnotnil.com/u/DaveS)\
**Post date:** [15 June 2020 14:33 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/4 "2020-06-15T14:33:55Z")

</div>

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

```auto
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

---

<div class="post-metadata">

**Author:** ![psb87](https://ifnotnil.com/letter_avatar_proxy/v4/letter/p/fbc32d/32.png) [@psb87](https://ifnotnil.com/u/psb87)\
**Post date:** [15 June 2020 14:38 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/5 "2020-06-15T14:38:47Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![DaveS](https://ifnotnil.com/user_avatar/ifnotnil.com/daves/32/79_2.png) [@DaveS](https://ifnotnil.com/u/DaveS)\
**Post date:** [15 June 2020 14:45 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/6 "2020-06-15T14:45:22Z")

</div>

> [@psb87](#):
>
> `/usr/local/bin/exiftool`

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

```swift
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 🙂

---

<div class="post-metadata">

**Author:** ![psb87](https://ifnotnil.com/letter_avatar_proxy/v4/letter/p/fbc32d/32.png) [@psb87](https://ifnotnil.com/u/psb87)\
**Post date:** [15 June 2020 14:56 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/7 "2020-06-15T14:56:48Z")

</div>

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.)_

---

<div class="post-metadata">

**Author:** ![DaveS](https://ifnotnil.com/user_avatar/ifnotnil.com/daves/32/79_2.png) [@DaveS](https://ifnotnil.com/u/DaveS)\
**Post date:** [15 June 2020 15:09 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/8 "2020-06-15T15:09:52Z")

</div>

> [@psb87](#):
>
> I believe UIImage framework isn’t available for Mac OS.

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…

---

<div class="post-metadata">

**Author:** ![samRowlands](https://ifnotnil.com/user_avatar/ifnotnil.com/samrowlands/32/121_2.png) [@samRowlands](https://ifnotnil.com/u/samRowlands)\
**Post date:** [16 June 2020 01:55 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/9 "2020-06-16T01:55:52Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![psb87](https://ifnotnil.com/letter_avatar_proxy/v4/letter/p/fbc32d/32.png) [@psb87](https://ifnotnil.com/u/psb87)\
**Post date:** [17 June 2020 02:39 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/10 "2020-06-17T02:39:59Z")

</div>

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.)

---

<div class="post-metadata">

**Author:** ![DaveS](https://ifnotnil.com/user_avatar/ifnotnil.com/daves/32/79_2.png) [@DaveS](https://ifnotnil.com/u/DaveS)\
**Post date:** [17 June 2020 04:32 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/11 "2020-06-17T04:32:10Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![psb87](https://ifnotnil.com/letter_avatar_proxy/v4/letter/p/fbc32d/32.png) [@psb87](https://ifnotnil.com/u/psb87)\
**Post date:** [17 June 2020 12:46 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/12 "2020-06-17T12:46:11Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![samRowlands](https://ifnotnil.com/user_avatar/ifnotnil.com/samrowlands/32/121_2.png) [@samRowlands](https://ifnotnil.com/u/samRowlands)\
**Post date:** [18 June 2020 01:30 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/13 "2020-06-18T01:30:58Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![psb87](https://ifnotnil.com/letter_avatar_proxy/v4/letter/p/fbc32d/32.png) [@psb87](https://ifnotnil.com/u/psb87)\
**Post date:** [18 June 2020 03:14 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/14 "2020-06-18T03:14:49Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![npalardy](https://ifnotnil.com/user_avatar/ifnotnil.com/npalardy/32/10_2.png) [@npalardy](https://ifnotnil.com/u/npalardy)\
**Post date:** [18 June 2020 03:37 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/15 "2020-06-18T03:37:47Z")

</div>

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

[https://developer.apple.com/documentation/foundation/nstask](https://developer.apple.com/documentation/foundation/nstask)

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

---

<div class="post-metadata">

**Author:** ![samRowlands](https://ifnotnil.com/user_avatar/ifnotnil.com/samrowlands/32/121_2.png) [@samRowlands](https://ifnotnil.com/u/samRowlands)\
**Post date:** [18 June 2020 03:47 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/16 "2020-06-18T03:47:10Z")

</div>

> [@psb87](#):
>
> If using NSTask happens to fix the issue I’m having will it still work when signed and notarized for distribution?

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.

> [@psb87](#):
>
> Thanks Sam

You’re welcome.

> [@npalardy](#):
>
> Apple docs dont say the entire class is deprecated

hmmm…

> [@npalardy](#):
>
> They DO have a statement saying you should write helpers as XPC services instead though

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.

---

<div class="post-metadata">

**Author:** ![psb87](https://ifnotnil.com/letter_avatar_proxy/v4/letter/p/fbc32d/32.png) [@psb87](https://ifnotnil.com/u/psb87)\
**Post date:** [18 June 2020 03:55 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/17 "2020-06-18T03:55:26Z")

</div>

… 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.

---

<div class="post-metadata">

**Author:** ![samRowlands](https://ifnotnil.com/user_avatar/ifnotnil.com/samrowlands/32/121_2.png) [@samRowlands](https://ifnotnil.com/u/samRowlands)\
**Post date:** [18 June 2020 04:06 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/18 "2020-06-18T04:06:00Z")

</div>

> [@psb87](#):
>
> 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.

---

<div class="post-metadata">

**Author:** ![npalardy](https://ifnotnil.com/user_avatar/ifnotnil.com/npalardy/32/10_2.png) [@npalardy](https://ifnotnil.com/u/npalardy)\
**Post date:** [18 June 2020 04:08 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/19 "2020-06-18T04:08:31Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![samRowlands](https://ifnotnil.com/user_avatar/ifnotnil.com/samrowlands/32/121_2.png) [@samRowlands](https://ifnotnil.com/u/samRowlands)\
**Post date:** [18 June 2020 04:44 UTC](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631/20 "2020-06-18T04:44:55Z")

</div>

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.

[Next page](https://ifnotnil.com/t/calling-exiftool-with-process-in-swift/631.md?page=2)
