あらたに電子書籍を刊行しました。「つたわる資料のつくりかた」。資料を作るすべての人に向けた、資料作成の基礎を解説する本です。Amazon Kindleで配信中。
クリップボードの画像を指定色でモノクロ化してクリップボードへ v3
クリップボードに入れた画像を、グレースケール化したあとに指定の色のベタ塗り画像とフィルタで合成し、単色の色付き画像に変換するAppleScriptです。
資料に掲載する画像の情報量を減らすために、単色画像に変換したいと考えました。Photoshopだと2つのレイヤーの重ね合わせで指定して処理するような内容です。ただ、もうPhotoshopにできるぐらいのことの大部分は、AppleScriptだけで単独でできてしまうのが2022年的な状況です。
アプリケーションを使わずに処理するためには、CIFilterを用いて画像処理して、単色画像にすることになります。
CIFilterにもいろいろな画像フィルタ機能が用意されているわけで、ここから「どのフィルタを使うか」選ぶことになります。
# フィルタが200種類ぐらいあるんですけど!!
このような場合のために、FileMaker Proで作った「FileMaker Pro PowerPack」だとひととおりのCIFilterをサンプルデータで処理できるようにしておきました。
FileMaker Proのデータベース上にサンプルデータをコピー&ペーストしておけば、DB上でフィルタ処理してどのような処理をしてくれるかがわかります。
いやーー、作っておいてよかったー。「なんでこんなにフィルタ処理ばっかりあるんだよ!」的な話がありましたが、こうして実際に役立つわけで。フィルタの名称、編集できるテストデータ、処理結果が表示されるところまで……「動かせる資料」的なものに仕上がっています>FileMaker Pro PowerPack
ひととおりAppleScriptを作ってみて、いろいろ調整してみたところ……調整し切れなかったので、edama2さんに相談して(送りつけて)こんな感じに仕上がりました。
これでなんとか動くはずなのに、なぜこうなるのか。。。CIFilterを実際に日常的に使うツールで使ったのは実はこれが最初だったので、意外な挙動に割と困りました。
▲画面上の指定範囲のスクリーンショットを撮ってクリップボードへ
▲ScriptをmacOS標準搭載のスクリプトメニューから呼び出すことを前提に作った。
▲クリップボードの内容をペーストすると、単色化された画像が出力される
AppleScript名:クリップボードの画像を指定色でモノクロ化してクリップボードへ v3.scpt |
— – Created by: Takaaki Naganoya – Created on: 2022/03/11 — – Copyright © 2022 Piyomaru Software, All Rights Reserved – v2 Takaaki Naganoya : マスクが1/4の大きさになったり2倍になったりしていた – v3 edama2:上記の問題に対処。クリーンナップ — use AppleScript version "2.7" use framework "AppKit" use framework "CoreImage" use framework "Foundation" use scripting additions on run my main() end run on main() –クリップボード内のデータをNSImageとして取得 set sourceImg to my getClipboardASImage() # 色指定 set aColor to my makeNSColorFromRGBA255val(252, 2, 128, 255) # 同じ大きさの塗りつぶし画像を作成 tell current application’s NSImage’s alloc() tell initWithSize_(sourceImg’s |size|()) lockFocus() aColor’s |set|() set aRect to current application’s NSMakeRect(0, 0, its |size|()’s width, its |size|()’s height) current application’s NSBezierPath’s fillRect:aRect unlockFocus() set fillImg to it end tell end tell # NSImage –> CIimage set sourceImage to my convNSImageToCIimage(sourceImg) set fillImage to my convNSImageToCIimage(fillImg) set newImage to my filterImage2(fillImage, sourceImage) my restoreClipboard({newImage}) end main on filterImage2(fillImage, sourceImage) set redValue to 0.295719844358 set greenValue to 0.295719844358 set blueValue to 0.295719844358 set alphaVlaue to 1.0 set aCIColor to current application’s CIColor’s alloc()’s initWithRed:redValue green:greenValue blue:blueValue alpha:alphaVlaue tell current application’s CIFilter — CIFilter(モノクロ化) tell filterWithName_("CIColorMonochrome") setDefaults() setValue_forKey_(sourceImage, "inputImage") setValue_forKey_(aCIColor, "inputColor") set filteredImage to valueForKey_("outputImage") end tell — CIFilter(モノクロ化) tell filterWithName_("CIAdditionCompositing") setDefaults() setValue_forKey_(fillImage, "inputImage") setValue_forKey_(filteredImage, "inputBackgroundImage") set theCIImage to valueForKey_(current application’s kCIOutputImageKey) end tell end tell # CIImage –> NSImage set imageRep to current application’s NSCIImageRep’s alloc()’s initWithCIImage:theCIImage set rNSImage to current application’s NSImage’s alloc()’s initWithSize:(imageRep’s |size|()) rNSImage’s addRepresentation:imageRep return rNSImage end filterImage2 # NSImage –> CIimage on convNSImageToCIimage(aNSImage) set tiffDat to aNSImage’s TIFFRepresentation() set aRep to current application’s NSBitmapImageRep’s imageRepWithData:tiffDat set newImg to current application’s CIImage’s alloc()’s initWithBitmapImageRep:aRep return newImg end convNSImageToCIimage — クリップボードの内容をNSImageとして取り出して返す on getClipboardASImage() set thePasteboard to current application’s NSPasteboard’s generalPasteboard() set theAttributedStringNSArray to thePasteboard’s readObjectsForClasses:({current application’s NSImage}) options:(missing value) set theNSImage to theAttributedStringNSArray’s objectAtIndex:0 return theNSImage end getClipboardASImage on restoreClipboard(theArray as list) set thePasteboard to current application’s NSPasteboard’s generalPasteboard() thePasteboard’s clearContents() thePasteboard’s writeObjects:theArray end restoreClipboard on makeNSColorFromRGBA255val(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer) set aRedCocoa to (redValue / 255) as real set aGreenCocoa to (greenValue / 255) as real set aBlueCocoa to (blueValue / 255) as real set aAlphaCocoa to (alphaValue / 255) as real set aColor to current application’s NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa return aColor end makeNSColorFromRGBA255val |
指定のPDFの本文テキストの文字数をカウント
指定のPDFの本文テキストを取り出し、文字数をカウントするAppleScriptです。
▲「AppleScriptによるWebブラウザ自動操縦ガイド」の文字数をカウントしようとした
300ページを超える、わりと大きな本のPDFデータから文字を取り出したので、それなりの文字数になりました。つまり、Cocoaの有効活用を考えないとデータサイズ的につらそうなデータ量になることが予想されました。
当初、(文字処理については)Cocoaの機能をあまり活用しないv2を作ったものの、処理にM1 Mac miniで30秒ほどかかりました。すべてNSStringのまま(AppleScriptのstringに型変換せずに)処理してみたら、案の定、大幅に処理が高速化され6秒あまりで完了。
ただし、両者でカウントした文字数が1万文字ぐらい違っていたので、(PDFから取得した文字の)Unicode文字のNormalize方式を変更したところ、両者で同じ結果になりました。また、処理速度に改変前から大幅な変化はありませんでした。
文字数を数えるという処理だとさすがにデータ数が膨大になるため、NSStringで処理したほうがメリットが大きいようです。
# あれ? 5文字ぐらい違う、、、、絵文字の部分か?
AppleScript名:指定のPDFの本文テキストの文字数を数える v2 |
use AppleScript version "2.8" –macOS 12 or later use framework "Foundation" use framework "PDFKit" –Comment Out under macOS 11 –use framework "Quartz"–Uncomment under macOS 11 use scripting additions script spd property cRes : "" property cList : {} end script set (cRes of spd) to "" set (cList of spd) to {} set (cRes of spd) to getTextFromPDF(POSIX path of (choose file of type {"pdf"})) of me set (cList of spd) to current application’s NSArray’s arrayWithArray:(characters of (cRes of spd)) set cLen to (cList of spd)’s |count|() return cLen –> 256137 (24.763sec) on getTextFromPDF(posixPath) set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping()) as text end getTextFromPDF |
AppleScript名:指定のPDFの本文テキストの文字数を数える v3 |
use AppleScript version "2.8" –macOS 12 or later use framework "Foundation" use framework "PDFKit" –Comment Out under macOS 11 –use framework "Quartz"–Uncomment under macOS 11 use scripting additions script spd property cRes : "" property cList : {} end script set (cRes of spd) to "" set (cList of spd) to {} set (cRes of spd) to getTextFromPDF(POSIX path of (choose file of type {"pdf"})) of me set cLen to (cRes of spd)’s |length| return cLen as anything –> 256142 (6.28 sec) on getTextFromPDF(posixPath) set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping()) end getTextFromPDF |
わずかとはいえ、違いが出ていることは確かなので、1つのPDFに対して2つの処理方法でテキストを取り出して、それを配列に入れて集合演算して差分をとってみました。M1でも処理に1分少々かかりました。こういう処理は、M1 MaxでもM1 Ultraでも所要時間は変わらないことでしょう(逆にM1の方が処理時間が短い可能性まである)。
どうやら改行コードの解釈で文字数カウント結果に違いが出たようです。
AppleScript名:テキストの抽出方法による文字数の相違チェック.scptd |
use AppleScript version "2.8" –macOS 12 or later use framework "Foundation" use framework "PDFKit" –Comment Out under macOS 11 –use framework "Quartz"–Uncomment under macOS 11 use scripting additions script spd property cRes : "" property cList : {} end script set (cRes of spd) to "" set (cList of spd) to {} set docPath to POSIX path of (choose file of type {"pdf"}) set (cRes of spd) to getTextFromPDF1(docPath) of me set (cList of spd) to characters of (cRes of spd) set anArray to current application’s NSArray’s arrayWithArray:(cList of spd) set bStr to getTextFromPDF2(docPath) of me set bArray to current application’s NSMutableArray’s new() set bLen to (bStr’s |length|) as anything repeat with i from 0 to (bLen – 1) set tmpStr to (bStr’s substringWithRange:(current application’s NSMakeRange(i, 1))) (bArray’s addObject:(tmpStr)) end repeat set aRes to diffLists(anArray, bArray) of me set bRes to diffLists(bArray, anArray) of me return {aRes, bRes} on getTextFromPDF1(posixPath) set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping()) as text end getTextFromPDF1 on getTextFromPDF2(posixPath) set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping()) end getTextFromPDF2 –1D List同士のdiffを計算する on diffLists(aList, bList) set aSet to current application’s NSMutableSet’s setWithArray:aList set bSet to current application’s NSMutableSet’s setWithArray:bList set aRes to calcSetDifference(aSet, bSet) of me return aRes end diffLists –2つのNSMutableSetの補集合を求める on calcSetDifference(aSet, bSet) aSet’s minusSet:bSet –補集合 set aRes to aSet’s allObjects() as list return aRes end calcSetDifference |
macOS 12のスクリプトエディタで、Context Menu機能にバグ
「AppleScriptによるWebブラウザ自動操縦ガイド」に添付している「Piyomaru Context Menu Assistant」。
スクリプトエディタのコンテクストメニューからAppleScriptを呼び出せるスクリプトエディタの機能を利用して、macOS標準装備の貧相で使い物にならないScriptを全部捨てて、そのかわりに強力なものをインストールするものです。
▲macOS標準でインストールされている、Script Assistant。古い、使えない、役に立たないの3拍子
▲Piyomaru Softwareが書籍のオマケでご提供しているPiyomaru Script Assistant(macOS 10.14.6)
▲macOS 12.3 beta 5上で表示したPiyomaru Script Assistant。メニュー項目(≒ファイル名)が2重に表示されている(macOS 12.3 beta5)
このScript Assistantが、macOS 12.3 beta 5上でメニュー項目が重複して表示されてしまうという現象に遭遇しています。
これは、macOS側のAppleが作ったバグであります。
書籍フォルダの階層をさかのぼって、ツメに掲載する最大チャプターを推測 v2
電子書籍を作るのにPagesやKeynoteを使っており、「AppleScriptによるWebブラウザ自動操縦ガイド」(以下、Webブラウザガイド)も全ページPagesで作っています。
PagesやKeynoteでは書籍作成用としては機能が素朴すぎて、足りない点はAppleScriptでツールを作って、作業の手間を減らしています。それらの補助Scriptは、各種パラメータをその本に合わせて固定して使用しています。
Webブラウザガイドは全14章で構成されているため、ページの左右につけている「ツメ」(Index)は1から14までの数字が入っています。
今後もツメチェックAppleScript(座標、塗りつぶし色と非選択色の自動判別、ファイル名からの該当章の自動ピックアップ)を他の書籍用にも運用していくつもりですが、この「全14章」という仕様は固定なので、章構成が異なる他の本のプロジェクトでは、自動で章の数をかぞえてくれるとよさそうだと考えました。
だいたい電子書籍のファイルについては、フォルダ分けして2階層ぐらいで管理しているので、その階層数については決め打ちでDoc rootフォルダを計算(parent of parent of….)するようにしました。そして、全フォルダのフォルダ名称を取得。
ダイアログで最終章を選択させると、そこから章番号を自動抽出して(「XX章」と書かれていることが前提)、その番号を返します。
こういう用途を考えると、階層構造をそのまま選択できるNSOutlineViewを選択用の部品に使えると便利で……これまでにもedama2さんと意見交換しつつNSOutlineViewをNSAlertダイアログ上に表示するといった試作も何回か検討してきたのですが、スクリプトエディタ/Script Debugger上で記述するAppleScriptObjCではこの部品を扱うのがとても難しいんですね。
ならば、Xcode上で記述するAppleScriptObjCにAppleScript用語辞書を持たせて、階層ファイル構造を選択させる専用の補助アプリケーションを作ってもいいのかも? ただ、Xcode 13.x系が壊れて使えないままの環境であるため、いまXcodeでビルドするわけにもいかないのでした。
choose fileコマンドやchoose folderコマンドに「icon view」「list view」「column view」といった初期表示状態を指定できる機能があれば、それで済むような気もしますが、どうせAppleに要望出してもこういうのは通らないので、自分で作ったほうが確実で早いですわー。
にしても、この通常ウィンドウと見分けがつかないファイル選択ダイアログ、macOS 11で最初に見たときには「正気か?!」と、腰を抜かしました。あいかわらず、この決定を下した責任者は●●だと思いますが、せめてもう少し視覚的に見分けがつくようにできなかったもんでしょうか。
AppleScript名:書籍フォルダの階層をさかのぼって、ツメに掲載する最大チャプターを推測 v2.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/02/26 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions tell application "Pages" tell front document set filePath to (file of it) as alias end tell end tell tell application "Finder" set parentFol to (parent of parent of filePath) tell parentFol set fNames to name of every folder end tell end tell set folName to contents of (choose from list fNames with prompt "書籍のツメに載せる最終章のフォルダを選択") set cNum to retChapter(folName as string) of me –> 14 –ファイル名から「章」情報を抽出 on retChapter(aStr) set wList to words of aStr set aCount to 1 repeat with ii in wList set jj to contents of ii if jj = "章" then return contents of item (aCount – 1) of wList end if set aCount to aCount + 1 end repeat return 0 –Illeagal file name end retChapter |
Skimで現在表示中のページ(見開き2ページ、書籍モード)をJPEG画像で書き出す
SkimでPDFを、見開き2ページ、書籍モードで表示させた状態で、見開きごと2ページ分の画像をJPEG画像で書き出すAppleScriptです。
macOS 12.3 beta 5、Skim v1.6.8で動作を確認してあります。macOS 12に合わせてPDFKitを直接useコマンドで使用指定しています。
▲SkimでPDFをオープンした状態で実行。見開き2ページ、書籍モードを設定している状態
▲macOS標準搭載のスクリプトメニューから呼び出すことを前提に作ってあります
▲見開き2ページのうち、右ページを選択しているか、左ページを選択しているかの状態を検出して処理
AppleScript名:Skimで現在表示中のページ(見開き2ページ、書籍モード)をJPEG画像で書き出す |
— Created 2022-03-02 by Takaaki Naganoya — 2022 Piyomaru Software use AppleScript version "2.7" use scripting additions use framework "Foundation" use framework "Quartz" use framework "PDFKit" use framework "AppKit" property |NSURL| : a reference to current application’s |NSURL| property NSString : a reference to current application’s NSString property NSImage : a reference to current application’s NSImage property NSScreen : a reference to current application’s NSScreen property NSNumber : a reference to current application’s NSNumber property NSZeroPoint : a reference to current application’s NSZeroPoint property PDFDocument : a reference to current application’s PDFDocument property NSJPEGFileType : a reference to current application’s NSJPEGFileType property NSCompositeCopy : a reference to current application’s NSCompositeCopy property NSGraphicsContext : a reference to current application’s NSGraphicsContext property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep property NSNumberFormatter : a reference to current application’s NSNumberFormatter property NSImageInterpolationHigh : a reference to current application’s NSImageInterpolationHigh tell application "Skim" set docCount to count every document if docCount = 0 then return tell front document set curViewSets to view settings set curMode to display mode of curViewSets if curMode is not in {two up, two up continuous} then display dialog "2ページ見開きモードでないため、処理を終了します。" with title "error" with icon 0 return end if set bMode to displays as book of curViewSets if bMode = false then display dialog "「書籍モード」でないため、処理を終了します。" with title "error" with icon 0 return end if set curInd to index of current page set docFile to file of it end tell end tell –PDFのファイルパスから実際のPDFを求める set aPOSIX to POSIX path of docFile set aURL to (|NSURL|’s fileURLWithPath:aPOSIX) set aPDFdoc to PDFDocument’s alloc()’s initWithURL:aURL –PDFのページ数を求める set pCount to aPDFdoc’s pageCount() –ページ数 if curInd = pCount then display dialog "このページはPDFの最終ページなので、見開き表示になっていない可能性があります。" with title "エラー" return end if if curInd = 1 then display dialog "このページはPDFの最初のページなので、見開き表示になっていない可能性があります。" with title "エラー" return end if –見開き中の選択ページが奇数(右ページ)だった場合の対処 if chkOddNum(curInd) = true then set curInd to curInd – 1 –Detect Retina Environment set compFactor to 1.0 –1.0 — 0.0 = max jpeg compression, 1.0 = none set retinaF to NSScreen’s mainScreen()’s backingScaleFactor() if retinaF = 1.0 then set aScale to 2.0 –Non Retina Env else set aScale to 1.0 –Retina Env end if –Pick Up a PDF page as an image (Left Side Page) set thisPageL to (aPDFdoc’s pageAtIndex:(curInd – 1)) set imgL to (NSImage’s alloc()’s initWithData:(thisPageL’s dataRepresentation())) set pageL to renderPDFPageToNSImage(imgL, (curInd – 1), aScale) of me –Pick Up a PDF page as an image (Right Side Page) set thisPageR to (aPDFdoc’s pageAtIndex:(curInd – 0)) set imgR to (NSImage’s alloc()’s initWithData:(thisPageR’s dataRepresentation())) set pageR to renderPDFPageToNSImage(imgR, (curInd – 0), aScale) of me –Calc 2 pages’ width and others set origWidth to (pageR’s |size|()’s width) set newWidth to origWidth * 2 set newHeight to pageR’s |size|()’s height –Make 2 pages’ blank image set aSize to current application’s NSMakeSize(newWidth, newHeight) set newImage to NSImage’s alloc()’s initWithSize:aSize –Compositte each Left and Right page image overlayNSImageByLeftTopOrigin(newImage, pageL, {0, 0}) of me overlayNSImageByLeftTopOrigin(newImage, pageR, {origWidth, 0}) of me –Save Image as JPEG set theData to newImage’s TIFFRepresentation() set newRep to (NSBitmapImageRep’s imageRepWithData:theData) set targData to (newRep’s representationUsingType:(NSJPEGFileType) |properties|:{NSImageCompressionFactor:compFactor, NSImageProgressive:false}) set zText to retZeroPaddingText((curInd + 1), 4) of me set outPath to addString_beforeExtensionIn_addingExtension_("_" & zText, aPOSIX, "jpg") (targData’s writeToFile:outPath atomically:true) –書き出し on renderPDFPageToNSImage(anImage, aPageNum, aScale) set pointSize to anImage’s |size|() set newSize to current application’s NSMakeSize((pointSize’s width) * aScale, (pointSize’s height) * aScale) set newImage to (NSImage’s alloc()’s initWithSize:newSize) newImage’s lockFocus() (anImage’s setSize:newSize) (NSGraphicsContext’s currentContext()’s setImageInterpolation:(NSImageInterpolationHigh)) (anImage’s drawAtPoint:(NSZeroPoint) fromRect:(current application’s CGRectMake(0, 0, newSize’s width, newSize’s height)) operation:(NSCompositeCopy) fraction:2.0) newImage’s unlockFocus() return newImage end renderPDFPageToNSImage –ファイルパス(POSIX path)に対して、文字列(枝番)を追加。任意の拡張子を追加 on addString:extraString beforeExtensionIn:aPath addingExtension:aExt set pathString to NSString’s stringWithString:aPath set theExtension to pathString’s pathExtension() set thePathNoExt to pathString’s stringByDeletingPathExtension() set newPath to (thePathNoExt’s stringByAppendingString:extraString)’s stringByAppendingPathExtension:aExt return newPath as string end addString:beforeExtensionIn:addingExtension: on retZeroPaddingText(aNum, aLen) set tText to ("0000000000" & aNum as text) set tCount to length of tText set resText to text (tCount – aLen + 1) thru tCount of tText return resText end retZeroPaddingText –2つのNSImageを重ね合わせ合成してNSImageで返す(x,yで配置座標を指定) –newImageを参照渡し on overlayNSImageByLeftTopOrigin(newImage, composeImage, aTargPos as list) set backSize to newImage’s |size|() set bHeight to (height of backSize) set overlaySize to composeImage’s |size|() copy aTargPos to {x1, tempy1} set x2 to (width of overlaySize) set y2 to (height of overlaySize) set y1 to bHeight – y2 + tempy1 newImage’s lockFocus() set bRect to {{x1, y1}, {x2, y2}} –macOS 10.13 or later set newImageRect to {{0, 0}, (newImage’s |size|)} newImage’s drawInRect:newImageRect composeImage’s drawInRect:bRect newImage’s unlockFocus() end overlayNSImageByLeftTopOrigin on retUUIDfilePath(aPath, aExt) set aUUIDstr to (NSUUID’s UUID()’s UUIDString()) as string set aPath to ((NSString’s stringWithString:aPath)’s stringByDeletingLastPathComponent()’s stringByAppendingPathComponent:aUUIDstr)’s stringByAppendingPathExtension:aExt return aPath end retUUIDfilePath –NSImageを指定パスにPNG形式で保存 on saveNSImageAtPathAsPNG(anImage, outPath) set imageRep to anImage’s TIFFRepresentation() set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep set pathString to NSString’s stringWithString:outPath set newPath to pathString’s stringByExpandingTildeInPath() set myNewImageData to (aRawimg’s representationUsingType:(NSPNGFileType) |properties|:(missing value)) set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean return aRes –true/false end saveNSImageAtPathAsPNG –奇数かどうかチェック on chkOddNum(aNum) set a to aNum mod 2 if a = 1 then return true else return false end if end chkOddNum –偶数かどうかチェック on chkEvenNum(aNum) set a to aNum mod 2 if a = 0 then return true else return false end if end chkEvenNum |
macOS 12.3 beta 5、ASの障害が解消される(?)
macOS 12.3 beta 3/beta 4で発生していたAppleScriptの処理系全般にわたって発生していた障害が、beta 5で解消されたように見えます。
本Blogへのプログラムリスト掲載時に使っている「AS Publisher v1.8」(AppleScriptでAppleScriptを処理して掲載用のHTMLを生成するプログラム)自体が動作せず、Blogに投稿できない(横にある別Ver.OSのマシンでやればいいんですが)状況が続いていました。
本日配信されていたmacOS 12.3 beta 5で解消されたように見えます。手元にあるScriptが膨大すぎて、全数チェックするわけにもいきませんが、オープンできずにいたAppleScript書類はオープン/実行できています。
昨日リリースした書籍に掲載予定だったリストに動かないものがあって、掲載を見送る処理&使用しているプログラムの作者にお詫びのメールを送っていたのですが、なんのことはない、このbeta 3/4のバグのせいでした(beta 5にアップデートしたら何事もなかったように動いた)。
AppleScript書類をオープンできないとか実行できないといった「最悪レベルの問題」を起こさないことは確認できていますが、やっぱり「内部の表があふれる」的なエラーを出すScriptはまだあるようです。
macOS 11や10.15でそのようなエラーを起こす例を見なかったScriptなので、やはりmacOS 12環境に固有の問題が何かまだ残されているということなんでしょう。
macOS 12.3 beta 5、古めのMac OS X 10.2ぐらいの時期に書かれたAppleScript書類で、現在すでにOSにインストールされていない各種補助アプリケーションを呼び出しているものを、アプリケーション選択ダイアログを出さずに、いきなり「オープンできない」とダイアログを出して切り捨てる動作を行なっています。Script Debugger経由ではオープンできるため、依然として注意が必要です。
新刊発売:AppleScriptによるWebブラウザ自動操縦ガイド
macOS用の7つのWebブラウザ(Safari、Chrome、Chromium、Microsoft Edge、Vivaldi、Brave Browser、Opera)を操作するAppleScript本です。PDF形式306ページ。
→ 販売ページ
1章 めんどうな操作を自動化しよう!
人間の手で操作して情報を集めたり、データ入力するのは非効率。スクリプトから操作して自動操作
2章 スクリプトエディタの使い方
AppleScript専用のスクリプトエディタの使い方など、基礎的な内容をご紹介。
3章 WebブラウザをAppleScriptから動かそう
macOS用Webブラウザの大半はAppleScriptから操作可能。AppleScript対応は必須の機能!
4章 Webブラウザの情報を取り出そう
Webブラウザ自体が大量の情報を管理しています。まずは、ブラウザの情報を調べてみましょう。
5章 指定URLをオープンしよう
誰にでも確実に行える操作です。かならず経験しておきましょう。URLをオープンした後が大事です。
6章 コンテンツをキャプチャして保存しよう
表示内容を変化しないデータや、再利用可能なデータとして残しておくことは、重要な処理です。
7章 Webコンテンツにアクセスしよう
HTML内の操作対象にアクセスするための、さまざまなアプローチをご紹介
8章 Webコンテンツを画面部品として操作しよう
画面上の部品と同様にWebコンテンツにアクセスして強引に操作する「奥の手」GUI Scripting
9章 ログイン、ログアウトしてみよう
ユーザー登録が必要なWebサイトの処理を行うために必須の作業です。意外とクリアしにくい箇所
10章 データをダウンロードして処理しよう
直接ダウンロードできないファイルのダウンロード完了を検出して、ファイル処理しよう! ダウンロード後にファイル整理したりファイル名を変更したり
11章 仮想ディスプレイでユーザーの誤操作を防ごう
ユーザーからの操作をガードするために、仮想ディスプレイを用意してWebブラウザを表示! 画面上から強引にScriptで動かすと、ユーザーの誤操作が一番の大敵
12章 さまざまな実行環境を知ろう
AppleScriptにはいろいろな実行環境があって、環境ごとにできる/できないことがあります。時間と気持ちに余裕のある時にでも読んでおくとよいでしょう。
13章 実例:Quoraの統計データを取得しよう
実際に、Quoraのアクセス情報ページにアクセスし、自分の投稿情報を取得してみよう!
14章 さまざまな技術資料。興味があったら読んでね
アプリケーション・オブジェクトの指定方法/AppleScript用語辞書の確認方法/Webブラウザの基礎的なScripting/Google Chrome系のWebブラウザのsdef/AppleScriptの歴史/AppleScriptのエラーコード表/AppleScript予約語一覧/各Webブラウザの用語辞書の変更履歴
macOS 12.3 beta4、まだ直らないASまわりの障害
macOS 12.3 beta 3で発生した目が覚めるような不具合。本日、beta 4が出てきたものの、AppleScript書類をオープンできない(ものがある)とか、実行できない(ものもある)というなかなかハードな状況です。正直、macOS 12.2に戻したいデス(^ー^;;
ちょっと前にSkimで遭遇した「内部の表があふれました」エラーの問題がどうやら(Skim以外にも)存在していて、その解決を図ろうとして他の問題を引き起こしてしまったのではないかと推測しています。
どこか別のチームが引き起こした修正が影響を及ぼしているのかと思いきや……そうでもない雰囲気が(汗)
macOS 12.3がどの程度までbetaを出すのかわかりませんが、通例ではbeta 5ぐらいでReleaseするんじゃないでしょうか。ラスト1take?
少なくとも、常識的に考えれば3月にリリースするとか噂で言われている新ハードウェアの発売に合わせて(未発表なので詳細は知りませんが)、これらのハードウェア向けにmacOS 12.3をリリースするとかいう話なんじゃないでしょうか。
# macOS 12.2.2とかいった細かいバージョンアップで例外的に対応することも不可能ではないと思われますが、外野からではリリース番号のポリシーなどはよくわかりません
自分なら、当初取り掛かっていた問題解決をいったん引っ込めて、12.2と同等の状況に戻してリリースすることでしょう。一部の問題解決を目指して、より広範囲に問題を引き起こすのは得策ではありません。
正直、AppleScriptの処理系の安定性がここまで「揺らいだ」のは初めての出来事なので(Mac OS X 10.3.xで、自分が多用している「is in」演算子が動かないことに気づいた時には目の前が真っ暗になりました…「Newt Onジャマー」とか呼んで、いいかげんにしてくれよと思ってました)、正直困惑しています。
CotEditor v4.1.2でAppleScript系の機能を追加
オープンソース開発されているフリーのテキストエディタ「CotEditor」v4.1.2において、AppleScript系の機能が追加されています。
・DocumentオブジェクトのhasBOM属性
has BOM (boolean, r/o) : Is the file encoding of the document has BOM (byte order mark)?
・convertコマンドのBOMオプション
convert v : Convert the document text to new encoding. convert document : The document to convert encoding. [lossy boolean] : Allows lossy conversion? [BOM boolean] : Has the new encoding a BOM (byte order mark)? to text : The new encoding, either in localized encoding name or an IANA charset name. → boolean : Did the convertion succeed?
・新設のjumpコマンド
jump v : Move the caret to the specified location. At least, either one of a parameter is required. jump document : The document to move. to line integer : The number of the line to go. If a negative value is provided, the line is counted from the end of the document. [column integer] : The location in the line to jump. If a negative value is provided, the column is counted from the end of the line.
こんなサンプル書類があったとして、
AppleScriptのdocumentオブジェクトの文字データを取得してダンプしてみても、
--No BOM {"E3", "81", "B4", "E3", "82", "88", "E3", "81", "BE", "E3", "82", "8B", "E3", "82", "BD", "E3", "83", "95", "E3", "83", "88", "E3", "82", "A6", "E3", "82", "A7", "E3", "82", "A2", "0A", "61", "62", "63", "64", "E9", "AB", "98", "E5", "B3", "B6", "E5", "B1", "8B", "65", "66", "67", "68", "69", "0A", "0A"} --with BOM {"E3", "81", "B4", "E3", "82", "88", "E3", "81", "BE", "E3", "82", "8B", "E3", "82", "BD", "E3", "83", "95", "E3", "83", "88", "E3", "82", "A6", "E3", "82", "A7", "E3", "82", "A2", "0A", "61", "62", "63", "64", "E9", "AB", "98", "E5", "B3", "B6", "E5", "B1", "8B", "65", "66", "67", "68", "69", "0A", "0A"}
この状態ではhasBOM属性値で差があっても、内部データでは差が出ません。これをファイルに書き込んで、ファイル内容についてチェックを行うと、
--No BOM 0000000 81e3 e3b4 8882 81e3 e3be 8b82 82e3 e3bd 0000010 9583 83e3 e388 a682 82e3 e3a7 a282 610a 0000020 6362 e964 98ab b3e5 e5b6 8bb1 6665 6867 0000030 0a69 000a 0000033 --With BOM 0000000 bbef e3bf b481 82e3 e388 be81 82e3 e38b 0000010 bd82 83e3 e395 8883 82e3 e3a6 a782 82e3 0000020 0aa2 6261 6463 abe9 e598 b6b3 b1e5 658b 0000030 6766 6968 0a0a 0000036
のように、差を検出できます。
[超危険]macOS 12.3 beta3、errOSAInternalTableOverflow多発
今朝方来ていたmacOS 12.3 beta3アップデートをインストールしたら、(Script Debuggerで)AppleScript書類のでかいのをオープンしただけで「errOSAInternalTableOverflow」が表示されるようになりました。
スクリプトエディタでは、AppleScript書類のオープンすら(小さいものでないと)できない状況です。
過去最悪レベルの問題リリースです>macOS 12.3beta 3
▲今日の深夜に問題なく実行できていたScriptがいきなりオープンできなかったり実行できなくなったりする問題が発生
▲昨日までオープンできていたAppleScript書類をスクリプトエディタでオープンできなくなる事態が発生!!!
こういうアップデートは困ります、、、、Betaプログラムに参加されている方は、Beta 3のアップデートをインストールすることはやめておいたほうがいいと思います。
日常的に、Pagesの連続PDF出力+連結など大規模なScriptを動かしていたのが、急に今日になって動かなくなってしまいました。
こういうのは困るんですが?(ーー;;;
大きなScriptを動かすときには、部品ごとに分割して、別ファイルに分割して対処を行なってみていますが、、、過去にこのようなトラブルに遭遇したことはなかったので、純粋に腹が立つバグですわー
# どうしても動かないと困るAppleScriptについては、書き換えてScriptの機能をライブラリに分割して、バンドル内にライブラリを同梱する方向で対処しました
バグレポートはしましたが、「ざけんなコラ!!!!」と日本語で書きそうになりましたわー。
# さすがに直したらしい(謎情報)ですが、macOS 12.3 Beta 4自体がいつ出るのか不明。ものすごくScript周りがバギーで一刻も早く出てほしい。Appleの会議体制から考えると1週間以内に出ることはない
# macOS 12.3 beta 5で直りました(多分)
Pages書類内の表の指定ラベルの行を削除
Pagesの書類上にある表に対して、指定のラベルを持つ行を削除するAppleScriptです。macOS 12.3beta2+Pages 11.2で動作確認しています。
現在作成中のWebブラウザのScripting本で、各種AppleScript実行環境の一覧表を掲載しているのですが、
それぞれの差別化ポイントとして掲載していたデータのうちの1つが、執筆後に一律で解決できることになり(NSAlertダイアログの最前面表示)、そのデータ行については削除することになりました。
そこで、複数のPages書類に記載した表を一括で削除することになり、AppleScriptを組んで削除することにしました。
必要はありませんでしたが、ヘッダー列が1列だけでなく、複数の列になった場合と、ヘッダーの複数セルが1つにまとめられていた場合への対処も行っておきました。ただし、気休め程度であって、本気で対処したものではありません。
AppleScript名:Pages書類内の表の指定ラベルの行を削除.scpt |
— – Created by: Takaaki Naganoya – Created on: 2022/02/14 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" use framework "Foundation" use scripting additions set targRowLabel to "NSAlert ダイアログの最前面表示" tell application "Pages" tell front document set tList to every table whose column count = 2 end tell end tell delRowInEveryTable(tList, targRowLabel) of me on delRowInEveryTable(tList as list, targRowLabel as string) tell application "Pages" repeat with i in tList set j to contents of i tell j set hCCount to header column count set hRCount to header column count –ヘッダーカラムが複数存在している場合に対処? repeat with hc from 1 to hCCount tell column hc set aList to value of every cell end tell if targRowLabel is in aList then set aRes to search1DList(aList, targRowLabel) of me –ヘッダー列に削除対象ラベルが存在しつつ、削除対象ラベルがヘッダー行の範囲ではない場所に出現した場合に削除 if (aRes is not equal to false) and (aRes ≥ hRCount) then try –ねんのため delete row aRes end try end if end if end repeat end tell end repeat end tell end delRowInEveryTable on search1DList(aList, aTarg) set anArray to current application’s NSMutableArray’s arrayWithArray:aList set anIndex to anArray’s indexOfObject:aTarg if (anIndex = current application’s NSNotFound) or (anIndex > 9.99999999E+8) then return false end if return (anIndex as integer) + 1 –convert index base (0 based to 1 based) end search1DList |
リストに入れたテキストで、冒頭に入ったマルつき数字をリナンバーする
日本語環境限定かもしれませんが、マルつき数字(①②③④⑤⑥⑦⑧⑨….)をさまざまな場所でよく使います。
データにマルつき数字を入れると、順番がわかりやすくてよいのですが、データそのものを入れ替えたときに番号をふり直すという手間がかかってしまいます。これがけっこうな手間になっています(地味に大変)。
そこで、
{"③AAAAAA", "②BBBBB", "①CCCCC", "⑬DDDDDD", "⑫EEEE", "④FFFF", "⑤GGGG", "⑥HHHH", "⑲IIIII", "⑧JJJJ"}
というデータを本Scriptによって、
{"①AAAAAA", "②BBBBB", "③CCCCC", "④DDDDDD", "⑤EEEE", "⑥FFFF", "⑦GGGG", "⑧HHHH", "⑨IIIII", "⑩JJJJ"}
と、リナンバー処理します。
本処理は、絵文字の削除Scriptの副産物として生まれたもので、マル文字を削除したのちに番号をふり直して付加したところ、たいへん有用性を感じられました。
Keynote、Numbers、Pages…と、同じことができるようにScriptを整備し、CotEditor用にあったほうが便利だろうと考えて、CotEditor用にかきかえた際に、
「ほかのアプリケーションでも使えたほうが便利なので、再利用しやすいように部品化しておこう」
と、Script文でラッピングしてみたものがこれです。
AppleScript名:リストに入れたテキストで、冒頭に入ったマルつき数字をリナンバーする.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/02/12 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions set aOffset to 0 set aSelList to {"③AAAAAA", "②BBBBB", "①CCCCC", "⑬DDDDDD", "⑫EEEE", "④FFFF", "⑤GGGG", "⑥HHHH", "⑲IIIII", "⑧JJJJ"} —データ中に丸つき数字が存在した場合には、最小のものを取得 set aOffset to (getMinimumNumFromNumberWithSign(aSelList) of maruNumKit) –ユーザーに対して「本当に初期値がこれでいいのか?」をダイアログなどで確認したほうがいい –Keynoteの表のセルから取得したデータから丸つき数字を除去する set cList to removeNumberWithSignFromList(aSelList) of maruNumKit –list中の各アイテムの冒頭に順次丸つき数字を追加する set dList to {} set aCount to 0 repeat with i in cList set j to convNumToNumWithSign(aCount + aOffset) of maruNumKit set jj to contents of i set the end of dList to (j & jj) set aCount to aCount + 1 end repeat return dList –> {"①AAAAAA", "②BBBBB", "③CCCCC", "④DDDDDD", "⑤EEEE", "⑥FFFF", "⑦GGGG", "⑧HHHH", "⑨IIIII", "⑩JJJJ"} –1D Arrayを改行コードをデリミタに指定しつつテキスト化 –set outStr to retDelimedText(dList, return) of maruNumKit –丸つき数字を扱うキット script maruNumKit use AppleScript use framework "Foundation" use scripting additions property parent : AppleScript –1~50の範囲の数値を丸つき数字に変換して返す on convNumToNumWithSign(aNum as number) if (aNum ≤ 0) or (aNum > 50) then return "" set aStr to "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿" set bChar to character aNum of aStr return bChar end convNumToNumWithSign –1D List上で指定データを検索してヒットしたアイテム番号を返す on search1DList(aList, aTarg) set anArray to current application’s NSMutableArray’s arrayWithArray:aList set anIndex to anArray’s indexOfObject:aTarg if (anIndex = current application’s NSNotFound) or (anIndex > 9.99999999E+8) then return false end if return (anIndex as integer) + 1 –convert index base (0 based to 1 based) end search1DList –1D listのクリーニング on cleanUp1DList(aList as list, cleanUpItems as list) set bList to {} repeat with i in aList set j to contents of i if j is not in cleanUpItems then set the end of bList to j else set the end of bList to "" end if end repeat return bList end cleanUp1DList –text in listから丸つき数字を除去する on removeNumberWithSignFromList(aList as list) set bList to {} repeat with i in aList set j to contents of i set j2 to removeNumberWithSign(j) of me set the end of bList to j2 end repeat return bList end removeNumberWithSignFromList –文字列から丸つき数字を除去する on removeNumberWithSign(aStr as text) set aNSString to current application’s NSString’s stringWithString:aStr return (aNSString’s stringByReplacingOccurrencesOfString:"[\\U000024EA-\\U000024EA\\U00002460-\\U00002473\\U00003251-\\U000032BF\\U000024FF-\\U000024FF\\U00002776-\\U0000277F\\U000024EB-\\U000024F4\\U00002780-\\U00002789\\U0000278A-\\U00002793\\U000024F5-\\U000024FE]" withString:"" options:(current application’s NSRegularExpressionSearch) range:{0, aNSString’s |length|()}) as text end removeNumberWithSign –1D Listに入っているテキストから丸つき数字を抽出して数値化し、最小のものを求める on getMinimumNumFromNumberWithSign(aList) set nList to {} repeat with i in aList set j to contents of i –与えられたテキストのうち、丸つき数字(白)の set j2 to holdNumberWithSignOnly(j) of me set n2List to characters of j2 –複数の丸つき数字が入っている場合に対処 repeat with ii in n2List set jj to contents of ii set tmpNum to decodeNumFromNumWithSign(jj) of me set the end of nList to tmpNum end repeat end repeat set anArray to current application’s NSArray’s arrayWithArray:nList set cRes to (anArray’s valueForKeyPath:"@min.self") as integer return cRes end getMinimumNumFromNumberWithSign –指定文字列から丸つき数字のみ抽出する on holdNumberWithSignOnly(aStr as text) set aNSString to current application’s NSString’s stringWithString:aStr return (aNSString’s stringByReplacingOccurrencesOfString:"[^\\U000024EA-\\U000024EA\\U00002460-\\U00002473\\U00003251-\\U000032BF\\U000024FF-\\U000024FF\\U00002776-\\U0000277F\\U000024EB-\\U000024F4\\U00002780-\\U00002789\\U0000278A-\\U00002793\\U000024F5-\\U000024FE]" withString:"" options:(current application’s NSRegularExpressionSearch) range:{0, aNSString’s |length|()}) as text end holdNumberWithSignOnly –丸つき数字を数値にデコードする v2 on decodeNumFromNumWithSign(aStr as string) set numStr1 to "①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜㉝㉞㉟㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿" set numStr2 to "❶❷❸❹❺❻❼❽❾❿⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴" set numStr3 to "➀➁➂➃➄➅➆➇➈➉" set numStr4 to "➊➋➌➍➎➏➐➑➒➓" set numStr5 to "⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾" set nList to {numStr1, numStr2, numStr3, numStr4, numStr5} repeat with i in nList set numTemp to contents of i if numTemp contains aStr then using terms from scripting additions set bNum to offset of aStr in numTemp end using terms from return bNum end if end repeat return false end decodeNumFromNumWithSign –1D Listを指定デリミタをはさみつつテキストに on retDelimedText(aList as list, aDelim as string) set aText to "" set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to aDelim set aText to aList as text set AppleScript’s text item delimiters to curDelim return aText end retDelimedText end script |
PDFViewでcustom URL protocolのリンクを含むPDFのリンクが途切れるバグが修正される
PDFView上で、カスタムURLプロトコルのURLリンクを含むPDFのリンクをクリックした場合に、展開されたリンクデータが途中で途切れるバグ(だか仕様だか)がmacOS 12.3beta 1で修正された…ように見えます。
なんの話だか、詳細が説明されなければわからないことでしょう。以下に詳細を示します。
macOS標準装備の「プレビュー.app」では、カスタムURLプロトコル入りのPDFでリンクをクリックしても反応しません。macOS標準装備のPDFビューワでこうしたPDFのリンクを拾わない、というAppleのセキュリティ上のポリシーを通すことについては、それはご勝手にすればいいでしょう。
ただ、だからといってPDFViewというOSの部品レベルでそれを阻害するような機能を実装するというのは、「やりすぎ」であり、「起動しないコンピュータ、動作しないコンピュータを作れば100%セキュリティを守れます!」というどこかの責任者のバカみたいな主張をバカな現場がそのまま実装したというだけの話です。
プレビュー.appなんて「よくわからない人」が使うPDFビューワーであり、文化的な最低限のレベルを満たしている人類は普通にSkimを使います。このバグによってSkimにまで影響が出て、基本的人権ともいえるPDFブラウジングが阻害されたため、「直してくれ」と要求した次第です。
2019/11/29 macOS 10.15でPDFView経由のURLイベントが正しくデコードされないバグ
macOS 10.15でこのバグ(だか仕様変更だか)が発生してAppleにバグレポート。macOS 10.15はそういう勘違いで独善的な仕様変更のオンパレード。macOS 10.15は本当に腹のたつアップデートでした。
そして、待てど暮らせど直る気配もなく、急にレポートがきて「いまごろ、何の話だ?」と、驚いてしまったほどです。
本バグ(と、自分は位置付けている)レポートは、「applescript://」URLリンクを埋め込んだPDFが、macOS上でリンククリックすると、Script Editorにその内容がすべて転送されず、途中で途切れるようになったという現象についての抗議です。
勝手に仕様変更だかバグだかを作ったのはAppleであり、その修正までに2年かかったというバカみたいな話です。
macOS 10.15:PDFViewのバグ発生を検出、Appleにサンプルコードつきでバグレポートとして報告する
macOS 11:バグ継続
macOS 12:Beta 3でバグが修正されたことが通告される
勝手に仕様変更だかバグを作ったのはAppleなのに、利用者がその不利益を被って、多大なる労力を要求されるってなんなんでしょう、、、
PDFViewでPDFを表示する程度のシンプルでおかわいらしい内容のテストプログラムを作ってあったので、Xcodeでビルドして実行してテストしてみました。まだ、すべてのPDFでチェックしたわけではありませんが、いまのところ「いい感じ」に見えます。
この、Apple純正のバグをApple様に直していただいて、そのことをApple様に感謝しなければいけないのでしょうか? なんというマッチポンプ。もしかして、組織のどこかの人たちが善意で直してくれたのかもしれませんが、自分には知る由もありません。
ちなみに、SkimについてはmacOS 12でカスタムURLプロトコルリンクのPDFを問題なく処理できることを確認しています。
この調子で、PDFViewのcurrentPageがAppleScriptにまともにブリッジされていない件についても修正してくださるとありがたいのですが、どんなもんなんでしょうか。
与えられた自然言語テキストから言語を推測して、指定の性別で、TTSキャラクタを自動選択して読み上げ
自然言語テキストを与えると、記述言語を推測して、その言語コード(jaとか)、性別、Premium(高音質)音声かどうか(true/false)をもとにText to Speechの読み上げ音声キャラクタをしぼりこんで、sayコマンドで音声読み上げするAppleScriptです。
# ScriptのリストについているURL Linkを書き換えました
自然言語から推測される言語コードと、TTS音声キャラクタに振られている言語コードの間に仕様的な食い違いがあるので、中国語の自動判定を行うためには、(若干の)処理を追加する必要があります。
自然言語テキストから取得できるのは「簡体字」「繁体字」のコードである一方で、TTS読み上げキャラクタが持っているのは、China、HongKong、Taiwanと国コードなので、対照表でもつけるか、いっそ全部「zh」でくくってランダム選択するか、、、はたまた、実行マシンの緯度・経度情報から判定するか、テーブルを編集可能なようにしておいて、テーブルのルールを決め打ちで反映するとか、、、、
▲システム環境設定>アクセシビリティ>読み上げコンテンツ>システムの声 のポップアップメニューで、一番下に「カスタマイズ」の項目があり、Text To Speech読み上げキャラクタの追加が行える
▲追加したTTSキャラクタの音声データは自動でダウンロードが行われる。TTS用にSiri音声は指定できないが、「ショートカット」の音声読み上げでは指定できる。このあたり、外部のTTS音声データ提供会社との契約によるものなのか、あるいは管理プログラムが異なるのか?
AppleScript名:与えられた自然言語テキストから言語を推測して、指定の性別で、TTSキャラクタを自動選択して読み上げ v1(簡体字、繁体字 未サポート).scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/02/05 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" use scripting additions use framework "Foundation" use framework "AppKit" property NSSpeechSynthesizer : a reference to current application’s NSSpeechSynthesizer set str1 to "こんにちは" –指定文字列が何語かを推測して、言語コード(Short)を取得 set a1Res to guessLanguageCodeOf(str1) of me –指定の言語コード(Short)をキーにしてTTS属性情報を取得 set vList to retAvailableTTSbyShortLangCodeAndSexAndPremium(a1Res, "Female", true) of me if vList = {} then return –取得したTTS情報リストから、てきとーに項目を取得 set fV to contents of first item of vList set vName to VoiceName of fV say str1 using vName — on retAvailableTTSbyShortLangCodeAndSexAndPremium(aLangShortCode as string, aSex as string, premiumFlag as boolean) set outList to {} if aSex is not in {"Male", "Female"} then error "Sex code is wrong" set aList to NSSpeechSynthesizer’s availableVoices() set bList to aList as list repeat with i in bList set j to contents of i set aInfo to (NSSpeechSynthesizer’s attributesForVoice:j) set aInfoRec to aInfo as record –読み上げ対象文字データは多すぎるので削除しておく set VoiceIndividuallySpokenCharacters of aInfoRec to {} set VoiceSupportedCharacters of aInfoRec to {} set aName to VoiceName of aInfoRec set aLangCode to VoiceLocaleIdentifier of aInfoRec set aGender to VoiceGender of aInfoRec set aVID to VoiceIdentifier of aInfoRec if (aLangCode starts with aLangShortCode) and (aGender = "VoiceGender" & aSex) then if premiumFlag = true then if aVID ends with "premium" then set the end of outList to aInfoRec end if else set the end of outList to aInfoRec end if end if end repeat return outList end retAvailableTTSbyShortLangCodeAndSexAndPremium –文字列から言語を推測して言語名を返す on guessLanguageOf(theString) set theTagger to current application’s NSLinguisticTagger’s alloc()’s initWithTagSchemes:{current application’s NSLinguisticTagSchemeLanguage} options:0 theTagger’s setString:theString set languageID to theTagger’s tagAtIndex:0 |scheme|:(current application’s NSLinguisticTagSchemeLanguage) tokenRange:(missing value) sentenceRange:(missing value) return ((current application’s NSLocale’s localeWithLocaleIdentifier:"en")’s localizedStringForLanguageCode:languageID) as text end guessLanguageOf –文字列から言語を推測して言語コードを返す on guessLanguageCodeOf(theString) set theTagger to current application’s NSLinguisticTagger’s alloc()’s initWithTagSchemes:{current application’s NSLinguisticTagSchemeLanguage} options:0 theTagger’s setString:theString set languageID to theTagger’s tagAtIndex:0 |scheme|:(current application’s NSLinguisticTagSchemeLanguage) tokenRange:(missing value) sentenceRange:(missing value) return languageID as text end guessLanguageCodeOf |
指定アプリケーションの各言語のローカライズ名称を取得して、言語名をローカライズしてNumbersに出力
指定アプリケーションが対応している各ローカライズ言語におけるアプリケーション名称を取得して、言語名をcurrent localeに合わせて変換しつつCSV出力してNumbersでオープンするAppleScriptです。
アプリケーションバンドルを調査して、ローカライズ対応している言語の一覧を取得するプログラムは組んでありました。そのローカライズを順次調べて、InfoPlist.stringsファイルを読み込み、CFBundleNameのエントリを調べています。
これで、その言語向けにローカライズされた「名称」を調べられます。あとは、言語コードを名称に変換する処理(これも、ありもの)を組み合わせて、2次元配列(2D list)にまとめあげ、CSV書き出しして(ありもの)、Numbersでオープンしただけのものです。
言語名称については、currentLocaleを利用しているため、日本語環境で実行すれば日本語表現で出力されますし、英語環境で実行すれば英語表現で出力されます。
実際に、書籍に掲載する資料用のデータを作成するときに使ってみました。
言語 | Code | 「地図」アプリのローカライズ名称 |
ドイツ語 | de | Karten |
ヘブライ語 | he | מפות |
英語(オーストラリア) | en_AU | Maps |
アラビア語 | ar | الخرائط |
ギリシャ語 | el | Χάρτες |
日本語 | ja | マップ |
英語 | en | Maps |
ウクライナ語 | uk | Карти |
スペイン語(ラテンアメリカ) | es_419 | Mapas |
中国語(中国本土) | zh_CN | 地图 |
スペイン語 | es | Mapas |
デンマーク語 | da | Kort |
イタリア語 | it | Mappe |
スロバキア語 | sk | Mapy |
ポルトガル語(ポルトガル) | pt_PT | Mapas |
マレー語 | ms | Peta |
スウェーデン語 | sv | Kartor |
チェコ語 | cs | Mapy |
韓国語 | ko | 지도 |
広東語(中国本土) | yue_CN | 地图 |
ノルウェー語 | no | Kart |
ハンガリー語 | hu | Térképek |
中国語(香港) | zh_HK | 地圖 |
トルコ語 | tr | Harita |
ポーランド語 | pl | Mapy |
中国語(台湾) | zh_TW | 地圖 |
英語(イギリス) | en_GB | Maps |
ベトナム語 | vi | Bản đồ |
ロシア語 | ru | Карты |
フランス語(カナダ) | fr_CA | Plans |
フランス語 | fr | Plans |
フィンランド語 | fi | Kartat |
インドネシア語 | id | Peta |
オランダ語 | nl | Kaarten |
タイ語 | th | แผนที่ |
ポルトガル語 | pt | Mapas |
ルーマニア語 | ro | Hărți |
クロアチア語 | hr | Karte |
ヒンディー語 | hi | नक़्शा |
カタロニア語 | ca | Mapes |
AppleScript名:指定アプリケーションの各言語のローカライズ名称を取得して、言語名をローカライズしてNumbersに出力.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/02/04 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use framework "AppKit" use scripting additions set targFile to "InfoPlist.strings" set targKey to "CFBundleName" set aLocale to (current application’s NSLocale’s currentLocale()) set aLoc to path to applications folder set anApp to POSIX path of (choose file of type {"com.apple.application-bundle"} default location aLoc) set aBundle to getBundleFromPath(anApp) of me set aName to aBundle’s objectForInfoDictionaryKey:(current application’s kCFBundleNameKey) set aLocList to getSpecifiedAppFilesLocalizationListWithDuplication(aBundle) of me set hitList to {} repeat with i in aLocList set j to contents of i if j is not equal to "Base" then set allPath to anApp & "/Contents/Resources/" & j & ".lproj/" & targFile set aDict to (current application’s NSDictionary’s alloc()’s initWithContentsOfFile:allPath) if aDict is not equal to missing value then set aVal to (aDict’s valueForKeyPath:(targKey)) if aVal is not equal to missing value then set aLang to getLangNameWithLocale(j, aLocale) of me set the end of hitList to {aLang, j, aVal as string} end if else log {"Error in ", j} end if end if end repeat –一時ファイルをCSV形式でデスクトップに書き出し set aPath to (path to desktop as string) & (do shell script "uuidgen") & ".csv" saveAsCSV(hitList, aPath) of me –書き出したCSVファイルをNumbersでオープン tell application "Numbers" open (aPath as alias) end tell –Application path –> Bundle on getBundleFromPath(aPOSIXpath) set aURL to current application’s |NSURL|’s fileURLWithPath:aPOSIXpath set aWorkspace to current application’s NSWorkspace’s sharedWorkspace() set appURL to aWorkspace’s URLForApplicationToOpenURL:aURL set aBundle to current application’s NSBundle’s bundleWithURL:appURL return aBundle end getBundleFromPath –指定Bundleのローカライズ言語リストを求める。重複を許容 on getSpecifiedAppFilesLocalizationListWithDuplication(aBundle) set locList to aBundle’s localizations() return locList as list end getSpecifiedAppFilesLocalizationListWithDuplication on getLangNameWithLocale(langCode, aLocale) set aLangName to (aLocale’s displayNameForKey:(current application’s NSLocaleIdentifier) value:langCode) as string return aLangName end getLangNameWithLocale –2D List to CSV file on saveAsCSV(aList, aPath) –set crlfChar to (ASCII character 13) & (ASCII character 10) set crlfChar to (string id 13) & (string id 10) set LF to (string id 10) set wholeText to "" repeat with i in aList set newLine to {} –Sanitize (Double Quote) repeat with ii in i set jj to ii as text set kk to repChar(jj, string id 34, (string id 34) & (string id 34)) of me –Escape Double Quote set the end of newLine to kk end repeat –Change Delimiter set aLineText to "" set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to "\",\"" set aLineList to newLine as text set AppleScript’s text item delimiters to curDelim set aLineText to repChar(aLineList, return, "") of me –delete return set aLineText to repChar(aLineText, LF, "") of me –delete lf set wholeText to wholeText & "\"" & aLineText & "\"" & crlfChar –line terminator: CR+LF end repeat if (aPath as string) does not end with ".csv" then set bPath to aPath & ".csv" as Unicode text else set bPath to aPath as Unicode text end if writeToFileAsUTF8(wholeText, bPath, false) of me end saveAsCSV on writeToFileAsUTF8(this_data, target_file, append_data) tell current application try set the target_file to the target_file as text set the open_target_file to open for access file target_file with write permission if append_data is false then set eof of the open_target_file to 0 write this_data as «class utf8» to the open_target_file starting at eof close access the open_target_file return true on error error_message try close access file target_file end try return error_message end try end tell end writeToFileAsUTF8 on repChar(origText as text, targChar as text, repChar as text) set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to targChar set tmpList to text items of origText set AppleScript’s text item delimiters to repChar set retText to tmpList as string set AppleScript’s text item delimiters to curDelim return retText end repChar |
Numbersの表でセル連結箇所が存在していたらすべて連結解除
指定のNumbers書類中の指定の表で、セルの連結が行われた箇所が存在していたらすべて連結解除するAppleScriptです。
Numbersの表でセルの連結が存在していると、フィルタ処理などが行えないために、セル連結箇所がないかを調べる手段がないと困ります。でも、そういう便利なコマンドがNumbersのAppleScript用語辞書には存在していないので作りました。
連結箇所が分かれば、個別に連結解除するだけです。ループですべてunmergeします。
動作確認は、M1 Mac mini+macOS 12.3beta+Numbersバージョン11.2で行なっています。
AppleScript名:指定の表で連結セルがあればすべて分離.scpt |
— – Created by: Takaaki Naganoya – Created on: 2022/01/31 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" use scripting additions use framework "Foundation" property NSCountedSet : a reference to current application’s NSCountedSet tell application "Numbers" tell front document tell active sheet tell table 1 set nList to name of every cell set aRes1 to returnDuplicatesOnly(nList) of me –重複するセルの名称のみピックアップ –重複セルを個別に分離 repeat with i in aRes1 set j to contents of i unmerge cell j end repeat end tell end tell end tell end tell on returnDuplicatesOnly(aList as list) set aSet to NSCountedSet’s alloc()’s initWithArray:aList set bList to (aSet’s allObjects()) as list set dupList to {} repeat with i in bList set aRes to (aSet’s countForObject:i) if aRes > 1 then set the end of dupList to (contents of i) end if end repeat return dupList end returnDuplicatesOnly |
Numbersの表でセル連結箇所が存在しているかどうかチェック
指定のNumbers書類中の指定の表で、セルの連結が行われた箇所が存在しているかどうかチェックするAppleScriptです。
Numbersの表でセルの連結が存在していると、フィルタ処理などが行えないために、セル連結箇所がないかを調べる手段がないと困ります。でも、そういう便利なコマンドはNumbersのAppleScript用語辞書には存在していません。
動作確認は、M1 Mac mini+macOS 12.3beta+Numbersバージョン11.2で行なっています。
セルが連結されている箇所は、セルのnameが重複していることが判明。すべてのセルの「name」を取得して、重複しているものをチェックするとセル連結の有無がわかります。
B3セルのproperties
C3セルのproperties
AppleScript名:指定の表でセル連結がないかチェック.scpt |
— – Created by: Takaaki Naganoya – Created on: 2022/01/31 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" use scripting additions use framework "Foundation" property NSCountedSet : a reference to current application’s NSCountedSet tell application "Numbers" tell front document tell active sheet tell table 1 set nList to name of every cell set aRes1 to returnDuplicatesOnly(nList) of me return aRes1 –> {"B3"} end tell end tell end tell end tell on returnDuplicatesOnly(aList as list) set aSet to NSCountedSet’s alloc()’s initWithArray:aList set bList to (aSet’s allObjects()) as list set dupList to {} repeat with i in bList set aRes to (aSet’s countForObject:i) if aRes > 1 then set the end of dupList to (contents of i) end if end repeat return dupList end returnDuplicatesOnly |
macOS 12.3 Beta(21E5196i)、電話番号ピックアップできないバグが直る?
macOS 12.3 Beta(21E5196i)が配信され、M1 Mac mini上で実験してみたところ、macOS 12でバグが出ていた「自然言語テキストからNSDataDetectorで電話番号を抽出しようとすると何も出てこない」件(日本語環境限定)が修正されているように見えます。
Thanks Shane!
AppleScript名:与えられたテキストから電話番号を抽出 v2 |
— Created 2015-08-21 by Shane Stanley — Modified 2015-08-21 by Takaaki Naganoya — Modified 2015-08-22 by Shane Stanley use AppleScript version "2.4" use scripting additions use framework "Foundation" set theString to "長野谷隆昌 (Takaaki Naganoya) maro@piyocast.com http://piyocast.com/as 2015年8月21日〜23日 080-1111-2222 030-1234-5678 東京都練馬区中村橋1-2-3 " set theDates to (extractPhoneNumberFromNaturalText(theString)) –> {"080-1111-2222"}–macOS 10.12 or other version –> {"080-1111-2222", "030-1234-5678"}–macOS 13.6 with Intel MacBook Air –> {"080-1111-2222", "030-1234-5678"}–macOS 14.6 with Intel MacBook Pro –> {"080-1111-2222", "030-1234-5678"}–macOS 15.7 with Intel MacBook Pro –> {} –macOS 12 beta 6 with M1 Mac mini –> {"080-1111-2222", "030-1234-5678"}–macOS 12.3beta1 with M1 Mac mini on extractPhoneNumberFromNaturalText(aString) set anNSString to current application’s NSString’s stringWithString:aString set {theDetector, theError} to current application’s NSDataDetector’s dataDetectorWithTypes:(current application’s NSTextCheckingTypePhoneNumber) |error|:(reference) set theMatches to theDetector’s matchesInString:anNSString options:0 range:{0, anNSString’s |length|()} set theResults to theMatches’s valueForKey:"phoneNumber" return theResults as list end extractPhoneNumberFromNaturalText |
不可視プロセスで表示したNSAlertを最前面に表示
コンテクストメニューからAppleScriptを実行するツール「Service Station」を連日こづき回していろいろ試しています。
その中で、Service StationではScript実行をGUIなしの補助プログラムからosascriptコマンドを経由してAppleScriptを実行しているために、AppleScript中でNSAlertによるダイアログ表示をおこなった際に、ダイアログが最前面に表示されないという問題が生じていました。
これを見たedama2さんから、強制的にNSAlertダイアログを最前面に表示させるコードを提供していただいたので、実際にテストに用いたAppleScriptに入れたものをご紹介します。
▲そのまま普通にNSAlertダイアログを表示させたところ。Service Stationによるコンテクストメニューから実行すると、最前面に表示されないという問題があった
▲edama2さんからもたらされたコードを追加したNSAlertダイアログ。Service Stationから実行しても、問題なく最前面に表示される
コードは2行、効き目はばっちり!
--Move to frontmost (By edama2) current application's NSApplication's sharedApplication()'s setActivationPolicy:(current application's NSApplicationActivationPolicyRegular) current application's NSApp's activateIgnoringOtherApps:(true)
副作用として、Dockにターミナルのアイコンが表示され、最前面のアプリケーションが「osascript」になってしまいますが、気にならないところでしょう。
Program Name | Name of runtime | Support AppleScript document format | AS Format | NSAlert dialog is displayed in frontmost | Can use GUI Scripting functions | Can call AppleScript Libraries? | Can call AS Library including Frameworks? | Can call Generic Cocoa Functions? | Can use Cocoa system notification functions? |
Service Station | osascript | Script/Text Script/Applet | Script/Text Script | No-> Yes | Yes | Yes | No | Yes | No |
Script Menu | osascript | Script/Scriptd/Applet | Script/Scriptd | Yes | Yes | Yes | No | Yes | Yes |
Shortcuts Events | MacHelper | File Embedded Script | Text | Yes | Yes | Yes | No | Yes | No |
Switch Control | Assistive Control | File Embedded Script | Script (archived) | Yes | Yes | No | No | Yes | No |
FastScript 3 | FastScripts Script Runner | Script/Scriptd/Applet | Script/Scriptd | Yes | Yes | Yes | No | Yes |
あれ? edama2さんのおかげで、Service Stationの弱点が1つなくなりましたよ。Service Stationについては、
(1)「Kind–> Script」「AppleScript」でテキストで書いた「.applescript」しかピックアップできないとかいう気の狂ったようなRulesの仕様は要・修正
(2)実行Scriptにフラットな.scptとテキストの.applescriptしか実行できないのはダメ。バンドル形式の.scptdの実行サポートは必須
(3)大量のAppleScriptをコンテクストメニューに入れると使い勝手が落ちるので、Rulesでもう少しこまかく条件付けできるとよさそう。ただし必須ではない
といったところでしょうか。
AppleScript名:Webダイアログ表示(強制最前面).scpt |
use AppleScript version "2.4" use scripting additions use framework "Foundation" my serviceStationDidSelect("", "", "") on serviceStationDidSelect(targetedURL, selectedItemURLs, menuKind) set aList to {{label:"TEST1", value:403}, {label:"TEST2", value:301}, {label:"TEST3", value:101}, {label:"TEST4", value:65}} set bList to sortRecListByLabel(aList, {"value"}, {false}) of me –降順ソート –https://www.amcharts.com/demos/pie-chart/ set myStr to retHTML() of me set jsonStr to array2DToJSONArray(bList) of me as string set aString to current application’s NSString’s stringWithFormat_(myStr, jsonStr) as string set paramObj to {myMessage:"Simple Pie Chart", mySubMessage:"This is a AMCharts test", htmlStr:aString, viewSize:{1000, 550}} my webD’s displayWebDialog(paramObj) end serviceStationDidSelect on array2DToJSONArray(aList) set anArray to current application’s NSMutableArray’s arrayWithArray:aList set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding) return resString end array2DToJSONArray –リストに入れたレコードを、指定の属性ラベルの値でソート on sortRecListByLabel(aRecList as list, aLabelStr as list, ascendF as list) set aArray to current application’s NSArray’s arrayWithArray:aRecList set aCount to length of aLabelStr set sortDescArray to current application’s NSMutableArray’s new() repeat with i from 1 to aCount set aLabel to (item i of aLabelStr) set aKey to (item i of ascendF) set sortDesc to (current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabel ascending:aKey) (sortDescArray’s addObject:sortDesc) end repeat return (aArray’s sortedArrayUsingDescriptors:sortDescArray) as list end sortRecListByLabel script webD — – Created by: Takaaki Naganoya – Created on: 2020/06/20 — – Copyright © 2020 Piyomaru Software, All Rights Reserved — use AppleScript use framework "Foundation" use framework "AppKit" use framework "WebKit" use scripting additions property parent : AppleScript property |NSURL| : a reference to current application’s |NSURL| property NSAlert : a reference to current application’s NSAlert property NSString : a reference to current application’s NSString property NSButton : a reference to current application’s NSButton property WKWebView : a reference to current application’s WKWebView property WKUserScript : a reference to current application’s WKUserScript property NSURLRequest : a reference to current application’s NSURLRequest property NSRunningApplication : a reference to current application’s NSRunningApplication property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding property WKUserContentController : a reference to current application’s WKUserContentController property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd property returnCode : 0 on displayWebDialog(paramObj) my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true end displayWebDialog on browseStrWebContents:paramObj set aMainMes to myMessage of paramObj as string set aSubMes to mySubMessage of paramObj as string set htmlString to (htmlStr of paramObj) as string –set jsDelimList to (jsDelimiters of paramObj) as list set webSize to (viewSize of paramObj) as list copy webSize to {aWidth, aHeight} –WebViewをつくる set aConf to WKWebViewConfiguration’s alloc()’s init() set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf aWebView’s setNavigationDelegate:me aWebView’s setUIDelegate:me aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true using terms from scripting additions set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me)) end using terms from aWebView’s loadHTMLString:htmlString baseURL:(bURL) –Move to frontmost (By edama2) current application’s NSApplication’s sharedApplication()’s setActivationPolicy:(current application’s NSApplicationActivationPolicyRegular) current application’s NSApp’s activateIgnoringOtherApps:(true) — set up alert set theAlert to NSAlert’s alloc()’s init() tell theAlert its setMessageText:aMainMes its setInformativeText:aSubMes its addButtonWithTitle:"OK" –its addButtonWithTitle:"Cancel" its setAccessoryView:aWebView set myWindow to its |window| end tell — show alert in modal loop NSRunningApplication’s currentApplication()’s activateWithOptions:0 my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true if (my returnCode as number) = 1001 then error number -128 ##後始末 aWebView’s stopLoading() set js to "window.open(’about:blank’,’_self’).close();" aWebView’s evaluateJavaScript:js completionHandler:(missing value) set aWebView to missing value end browseStrWebContents: on doModal:aParam set (my returnCode) to (aParam’s runModal()) as number end doModal: on viewDidLoad:aNotification return true end viewDidLoad: on fetchJSSourceString(aURL) set jsURL to |NSURL|’s URLWithString:aURL set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value) return jsSourceString end fetchJSSourceString on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string) using terms from scripting additions set a1Offset to offset of s1Str in aStr if a1Offset = 0 then return false set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr set a2Offset to offset of s2Str in bStr if a2Offset = 0 then return false set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr return cStr as string end using terms from end pickUpFromToStr –リストを任意のデリミタ付きでテキストに on retArrowText(aList, aDelim) using terms from scripting additions set aText to "" set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to aDelim set aText to aList as text set AppleScript’s text item delimiters to curDelim return aText end using terms from end retArrowText on array2DToJSONArray(aList) set anArray to current application’s NSMutableArray’s arrayWithArray:aList set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding) return resString end array2DToJSONArray on parseByDelim(aData, aDelim) using terms from scripting additions set curDelim to AppleScript’s text item delimiters set AppleScript’s text item delimiters to aDelim set dList to text items of aData set AppleScript’s text item delimiters to curDelim return dList end using terms from end parseByDelim end script on retHTML() return "<!doctype html> <head> <meta charset=\"utf-8\"> <!– Styles –> <style> body { background-color: #000000; color: #ffffff; } #chartdiv { width: 100%; height: 500px; } </style> <!– Resources –> <!– Chart code –> // Themes begin // Create chart instance // Add data // Add and configure Series // This creates initial animation chart.hiddenState.properties.radius = am4core.percent(0); }); // end am4core.ready() <!– HTML –> end retHTML |