FileMaker Proデータベースのオブジェクトフィールド上に生成したNSImageを入れるAppleScriptです。FileMaker Pro v19.2.1.14+macOS 11.2betaで動作確認しています。とくに環境依存は行わないはずです。
FileMaker Proのオブジェクトフィールドは一種のBlobで、画像やPDF、機械学習モデル(mlmodel)、他のデータベース(.fmp12)を突っ込んだりできます。
ところが、AppleScriptでNSImageを作成し、その結果をFileMaker Proのオブジェクトフィールドにそのまま入れることはできません。エラーになります。
方法1:AppleScript側でNSImageをクリップボードに入れ、FileMaker Pro側でクリップボードの内容をフィールドに入れる
この方法は、FileMaker Pro側が最前面にある場合には問題なかったのですが、FileMaker Proが最前面にない場合には問題が発生する可能性があります。実際に試して成功したのですが、クリップボード経由でAppleScript側とFileMaker Script側がデータをやりとりすることになり、膨大なデータを処理した場合の信頼性に疑問がつきました。
方法2:AppleScript側でNSImageをクリップボードに入れ、クリップボードの内容を標準命令で画像に変換したのち、普通にオブジェクトフィールドに入れる
各種アプリケーションが認識する「画像データ」に明示的に変換するためには、ファイルに書き出すのが確実ですが、クリップボード経由で「画像」に変換するのが安全策です。
NSImageをJPEGデータに変換して、その結果をそのままオブジェクトフィールドに突っ込んでもエラーになりました。これが最有力な案だと思っていたので、うまく動かなかったのは残念でした。
そこで、安全策をとって(仕方なく)クリップボード経由でNSImageを画像に変換することになりました。このままでは方法1と大差ないように見えますが、実際にはAppleScriptでクリップボードにNSImageを入れて、AppleScriptでクリップボード内容を画像として評価して取得するという処理を行っています。
スピードや確実さを考慮すると、なるべくクリップボード経由の処理は行いたくないので、対策は考えておきたいところです。クリップボードや一時ファイルを経由させるよりも、極力メモリ上で対処したいところです。
▲ユーザーにAppleScriptの実行権限を与えておくとAppleScriptによる制御が有効になるFileMaker Pro
▲テキストフィールド「originalString」から文字情報を取り出して、オブジェクトフィールド「imageStore」にAppleScriptで生成した画像を突っ込む
▲実行後(Mac mini 2014で処理に初回で0.1秒ほど。2回目以降は1桁速くなる) AppleScript側で画像を作成してフィルタ処理をかけたりして、好き放題に合成してFileMaker DB上のフィールドに設定できる。バーコードやQRコードをAppleScript側で生成して設定したり、PDFをレンダリングした画像を設定できるのは便利
AppleScript名:NSImage to FM Object Field v2.scptd |
— Created 2020-12-20 by Takaaki Naganoya — 2020 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "AppKit" property fmBundleID : "" set fmBundleID to getBundleID() of me –DB側から画像化するテキストを取得する using terms from application "FileMaker Pro" tell application ID fmBundleID tell window 1 tell current record set aText to field "originalString" end tell end tell end tell end using terms from set aWidth to 500.0 –幅 set aHeight to 200.0 –高さ set fillColor to current application’s NSColor’s blackColor –塗り色 set drawColor to current application’s NSColor’s whiteColor –文字色 set {xPos, yPos} to {1, 5} –新規画像を作成して背景を塗る set aImage1 to makeImageWithFilledColor(aWidth, aHeight, fillColor) of me –画像に文字を塗る set aImage2 to drawStringsOnImage(aImage1, aText, "HiraKakuStd-W8", 36.0, drawColor, xPos, yPos) of me ( my restoreClipboard:{aImage2})using terms from scripting additions set tmpImg to the clipboard as JPEG picture end using terms from –DBに画像を設定する using terms from application "FileMaker Pro" tell application ID fmBundleID tell window 1 tell current record set field "imageStore" to tmpImg end tell end tell end tell end using terms from –画像のうえに指定の文字を描画して画像を返す on drawStringsOnImage(anImage, aText, aFontName, aPoint, drawColor, xPos, yPos) set aString to current application’s NSString’s stringWithString:aText set aDict to current application’s NSDictionary’s dictionaryWithObjects:{current application’s NSFont’s fontWithName:aFontName |size|:aPoint, drawColor} forKeys:{current application’s NSFontAttributeName, current application’s NSForegroundColorAttributeName} –文字描画開始 anImage’s lockFocus() aString’s drawAtPoint:(current application’s NSMakePoint(xPos, yPos)) withAttributes:aDict anImage’s unlockFocus() –文字描画ここまで return anImage end drawStringsOnImage –指定サイズの画像を作成し、背景を指定色で塗る on makeImageWithFilledColor(aWidth, aHeight, fillColor) –Imageの作成 set anImage to current application’s NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight)) –描画開始 anImage’s lockFocus() set theRect to {{x:0, y:0}, {width:aWidth, height:aHeight}} set theNSBezierPath to current application’s NSBezierPath’s bezierPath theNSBezierPath’s appendBezierPathWithRect:theRect fillColor’s |set|() –色設定 theNSBezierPath’s fill() –ぬりつぶし anImage’s unlockFocus() –描画ここまで return anImage –画像を返す end makeImageWithFilledColor on getBundleID() –FileMaker Pro 18 set fmProID to "com.filemaker.client.pro12" –FileMaker Pro 18 Advanced set fmProADVID to "com.filemaker.client.advanced12" using terms from application "FileMaker Pro" tell current application set aName to name end tell end using terms from if aName contains "Advanced" then return fmProADVID else return fmProID end if end getBundleID –クリップボードに内容を設定する on restoreClipboard:theArray — get pasteboard set thePasteboard to current application’s NSPasteboard’s generalPasteboard() — clear it, then write new contents thePasteboard’s clearContents() thePasteboard’s writeObjects:theArray end restoreClipboard: |