拡張子 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) 以前 CoreServicesMobileCoreServices などを利用して取得していましたが 非推奨となったため、その代替フレームワークが "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実行ファイル( getUtiFromExtGetUtiFromMime )ができれば、上記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" でホームフォルダ内に getUtiFromExtGetUtiFromMime があるか確認! 無ければ、もう一度実行してみてください。



 「ターミナル.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 を取得するとスマートだと思います。
 旧フレームワークの CoreServicesMobileCoreServices の一部は既に非推奨のため、今後利用できなくなるはずです。 早めに 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