拡張子 or MIME から UTI を取得 Cocoa AppleScript [01] with Swift

ASOC[01](CatchImage)

ASOC [01] 【macOS11以降限定】拡張子 or MIME から UTI を取得
 macOS11.0 (iOS14) 以降利用可能な新 "UniformTypeIdentifiers" framework の UTType クラスにて、拡張子 or MIME から UTI を取得!
 UTI (Uniform Type Identifier) は macOS10 (iOS13) 以前 CoreServices や MobileCoreServices などを利用して取得していましたが 非推奨となったため、その代替フレームワークが "UniformTypeIdentifiers" となります。
 kUTTypePlainText のような以前のフレームワークで参照できた kUTType は CFString で宣言されており、 Cocoa の NSString クラスとの相互変換が面倒でした。
 筆者もCFStringが問題で 拡張子からUTI取得を断念し、(拡張子を含めた)ファイルからUTIを取得するAppleScriptを紹介した過去が...

  コマンドライン版ですが、同機能の Swift コードと Cocoa Objective-C コードを追記! 





 Cocoa AppleScript [01] 【macOS11以降限定】拡張子 or MIME から UTI を取得 

ASOC[01] Png01

 まず、[アプリケーション]-[ユーティリティ] フォルダ内の「スクリプトエディタ.app」を起動して、左下の [新規書類]ボタン をクリック。


 AppleScriptコードを貼り付けて、[command]+[R] で即!テスト可能 

(1) 以下のAppleScriptコード表示部にマウスのカーソルを重ねるかクリックすると 右上に[コードをコピーする]ボタンが表示されるため、クリックしてコードをコピー。

(2) スクリプトエディタ画面内をクリックすると、画面上部でキャレットが点滅しているはずです。 この箇所にコードを挿入するためクリック後、 [command]+[V] でコードを貼り付け。

(3) [command]+[R] で、即!テスト可能

(4) 拡張子 "xlsm" あるいは MIME "application/pdf" を置き換えて [command]+[R] で即反映 (MIMEが不明なら、「pdf wiki」で検索すれば、wikipedia画面の右上に表示)

(5) 必要なら、 [command]+[S] にて(AppleScriptコードを)名前を付けて保存



-- Copyright 2021- ataruchi. [ https://twitter.com/ataruchi ]
-- 拡張子 or MIME から、UTI (Uniform Type Identifier) を取得 with Cocoa AppleScript (with ASOC)
-- 新 "UniformTypeIdentifiers" framework 利用のため、macOS11[Big Sur]以降 限定
use AppleScript version "2.7" --But macOS11〜 for use new "UniformTypeIdentifiers" framework
use scripting additions
use framework "Foundation"
use framework "UniformTypeIdentifiers" --New framework for UTI, macOS11.0+ [Big Sur or later]
property UTType : a reference to current application's UTType --new Class, macOS11.0+
--property NSString : a reference to current application's NSString

set theResult to getUtiFromExt("xlsm") --マクロ付きExcel、拡張子
set theResult to theResult & return --改行コードを挿入
set theResult to (theResult & getUtiFromMime("application/pdf")) --pdf、MIME
return theResult

on getUtiFromExt(theExt) --macOS11 or later only, for use "UniformTypeIdentifiers" framework
	set theUTType to UTType's typeWithFilenameExtension:theExt --create UTTyp's object
	if theUTType = (missing value) then return ("fail to search UTI: " & theExt)
	return (theUTType's identifier as string)
end getUtiFromExt

on getUtiFromMime(theMime) --macOS11 or later only, for use "UniformTypeIdentifiers" framework
	--set theMimeStr to NSString's stringWithString:theMime --create NSString's object
	--set theUTType to UTType's typeWithMIMEType:theMimeStr --create UTTyp's object
	set theUTType to UTType's typeWithMIMEType:theMime --create UTTyp's object
	if theUTType = (missing value) then return ("fail to search UTI: " & theMime)
	return (theUTType's identifier as string)
end getUtiFromMime

 [command] + [Q] にて スクリプトエディタ を終了し、AppleScriptコードを再利用しなければ ダイアログ左下の [削除] ボタンをクリック!
 既に最終のコードを保存済みならダイアログは表示されません。 また、ダイアログから名前を付けて保存することも可能。


 VBAとは異なり AppleScript に関しては初心者のため、不具合があればコメント等で教えて頂けると嬉しいです。



 勉強中の Swift コード(コマンドライン)版 

 Swiftコードのコンパイルには Xcode (無料)のインストールが必要ですが、40GB〜42GBの空き容量がないと App Storeからはインストールできない らしい。
(Apple Developers公式サイトからダウンロードすれば) 12GB ほどの最小版をインストール可能だそうです(Web検索すれば、出てくるはず)
 いずれにしろ、インストールするのであれば 空き容量に 注意してください!

 【ダウンロードリンクあり】 getUtiFromExt(main.swift) getUtiFromMime(main2.swift) 


//
//  main.swift
//  getUtiFromExt
//
//  Created by ataruchi on 2021/11/07.
//

import Foundation
import UniformTypeIdentifiers //New framework for UTI, macOS11.0+ [Big Sur or later]

if let argument = CommandLine.arguments.dropFirst().first {
    let ext: String = argument

    if let str = UTType.init(filenameExtension: ext) {
        print(str)
    }
    else {
        print("fail to search UTI: \(argument)")
    }
}

 上記 "main.swift" ファイルのダウンロードは  こちらから! 
上記リンクを右クリックして「リンク先のファイルをダウンロード」等を選択してダウンロード可能。 ( "Google Chrome" ブラウザの場合、上記リンクを右クリックして「名前を付けてリンク先を保存」を選択してダウンロード )
 (注) [ Unicode(UTF-8) 、改行コードは LF ] ファイル置き場として、筆者の旧ブログを利用


//
//  main2.swift
//  getUtiFromMime
//
//  Created by ataruchi on 2021/11/07.
//

import Foundation
import UniformTypeIdentifiers //New framework for UTI, macOS11.0+ [Big Sur or later]

if let argument = CommandLine.arguments.dropFirst().first {
    let mime: String = argument

    if let str = UTType.init(mimeType: mime) {
        print(str)
    }
    else {
        print("fail to search UTI: \(argument)")
    }
}

 上記 "main2.swift" ファイルのダウンロードは  こちらから! 
上記リンクを右クリックして「リンク先のファイルをダウンロード」等を選択してダウンロード可能。 ( "Google Chrome" ブラウザの場合、上記リンクを右クリックして「名前を付けてリンク先を保存」を選択してダウンロード )
 (注) [ Unicode(UTF-8) 、改行コードは LF ] ファイル置き場として、筆者の旧ブログを利用



 「ターミナル.app」での コンパイル方法 

 ダウンロードした "main.swift" と "main2.swift" の2ファイルを、ホームフォルダ( /Users/username/ )へコピーしておきます。 (注)usernameはユーザーによって異なります
 コンパイルして Unix実行ファイル( getUtiFromExt と GetUtiFromMime )ができれば、上記2ファイルは別のフォルダに移動か 削除してもかまいません。


ASOC[01] Png02


cd $home

swiftc -o getUtiFromExt main.swift

swiftc -o getUtiFromMime main2.swift

 Unixコマンドを実行する場合 問題なければ 次行に % のみ表示され、エラー発生時のみメッセージが表示されます。 覚えておいてください。
 慣れない方はコマンド文字列を コピー&ペースト 後 [return]キーを押下、 [return] キーのみを叩くと、 % のみの行を表示。

(1) [アプリケーション]-[ユーティリティ] フォルダ内の「ターミナル.app」を起動。

(2) 通常、ホームディレクトリ(ホームフォルダ)がカレントディレクトリで開くはずですが、念のため cd $home [return] にて移動。

(3) swiftc -o getUtiFromExt main.swift [return] にて main.swift をコンパイルし、「getUtiFromExt」Unix実行ファイルを作成。

(4) swiftc -o getUtiFromMime main2.swift [return] にて main2.swift をコンパイルし、「getUtiFromMime」Unix実行ファイルを作成。

 "Finder" でホームフォルダ内に getUtiFromExt と GetUtiFromMime があるか確認! 無ければ、もう一度実行してみてください。



 「ターミナル.app」での 実行方法 

 引き続き、「ターミナル.app」での作業となります!



/Users/wito/getUtiFromExt xlsm
org.openxmlformats.spreadsheetml.sheet.macroenabled

/Users/wito/getUtiFromExt swift
public.swift-source

/Users/wito/getUtiFromMime 'application/pdf'
com.adobe.pdf

 筆者のホームディレクトリ(フォルダ)は /Users/wito/ で、太字の部分は ユーザー毎に異なります。
 /Users/wito/getUtiFromExt あるいは /Users/wito/getUtiFromMime を [command]+[C] でコピーしておくと、入力ミスが減るのでオススメです。
 [command]+[V] で貼り付けして「カーソルキーの ▶︎ 」を叩いた後に [space]キーを叩き、残りの拡張子やMIME文字列を入力後、最後に [return]キーを押下。
 ( 空白文字 や ややこしい文字を含む場合は、 'application/pdf' あるいは "application/pdf" のように括る必要あり )

 次行に UTI が表示されます!

【注意】パスが通っているディレクトリに Unix実行ファイル をコピー(移動でも可)すれば 先頭の /Users/wito/ の部分を入力する必要はありませんが、/usr/local/bin/ デイレクトリが macOS11 では無くなっていたため 止めました。 適切なデイレクトリにコピーできる方は、コンパイル時の swiftc -o の後のパラメータで任意(ただし、Unixコマンド等と重複しないこと)に Unix実行ファイル名を変えれば、入力が楽になることでしょう!


 最後に [command]+[Q] などで、「ターミナル.app」アプリを忘れずに終了してください!



 【参考】(Cocoa) Objective-C コード(コマンドライン)版 

 Cocoa AppleScript に置き換えるのであれば Objective-C コードの方が分かりやすいのだけど、最近は Swift のサンプルコードばかりで...
Swift の String と Cocoa (Objective-C) の NSString は全く別物のクラスで、戸惑うことがあります。 Swift の場合、両方使えるし...
 ASOC 完全対応なのは Objective-C で間違いなくて、今回 同じ UTType クラスでも Swift と Objective-C(つまり ASOC)でメソッド名や返り値が微妙に違っていてややこしかった。
 Objective-C は昔ちょっとかじったことがあって何となく理解できるのですが、時代のながれなので Swift をもっと勉強しないといけないようです!

 現在は ①Swiftサンプルコード → ②Cocoa Objective-Cコード → ③Cocoa AppleScriptコード に変換してるんですが、慣れれば ① → ③ 対応できるか 不安かも?

 main.m [ getUtiFromExtObjC ] 


//
//  main.m
//  getUtiFromExtObjC
//
//  Created by ataruchi on 2021/11/08.
//
//「ターミナル.app」でのコンパイルは、以下で可能!
//gcc -o suti main.m -framework Foundation -framework UniformTypeIdentifiers

#import <Foundation/Foundation.h>
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        if (argc < 2) {
            printf("No parameter.\n"); //引数なし
            return 0;
        }
        
        // [arguments objectAtIndex:0] はコマンド名で、objectAtIndex:1 以降が引数
        NSArray *arguments = [[NSProcessInfo processInfo] arguments];
        NSString *ext = [NSString stringWithString:[arguments objectAtIndex:1]];
        NSString *uti;

        if ((uti = [[UTType typeWithFilenameExtension:ext] identifier])) {
            printf("%s\n",[uti UTF8String]); //UTI取得 成功
        }
        else {
            printf("fail to search UTI: %s\n",[ext UTF8String]); //UTI取得 失敗
        }
        
        return 0;
    }
}

 main2.m [ getUtiFromMimeObjC ] 


//
//  main2.m
//  getUtiFromMimeObjC
//
//  Created by ataruchi on 2021/11/08.
//
//「ターミナル.app」でのコンパイルは、以下で可能!
//gcc -o sutimime main2.m -framework Foundation -framework UniformTypeIdentifiers

#import <Foundation/Foundation.h>
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        if (argc < 2) {
            printf("No parameter.\n"); //引数なし
            return 0;
        }
        
        // [arguments objectAtIndex:0] はコマンド名で、objectAtIndex:1 以降が引数
        NSArray *arguments = [[NSProcessInfo processInfo] arguments];
        NSString *mime = [NSString stringWithString:[arguments objectAtIndex:1]];
        NSString *uti;
        
        if ((uti = [[UTType typeWithMIMEType:mime] identifier])) {
            printf("%s\n",[uti UTF8String]); //UTI取得 成功
        }
        else {
            printf("fail to search UTI: %s\n",[mime UTF8String]); //UTI取得 失敗
        }
        
        return 0;
    }
}


 UTI は Mac で プログラミング をする上で重要で、ファイル選択ダイアログでのファイル種別限定や ドラッグ&ドロップ実装時の登録にて 必要!
 macOS11 Big Sur (iOS14) 以降限定とはなりますが、直接 UTI を指定するのではなく 「拡張子」や「MIME」を指定して コード内部で間接的に UTI を取得するとスマートだと思います。
 旧フレームワークの CoreServices や MobileCoreServices の一部は既に非推奨のため、今後利用できなくなるはずです。 早めに UniformTypeIdentifiers フレームワークに対応しておけば、この先安心かと...

 早く macOS12 が安定すると良いですね。(筆者は、それまで macOS11.6.1 を使用) 愛用の Mac mini 2014 でも遅くなりませんように! macOS11 では intelチップ以外のMacで AppleScript が低速なコアのみで実行されるというバグ? があったため、 macOS12 の AppleScript 実行速度にビックリするそうですよ! intelチップのMacでも少々速くなるらしいです。







Macブログ ランキング アイコン
最後まで読んでいただき、ありがとうございます。 また、お越しくださいませ。
// アタル
For follow LINE Reader Group!Subscribe to this blog on Feedly!

Previous Post
No Comment
Add Comment
comment url