Menu

Skip to content
AppleScriptの穴
  • Home
  • Products
  • Books
  • Docs
  • Events
  • Forum
  • About This Blog
  • License
  • 仕事依頼

AppleScriptの穴

Useful & Practical AppleScript archive. Click '★Click Here to Open This Script' Link to download each AppleScript

月: 2019年11月

指定のフォントとサイズに該当するテキストを抽出する v2

Posted on 11月 30, 2019 by Takaaki Naganoya

macOS標準搭載のテキストエディタ「テキストエディット」の最前面のドキュメントから書式情報を取得し、フォント名とフォントサイズのペアをスタイルを反映させたポップアップメニューで選択。選択したスタイルが該当する箇所を抽出したのちにテキスト化してTextViewで結果を表示します。

–> Download Code-signed AppleScript applet executable with libraries


▲Sample RTF(なんでもOK)


▲添付のAppleScriptアプレットは、初回実行時に制御許可のダイアログが表示されます。OKすれば、2回目以降はダイアログ表示されません


▲書式情報をRTF書類から読み込んで、スタイルを反映させたポップアップメニューで表示。サンプル文をRTF書類から取得しているものの、改行部分だけがヒットしたりとなかなかうまくありません


▲一覧から選択


▲RTF書類から指定書式に相当するテキストを抽出して出力

AppleScript名:指定のフォントとサイズに該当するテキストを抽出する v2.scptd
— Created 2019-11-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use wgMenuLib : script "wysiwygMenuLib" –WYSIWYGポップアップメニューダイアログ ライブラリ
use dtLib : script "dTextView" –TextView表示ライブラリ

script spd
  property fontList : {}
  
property fontSizes : {}
  
property textList : {}
  
property outList : {}
  
property combiList : {}
end script

set (outList of spd) to {}
set (fontList of spd) to {}
set (fontSizes of spd) to {}
set (textList of spd) to {}
set (combiList of spd) to {}

–TextEdit書類から書式情報を根こそぎ取得
tell application "TextEdit"
  tell text of front document
    set (fontList of spd) to font of every attribute run –フォント名
    
set (fontSizes of spd) to size of every attribute run –文字サイズ
    
set (textList of spd) to character of every attribute run –文字
  end tell
end tell

–ポップアップメニュー選択用のデータを作成
set aLen to length of (fontList of spd)
set menuList to {}
set sampleList to {}
repeat with i from 1 to aLen
  set tmpFont to contents of item i of (fontList of spd)
  
set tmpSize to contents of item i of (fontSizes of spd)
  
set tmpSample to (contents of item i of (textList of spd)) as string
  
set tmpList to {tmpFont, tmpSize}
  
if {tmpList} is not in (combiList of spd) then
    set the end of (combiList of spd) to tmpList
    
set the end of menuList to (tmpFont & " — " & tmpSize as string) & " point ex.:" & tmpSample
  end if
end repeat

–WYSIWYGポップアップメニューで項目選択
set paramObj to {myMessage:"Select Attribute", mySubMessage:"Select target attribute", segmentMes:{menuList}, segmentTitles:{"Select combination of font name and size"}, segmentAttributes:(combiList of spd)}
set fRes to makeMenuAndcheck(paramObj) of wgMenuLib
if fRes = 0 then return

copy item (first item of fRes) of (combiList of spd) to {aFont, aSize}

–取得した条件にもとづいて、根こそぎ取得した書式と照合を行いつつループ
repeat with i from 1 to length of (fontList of spd)
  set tmpFont to contents of item i of (fontList of spd)
  
set tmpSize to contents of item i of (fontSizes of spd)
  
  
–文字サイズをざっくり判定することで「大、中、小」といったおおまかな切り分けも可能
  
if {tmpFont, tmpSize} = {aFont, aSize} then
    set tmpCon to (contents of item i of (textList of spd)) as string
    
if tmpCon does not contain "•" then –ごみ取り
      set the end of (outList of spd) to tmpCon
    end if
  end if
end repeat

–結果をTextViewで表示
set aStr to retListedText(outList of spd, return) of me
set eRes to (display text view aStr main message "Result" sub message "" with properties {font name:aFont, size:aSize, width:800, height:400})

on retListedText(aList, aSeparator)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aSeparator
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retListedText

★Click Here to Open This Script 

(Visited 52 times, 1 visits today)
Posted in dialog GUI list RTF | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

Double PDF v2.0完成に近づく

Posted on 11月 29, 2019 by Takaaki Naganoya

Mac App Storeで販売したはいいものの、途中(macOS 10.13)でド派手なバグをOS(PDFView)に作られ、AppleのDevelopper Supportに正式に連絡してもなしのつぶてでそのままMac App Storeに置かれている「Double PDF」。さすがに現状のままだとまずすぎるので、macOS 10.14/10.15上で動作するように改修作業を行なっている今日このごろ(macOS 10.13.xでは、動くことは動くんですがOS自体の未修正バグが多すぎて動作保証いたしかねます)。

# OSをアップデートすると機能が落ちるとは何事だろう?

PDFViewのド派手なバグ(currentPageを取得できない)を回避するために、自前でAppleScriptでいろいろ回避コードを走らせているので、ページめくりのスピードが落ちています(個人的にこれのために作ったので、テンションが落ちるところです)。

初版では画像処理にGPUImage.frameworkを同梱して利用していましたが、GPUImage1だとOpenGL経由でGPUの機能にアクセスしており、OpenGL自体が最新のmacOS 10.15では非推奨となっており、Mac App Storeでリジェクトされる危険性があります(より新しい代替APIであるMetalを使わないと因縁を付けられる気が、、、)。

そこで、GPUImageに依存しているコードをすべて書き換え、GPUImageを完全に取り外しました。これには、よくよく調べたら、PDFの各ページをグレースケール画像に変換する箇所でしか利用していなかったことが大きいです。これで、名実ともに「すべてAppleScriptで記述したアプリケーション」に。

GPUImageの除去は使い勝手には一切影響しません。若干の前向きな機能追加も行なっておきましょう。

これまでに意見として寄せられていないものの、どうもグレースケール画像で比較を行うことに不満を持っていたユーザーが一定数いるものとにらんでいたので、カラーのまま比較する機能を追加しました。

正直なところ、「カラー比較モード」は個人的には不要と思っている(文字主体の書籍の校正用に作った)のですが、念のためです。

Double PDFはデータ上のささいな違いを「見逃す」ように作ってあります。これは、Adobe AcrobatのPDF比較機能が、見た目には影響を及ぼさないデータ上の些細な違いばかりピックアップして実用性がまったくないことから思いついたものです。見た目に影響のない差異を見逃して、見た目や文字で差が発生している箇所を指摘するツールという味付けになっています。

画像サイズを小さくした上でグレースケール化して比較するのはそのための重要な機能です。ただ、間違って色が変わったことを検出したいような用途もあることでしょう。

あとは、PDFからテキスト抽出をしたときに、PDF書き出し時の環境(OSバージョン)によってはNo Width Spaceが検出されるものがあるため、No Width Spaceの削除機能を追加しました。

細かい箇所でまだ不具合点(右側のビューワーのノンブルが表示されないことがある)がありますが、とりあえず出してみてもよさそうな気配はしています。

地味なところで画像素材をDark Mode対応させました。Credits.rtfのダークモード対応など、地味に工数が増えるのは勘弁してほしいです。あとは、外部アプリケーション操作要求を行うためのInfo.plistのエントリ追加などもあります。これを追加しないと外部アプリケーションへの操作要求のダイアログ自体が出ない=一切操作できないので要注意点です。

ほかにも、現行のXcodeでCocoa AppleScriptアプリケーションのプロジェクトを作ると、デフォルトではソースコード開示状態のビルドセッティングになってしまうので、これも要チェック点でしょう。まさかと思ってこの設定を再確認してみたら、execute onlyになっていませんでした。怖すぎ、、、

(Visited 50 times, 1 visits today)
Posted in AppleScript Application on Xcode Image PDF | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy | Leave a comment

指定のNSImageをグレースケールに

Posted on 11月 29, 2019 by Takaaki Naganoya

指定のNSImageをグレースケール画像にしたのちNSImageで出力するAppleScriptです。

GPUImageをプログラムから取り外すにあたって必要になったので用意しました。ふだん、画像変換系のScriptはNSImageで入力したのちにファイルに出力するように組んであったのですが、入出力ともにNSImageにしてあるプログラムが手元に存在していなかったので。

GPUImageが自分にとって使いやすかったのは、入出力にNSImageが使えたからだと思います。CGImageだとAppleScriptからアクセスできないですし、CIImageもアクセスできないわけではないですが、ちょっと遠回りになります。

AppleScript名:指定のNSImageをグレースケールに
— Created 2019-07-09 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property NSColorSpace : a reference to current application’s NSColorSpace
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep
property NSColorRenderingIntentPerceptual : a reference to current application’s NSColorRenderingIntentPerceptual

set aFile to POSIX path of (choose file of type {"public.image"} with prompt "Select Image A")
set aImage to NSImage’s alloc()’s initWithContentsOfFile:aFile

set gImage to convNSIMageAsGray(aImage) of me

–NSImageをグレースケールに変換してNSImageで返す
on convNSIMageAsGray(anImage)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep
  
  
set bRawimg to convBitMapToDeviceGrey(aRawimg) of me
  
  
set bImage to NSImage’s alloc()’s initWithSize:(bRawimg’s |size|())
  
bImage’s addRepresentation:bRawimg
  
  
return bImage
end convNSIMageAsGray

–NSBitmapImageRepをグレースケールに変換する
on convBitMapToDeviceGrey(aBitmap)
  set aSpace to NSColorSpace’s deviceGrayColorSpace()
  
set bRawimg to aBitmap’s bitmapImageRepByConvertingToColorSpace:aSpace renderingIntent:(NSColorRenderingIntentPerceptual)
  
return bRawimg
end convBitMapToDeviceGrey

★Click Here to Open This Script 

(Visited 42 times, 1 visits today)
Posted in Color Image | Tagged 10.13savvy 10.14savvy 10.15savvy NSBitmapImageRep NSColorRenderingIntentPerceptual NSColorSpace NSImage NSString | Leave a comment

URLエンコードずみ文字列チェック

Posted on 11月 29, 2019 by Takaaki Naganoya

与えられた文字列がURLエンコードずみ文字列かどうかをチェックするAppleScriptです。

なんでそんなものが必要になったかといえば、macOS 10.15のPDFView上で発生した(”applescript://” schemeの)URL EventがデコードされずにOSデフォルト指定のスクリプトエディタに転送される、URLデコード不良バグが発生。これに対処した簡易PDFビューワーも用意しましたが、macOS 10.15.2 Beta3でこのバグが修正されているように見えます。

# 一度発生したバグは、今後もAppleが再発しないよう継続して監視する必要があります

すると、今度は簡易PDFビューワー側でURLイベントをデコードしてからScript Editorに転送している処理が「余計」になってしまいます。再デコードした文字列は途中で途切れてしまうので、処理対象の文字列がURLエンコードされたものかどうかをチェックする必要が出てきました。

このままOSにURLデコード不良バグが残存するよりは、こうしたプログラムでチェックしてから処理するほうがよいでしょう。

AppleScript名:URLエンコードずみ文字列チェック.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/29
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString

set aStr to "applescript://com.apple.scripteditor?action=new&script=display%20dialog%20%22TEST%22"
set aRes to chkEncodedURLorNot(aStr) of me
–> true –URL Encoded

set bStr to "display dialog \"TEST\""
set bRes to chkEncodedURLorNot(bStr) of me
–> false –Not URL encoded

on chkEncodedURLorNot(aStr)
  set nsStr to NSString’s stringWithString:aStr
  
set decodedStr to nsStr’s stringByRemovingPercentEncoding()
  
  
if (nsStr’s isEqualToString:decodedStr) then
    return false –encoded URL
  else
    return true –Not encoded URL
  end if
end chkEncodedURLorNot

★Click Here to Open This Script 

(Visited 39 times, 1 visits today)
Posted in Text URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSString NSURL | Leave a comment

[作業中]Double PDF 改修中

Posted on 11月 28, 2019 by Takaaki Naganoya

AppleがPDFViewのScripting Bridge関連データにバグを作り、レポートしても一向に直さないため、Mac App Storeに出しているものの、macOS 10.13以降のOSでは正常動作しない、Piyomaru Software謹製のPDF差分ブラウザ「Double PDF」。

Appleが作ったバグのせいで基礎的な動作が阻害されてしまっているので、機能アップは一切考えないで(機能アップ版として別のものを作っていたので)、Double PDFについては現在のOSで動くレベルで改修をすすめています(作業量が見えない、、、、)。

–> Demo Movie of Current Version of Double PDF v2.0 (on macOS 10.14.6)

AppleScriptの箱庭世界でモノを作っている分には環境変化は割と穏やかですが、直接Cocoaの機能に手を出しはじめると、OSバージョンごとの無意味な名称改変とか、予告なしの仕様変更とか、このような未改修のバグに直面することがあり、Mac OS X 10.3で「is in」という基礎的かつ重要な演算子にバグを作られた時と同質の負の感情を喚起されるものがあります。

正式にDevelopper Supportの窓口から詳細に症状を伝えてレポートしても無視されているので、AppleのDevelopper Supportもバグの報告でパンクしているということでしょうか。macOS 10.13以降、バグレポートしても返事も来ないのが日常化してしまったので(AppleScript関連ではないバグがほとんどなのですが)、バグを直す気がないんでしょうか。


▲macOS 10.14.6上で改修中。まだ画面操作まわりに着手しただけ


▲macOS 10.15.1上で動作確認。最近のmacOSはBetaで動作確認してもRelease版の品質がBeta以下なので、Beta上で確認する意義が、、、

Appleによって破壊された機能は、PDFViewまわりの基礎的な機能。

- (IBAction)goToFirstPage:(nullable id)sender;
- (IBAction)goToLastPage:(nullable id)sender;
- (IBAction)goToNextPage:(nullable id)sender;
- (IBAction)goToPreviousPage:(nullable id)sender;

@property (nonatomic, readonly, nullable) PDFPage *currentPage;

などです(他にもあるかも。いや、確実にある)。つまり、PDFビューワー機能を作ろうとすると、いろいろ苦労させられる状態です。

苦労が必要ということは、余計に処理時間が必要ということで、処理速度はオリジナル版よりも遅くなっています。とくに、PDFのページめくりが、、、


▲開発時に資料を作っておかなかったらもっと大変、、、、、

(Visited 93 times, 1 visits today)
Posted in news PRODUCTS | Tagged 10.14savvy 10.15savvy | Leave a comment

ジャンル名名寄せ v2

Posted on 11月 27, 2019 by Takaaki Naganoya

iTunes/Musicのライブラリに入っている楽曲データのジャンル分けのゆらぎ吸収を行う、ジャンル名のいわゆる「名寄せ」を行うAppleScriptです。


▲1つのアルバム中でもジャンル名に表記ゆれがあるのは勘弁してほしい

iTunes/Musicライブラリ中の全楽曲の最終再生日時を24時間の各時で集計を行い、ジャンルごとに再生時間に偏りがないかどうかを分析するため、さらにジャンルごろに集計してみました。

「名寄せ」(なよせ)は昔から情報処理に見られる泥臭い地道な処理で、データ上の表記ゆれを吸収するための処理です。地名などの固有名詞で多く見られます(念のためにWikipediaで調べたら、異なる業界では割とブラックな言葉として用いられている模様)。

このジャンル名が英語で入っていたり日本語で入っていたりと、ゆらぎが発生しているので、同様のジャンル名であれば同じものとして合算して集計してみました。

また、英語で表記されたジャンル名ではなく日本語で表記されたものを採用(=すべてアルファベットで書かれたものを不採用)しています。まだ、それほどいじめ抜いていない(自分の環境でしかテストしていない)ので、ジャンル名の名寄せリストはもう少し鍛えておく必要があるものと思っています。

AppleScript名:ジャンル名名寄せ v2
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/24
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use scripting additions

property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSScanner : a reference to current application’s NSScanner
property NSPredicate : a reference to current application’s NSPredicate
property NSMutableCharacterSet : a reference to current application’s NSMutableCharacterSet

–ジャンル名寄せリスト(2要素から構成される2D List)
set genreNayoseList to {{"World", "ワールド"}, {"Anime", "アニメ"}, {"Electronic", "エレクトロニック"}, {"R&B/ソウル", "R&B/ソウル"}, {"Kayokyoku", "歌謡曲"}, {"Electronic", "エレクトロニック"}, {"Vocal", "ヴォーカル"}, {"Classical", "クラシック"}, {"Dance", "ダンス"}, {"Soundtrack", "サウンドトラック"}}

–名寄せ対象リスト(genreNameを名寄せ)
set aList to {{genreName:"シンガーソングライター", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 0, 0, 0, 1, 5, 0, 0, 0, 0}}, {genreName:"ロック", playingList:{2, 2, 0, 0, 0, 1, 0, 0, 4, 3, 9, 5, 11, 11, 22, 19, 48, 17, 28, 15, 2, 11, 13, 1}}, {genreName:"Soundtrack", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, {genreName:"World", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, {genreName:"演歌", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"ホリデーミュージック", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"ディズニー", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0}}, {genreName:"J-Pop", playingList:{4, 0, 1, 1, 2, 1, 5, 3, 2, 3, 27, 19, 14, 26, 17, 20, 28, 32, 40, 25, 10, 10, 6, 6}}, {genreName:"ヒップホップ/ ラップ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"Electronic", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"アニメ", playingList:{7, 1, 0, 0, 7, 2, 0, 0, 0, 9, 23, 45, 17, 10, 17, 50, 48, 65, 53, 27, 12, 16, 23, 45}}, {genreName:"ポップ", playingList:{3, 0, 0, 0, 0, 0, 0, 3, 1, 6, 2, 9, 7, 0, 11, 7, 8, 10, 7, 5, 3, 1, 0, 1}}, {genreName:"Kayokyoku", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}}, {genreName:"ヒップホップ/ラップ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"Dance", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}}, {genreName:"ダンス", playingList:{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 2, 0, 0}}, {genreName:"R&B/ソウル", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"Anime", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0}}, {genreName:"チルドレン・ミュージック", playingList:{0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"Classical", playingList:{1, 1, 0, 0, 2, 1, 8, 1, 0, 0, 11, 5, 2, 0, 4, 9, 13, 2, 2, 0, 0, 0, 0, 0}}, {genreName:"ニューエイジ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 12, 0, 0, 0, 0}}, {genreName:"Pop", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, {genreName:"ヴォーカル", playingList:{0, 0, 0, 0, 0, 1, 0, 0, 0, 6, 7, 0, 0, 1, 6, 0, 0, 3, 1, 0, 3, 0, 0, 0}}, {genreName:"サウンドトラック", playingList:{23, 31, 0, 0, 0, 2, 1, 0, 7, 7, 27, 29, 26, 25, 28, 48, 66, 76, 56, 16, 8, 31, 6, 10}}, {genreName:"歌謡曲", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 4, 5, 5, 4, 6, 6, 7, 1, 0, 0, 0}}, {genreName:"ホリデー", playingList:{0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0}}, {genreName:"Folk", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}}, {genreName:"ジャズ", playingList:{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 16, 7, 3, 9, 0, 5, 10, 20, 10, 2, 1, 0, 0}}, {genreName:"エレクトロニック", playingList:{0, 1, 3, 0, 0, 0, 0, 1, 4, 13, 8, 13, 2, 18, 6, 13, 10, 16, 25, 7, 8, 0, 2, 10}}, {genreName:"ワールド", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 5, 5, 7, 6, 0, 0, 0, 0, 0}}, {genreName:"インストゥルメンタル", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}}, {genreName:"Vocal", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"クラシック", playingList:{0, 0, 1, 1, 0, 3, 2, 0, 4, 3, 13, 11, 24, 1, 21, 14, 24, 38, 21, 7, 5, 8, 4, 5}}, {genreName:"オルタナティブ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 1, 0, 0, 6, 9, 0}}, {genreName:"R&B/ソウル", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}

set bList to genreNayoseAndUnify(aList, genreNayoseList) of me
–> {{genreName:"シンガーソングライター", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 1, 0, 0, 0, 1, 5, 0, 0, 0, 0}}, {genreName:"ロック", playingList:{2, 2, 0, 0, 0, 1, 0, 0, 4, 3, 9, 5, 11, 11, 22, 19, 48, 17, 28, 15, 2, 11, 13, 1}}, {genreName:"サウンドトラック", playingList:{23, 31, 0, 0, 0, 2, 1, 0, 7, 7, 28, 29, 26, 25, 28, 48, 66, 77, 56, 16, 8, 31, 6, 10}}, {genreName:"ワールド", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 0, 5, 5, 8, 6, 0, 0, 0, 0, 0}}, {genreName:"演歌", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"ホリデーミュージック", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"ディズニー", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0}}, {genreName:"J-Pop", playingList:{4, 0, 1, 1, 2, 1, 5, 3, 2, 3, 27, 19, 14, 26, 17, 20, 28, 32, 40, 25, 10, 10, 6, 6}}, {genreName:"ヒップホップ/ ラップ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"エレクトロニック", playingList:{0, 1, 3, 0, 0, 0, 0, 1, 4, 13, 8, 13, 2, 19, 6, 13, 10, 16, 25, 7, 8, 0, 2, 10}}, {genreName:"アニメ", playingList:{7, 1, 0, 0, 7, 2, 0, 0, 0, 9, 23, 52, 17, 10, 17, 50, 49, 67, 54, 27, 12, 16, 23, 45}}, {genreName:"ポップ", playingList:{3, 0, 0, 0, 0, 0, 0, 3, 1, 6, 2, 9, 7, 0, 11, 7, 8, 10, 7, 5, 3, 1, 0, 1}}, {genreName:"歌謡曲", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 4, 5, 5, 4, 6, 7, 7, 1, 0, 0, 0}}, {genreName:"ヒップホップ/ラップ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"ダンス", playingList:{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0}}, {genreName:"R&B/ソウル", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"チルドレン・ミュージック", playingList:{0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, {genreName:"クラシック", playingList:{1, 1, 1, 1, 2, 4, 10, 1, 4, 3, 24, 16, 26, 1, 25, 23, 37, 40, 23, 7, 5, 8, 4, 5}}, {genreName:"ニューエイジ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 12, 0, 0, 0, 0}}, {genreName:"Pop", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0}}, {genreName:"ヴォーカル", playingList:{0, 0, 0, 0, 0, 1, 0, 0, 0, 6, 7, 0, 0, 1, 6, 1, 0, 3, 1, 0, 3, 0, 0, 0}}, {genreName:"ホリデー", playingList:{0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0}}, {genreName:"Folk", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}}, {genreName:"ジャズ", playingList:{0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 16, 7, 3, 9, 0, 5, 10, 20, 10, 2, 1, 0, 0}}, {genreName:"インストゥルメンタル", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}}, {genreName:"オルタナティブ", playingList:{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 1, 0, 0, 6, 9, 0}}}

on genreNayoseAndUnify(aList as list, genreNayoseList as list)
  set gList to FlattenList(genreNayoseList) of me
  
  
set didProc to {}
  
  
set a2List to {}
  
  
repeat with i in aList
    set aGenre to genreName of i
    
    
if (aGenre is in gList) and (aGenre is not in didProc) then
      
      
repeat with ii in genreNayoseList
        set jj to contents of ii
        
        
if aGenre is in jj then
          copy jj to {g1, g2}
          
          
          
if chkAlphabet(g1) of me = true then
            set targG to g2
            
set targG2 to g1
          else
            set targG to g1
            
set targG2 to g2
          end if
          
          
set s1Res to searchByGenreName(aList, targG) of me
          
set s2Res to searchByGenreName(aList, targG2) of me
          
          
set s3Res to addMutipleLists({s1Res, s2Res}) of me
          
          
set outRec to {genreName:targG, playingList:s3Res}
          
set the end of didProc to g1
          
set the end of didProc to g2
          
          
exit repeat
        end if
        
      end repeat
      
      
set the end of a2List to outRec
    else
      if (aGenre is not in didProc) then
        set the end of a2List to contents of i
      end if
    end if
  end repeat
  
  
return a2List
end genreNayoseAndUnify

on searchByGenreName(aList as list, aGenreName as string)
  set predicatesStr to "genreName == ’" & aGenreName & "’"
  
set anArray to (NSArray’s arrayWithArray:aList)
  
set aPred to (NSPredicate’s predicateWithFormat:predicatesStr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred)
  
  
set bbRes to first item of bRes
  
return (playingList of bbRes) as list
end searchByGenreName

on addMutipleLists(s1List)
  script spdAdd
    property s1List : {}
    
property s3List : {}
  end script
  
  
copy s1List to (s1List of spdAdd) –init
  
  
set s1Len to length of first item of (s1List of spdAdd)
  
set (s3List of spdAdd) to makeZero1DList(s1Len, 0) of me
  
  
repeat with i in (s1List of spdAdd)
    set tmpLen to length of i
    
if tmpLen is not equal to s1Len then return false
    
    
repeat with ii from 1 to s1Len
      set tmp1 to contents of item ii of (s3List of spdAdd)
      
set tmp2 to contents of item ii of i
      
      
set item ii of (s3List of spdAdd) to (tmp1 + tmp2)
    end repeat
  end repeat
  
  
return (s3List of spdAdd)
end addMutipleLists

–指定要素を指定回数追加したリストを作成する
on makeZero1DList(itemMax, itemElem)
  set allData to {}
  
repeat itemMax times
    set the end of allData to itemElem
  end repeat
  
return allData
end makeZero1DList

–By Paul Berkowitz
–2009年1月27日 2:24:08:JST
–Re: Flattening Nested Lists
on FlattenList(aList)
  set oldDelims to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {"????"}
  
set aString to aList as text
  
set aList to text items of aString
  
set AppleScript’s text item delimiters to oldDelims
  
return aList
end FlattenList

— アルファベットのみか調べて返す
on chkAlphabet(checkString)
  set aStr to NSString’s stringWithString:checkString
  
set allCharSet to NSMutableCharacterSet’s alloc()’s init()
  
allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "a", 26))
  
allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "A", 26))
  
set aBool to my chkCompareString:aStr baseString:allCharSet
  
return aBool as boolean
end chkAlphabet

on chkCompareString:checkString baseString:baseString
  set aScanner to NSScanner’s localizedScannerWithString:checkString
  
aScanner’s setCharactersToBeSkipped:(missing value)
  
aScanner’s scanCharactersFromSet:baseString intoString:(missing value)
  
return (aScanner’s isAtEnd()) as boolean
end chkCompareString:baseString:

★Click Here to Open This Script 

(Visited 70 times, 3 visits today)
Posted in list Record | Tagged 10.13savvy 10.14savvy 10.15savvy NSArray NSMutableCharacterSet NSPredicate NSScanner NSString | Leave a comment

1D Listの加算

Posted on 11月 26, 2019 by Takaaki Naganoya

2つの1D List(1次元配列)同士を加算するAppleScriptです。

よく書き捨てていますが、AppleScriptにそんな命令はないのでループで加算することになります。

最近では、Musicの楽曲ライブラリ中の曲の、カテゴリごとの最終再生日時の分布集計を行なったときに、「Classical」「クラシック」などの表記ゆれを吸収するために、これらの複数カテゴリのデータを合成するときに使いました。

AppleScript名:1D Listの加算
set s1List to {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}
set s2List to {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 4, 5, 5, 4, 6, 6, 7, 1, 0, 0, 0}

set sRes to addTwoList(s1List, s2List) of me
–> {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 4, 5, 5, 4, 6, 7, 7, 1, 0, 0, 0}

on addTwoList(s1List, s2List)
  set s3List to {}
  
set s1Len to length of s1List
  
set s2Len to length of s2List
  
if s1Len is not equal to s2Len then return false
  
  
repeat with ii from 1 to s1Len
    set tmp1 to contents of item ii of s1List
    
set tmp2 to contents of item ii of s2List
    
    
set the end of s3List to (tmp1 + tmp2)
  end repeat
  
  
return s3List
end addTwoList

★Click Here to Open This Script 

書き捨てレベルだとこんな感じ(↑)ですが、今後使い回すことを考えて書いておくと、こんな感じ(↓)でしょうか。データ数が増えたときの対策と、複数の1D Listを連続して大量に加算する必要が発生した際への対策を行なっています。

AppleScript名:1D List同士の加算 v2
set s1List to {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 4, 5, 5, 4, 6, 6, 7, 1, 0, 0, 0}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}

set sRes to addMutipleLists(s1List) of me
–> {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 3, 5, 6, 7, 6, 8, 8, 8, 2, 1, 1, 1}

on addMutipleLists(s1List)
  script spdAdd
    property s1List : {}
    
property s3List : {}
  end script
  
  
copy s1List to (s1List of spdAdd) –init
  
  
set s1Len to length of first item of (s1List of spdAdd)
  
set (s3List of spdAdd) to makeZero1DList(s1Len, 0) of me
  
  
repeat with i in (s1List of spdAdd)
    set tmpLen to length of i
    
if tmpLen is not equal to s1Len then return false
    
    
repeat with ii from 1 to s1Len
      set tmp1 to contents of item ii of (s3List of spdAdd)
      
set tmp2 to contents of item ii of i
      
      
set item ii of (s3List of spdAdd) to (tmp1 + tmp2)
    end repeat
  end repeat
  
  
return (s3List of spdAdd)
end addMutipleLists

–指定要素を指定回数追加したリストを作成する
on makeZero1DList(itemMax, itemElem)
  set allData to {}
  
repeat itemMax times
    set the end of allData to itemElem
  end repeat
  
return allData
end makeZero1DList

★Click Here to Open This Script 

(Visited 57 times, 1 visits today)
Posted in list | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy | Leave a comment

treeVar(ツリー状のデータ構造をNSBrowserで表示するためのルーチン)

Posted on 11月 24, 2019 by Takaaki Naganoya

ツリー状のデータ構造をNSBrowserで表示するためのデータ抽出を行うAppleScriptです。

NSBrowserでツリー構造のデータを抽出しつつ表示するインタフェースを作るために、その基盤部分となるツリー状のデータを絞り込むプログラムを書いてみました。

やりたいことをそのまま実装してみたもので、著しくどこかに同じ機能を持つものが存在していそうな気がします(NSTreeControllerとか)。

やりたいことは、現在のツリー構造上のアドレスをもとに、2次元配列で与えたツリー構造データ(データそのものがツリー構造なのではなくて、「アドレス情報」文字列がツリー構造になっている普通の2次元配列)から、

{{"1", "File"}, {"2", "Edit"}, {"3", "View"}, {"4", "Search"}, {"1.1", "New Script"}, {"1.2", "New Script From Template"}, {"1.3", "New Script Tab"}, {"1.4", "New Script Tab From Template"}, {"1.5", "Open..."}, {"1.6", "Open Quickly"}, {"1.6.1", "aaaaaaa"}, {"1.6.2", "bbbbbb"}, {"1.6.3", "ccccccc"}, {"1.6.4", "ddddddd"}, {"1.6.5", "eeeeeeeee"}}

該当するツリーアドレスの同一ブランチに存在するデータ一覧を取得するだけなので(日本語でも表現できているかどうか怪しい)、そこの部分だけ実装してテストしてみたものです。

Query List Item Result
{} –> {"File", "Edit", "View", "Search"}
{1} –> {"New Script", "New Script From Template", "New Script Tab", "New Script Tab From Template", "Open…", "Open Quickly"}
{1,6} –> {"aaaaaaa", "bbbbbb", "ccccccc", "ddddddd", "eeeeeeeee"}

よその処理系で見かけた処理なので、広く普遍的に存在していそうな処理ではあるものの、探してみるとなかなかお手軽なものが見つからなかったので、自分で作った次第です。

AppleScript名:treeVar.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/24
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property NSArray : a reference to current application’s NSArray
property NSPredicate : a reference to current application’s NSPredicate

set treeKeyList to {{"1", "File"}, {"2", "Edit"}, {"3", "View"}, {"4", "Search"}, {"1.1", "New Script"}, {"1.2", "New Script From Template"}, {"1.3", "New Script Tab"}, {"1.4", "New Script Tab From Template"}, {"1.5", "Open…"}, {"1.6", "Open Quickly"}, {"1.6.1", "aaaaaaa"}, {"1.6.2", "bbbbbb"}, {"1.6.3", "ccccccc"}, {"1.6.4", "ddddddd"}, {"1.6.5", "eeeeeeeee"}}

set keyList to {1}
set tRes to filterTreeKeyArrayByAddr(treeKeyList, keyList) of me
–> {"New Script", "New Script From Template", "New Script Tab", "New Script Tab From Template", "Open…", "Open Quickly"}

set keyList to {1, 6}
set tRes to filterTreeKeyArrayByAddr(treeKeyList, keyList) of me
–> {"aaaaaaa", "bbbbbb", "ccccccc", "ddddddd", "eeeeeeeee"}

on filterTreeKeyArrayByAddr(aList, keyList)
  set queryStr to ""
  
repeat with i in keyList
    set queryStr to queryStr & (contents of i) & "."
  end repeat
  
  
set queryStr to queryStr & "[0-99]"
  
set predicatesStr to "SELF[0] MATCHES ’" & queryStr & "’"
  
  
set anArray to NSArray’s arrayWithArray:aList
  
set aPred to NSPredicate’s predicateWithFormat:predicatesStr –"SELF[0] MATCHES ’1.[0-99]’"
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred)
  
  
set bList to {}
  
repeat with i in (bRes as list)
    set aTmp to last item of i
    
set the end of bList to aTmp
  end repeat
  
  
return bList
end filterTreeKeyArrayByAddr

★Click Here to Open This Script 

(Visited 146 times, 1 visits today)
Posted in list regexp | Tagged 10.14savvy 10.15savvy | Leave a comment

テキストエディットで指定のフォントとサイズに該当するテキストを抽出する

Posted on 11月 22, 2019 by Takaaki Naganoya

macOS標準搭載のテキストエディタ、「テキストエディット」(TextEdit)をコントロールして、最前面のウィンドウの書類から、指定のフォント名とサイズに該当するテキストを抽出するAppleScriptです。

テキストエディットはApple純正のアプリケーションの割にはAppleScriptサポート機能がよくできていて、選択範囲(selection)を取得できないことをのぞけば、けっこう使えます。

テキストエディットのAppleScript系の機能で最も重要なものは、書類からの書式取得機能(attribute run)です。


▲最前面の書類がリッチテキストフォーマットになっている必要があります


▲Github上のGPUImageのフィルタ紹介文からコピペしてきた文章


▲この書類のこのレベルの見出しだけを抽出したい場合にはHelvetica Neue Bold 20pointを指定


▲この書類のこのレベルの見出しだけを抽出したい場合にはHelvetica Neue Bold 16pointを指定

Webブラウザなどからコピペしてきたスタイル付きテキストから、特定のフォントや文字サイズの箇所を抽出したい場合に使います。

実行すると、リッチテキストで使用されているフォント名とサイズの一覧を生成し、ダイアログでフォント名の選択、

そして、文字サイズの選択を実行。

すると、該当箇所のみ抽出して返します。さらに改行で区切ったテキストに変換するとかいった処理を行なってもよいでしょう。

RTFのファイルを処理するのであれば、テキストエディットを使わなくてもCocoaの機能を用いて同様の処理を行えますが、割と書き捨てレベルの瑣末なScriptなのでテキストエディット経由で書式情報を取得するように組んでみました。

AppleScript名:指定のフォントとサイズに該当するテキストを抽出する
— Created 2019-11-22 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

script spd
  property fontList : {}
  
property fontSizes : {}
  
property textList : {}
  
property outList : {}
end script

set (outList of spd) to {}
set (fontList of spd) to {}
set (fontSizes of spd) to {}
set (textList of spd) to {}

–TextEdit書類から書式情報を根こそぎ取得
tell application "TextEdit"
  tell text of front document
    set (fontList of spd) to font of every attribute run –フォント名
    
set (fontSizes of spd) to size of every attribute run –文字サイズ
    
set (textList of spd) to character of every attribute run –文字
  end tell
end tell

–取得したフォント名一覧から重複部分を除去してどれを対象にするかユーザーに問い合わせ
set fRes to uniquify1DList((fontList of spd), true) of me
set targFont to choose from list fRes
set aFont to contents of first item of targFont

–取得したフォントサイズ一覧から重複部分を除去してどれを対象にするかユーザーに問い合わせ
set sRes to uniquify1DList((fontSizes of spd), true) of me
set targSize to choose from list sRes
set aSize to contents of first item of targSize

–取得した条件にもとづいて、根こそぎ取得した書式と照合を行いつつループ
repeat with i from 1 to length of (fontList of spd)
  set tmpFont to contents of item i of (fontList of spd)
  
set tmpSize to contents of item i of (fontSizes of spd)
  
  
–文字サイズをざっくり判定することで「大、中、小」といったおおまかな切り分けも可能
  
if {tmpFont, tmpSize} = {aFont, aSize} then
    set tmpCon to (contents of item i of (textList of spd)) as string
    
if tmpCon does not contain "•" then –ごみ取り
      set the end of (outList of spd) to tmpCon
    end if
  end if
end repeat

return (outList of spd)

–1D/2D Listをユニーク化
on uniquify1DList(theList as list, aBool as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
if aBool = true then
    return bArray as list
  else
    return bArray
  end if
end uniquify1DList

★Click Here to Open This Script 

(Visited 260 times, 1 visits today)
Posted in Font list RTF Text | Tagged 10.13savvy 10.14savvy 10.15savvy NSArray TextEdit | Leave a comment

CIFilterとGPUImageで画像差分検出演算を比較

Posted on 11月 22, 2019 by Takaaki Naganoya

オープンソースのGPUImage.framework(GPUImage1)はAppleScriptから呼び出すのも簡単ですし、機能セットも充実しており、非常に重宝して使っています。

ただし、GPUImage自体はSwiftで書き直されたGPUImage2、OSの変更を受けてOpenGLではなくMetalを用いるように書き直され、いまだ発展途上のGPUImage3と変化してきました。

・GPUImageのバージョンと搭載フィルタ数の推移

GPUImage1:■■■■■■■■■■■■ 125
GPUImage2:■■■■■■■■■■ 100
GPUImage3:■■■■ 45

GPUImage2/3とバージョンが進むにつれて搭載フィルタ数が減っており、かつGPUImage2以降はAppleScriptから呼べないため、GPUImage3は(自分の)移行先になりません。

Objective-CベースのGPUImage1系のプログラムを使い続けるという判断をしている開発者は多いようで、Github上で派生プログラムが大量にみつかります。ただ、GPUImage1系はmacOSがOpenGLを完全廃止にしたとたんに動かなくなるはずです。

このため、GPUImage1系に依存しているプログラムは別の部品を呼び出して処理する必要が出てきます。

一番有望なのは、macOS標準搭載のCIFilter。CIFilterについては、実際にプログラムを組んでみて「組みにくい」という印象を受けていました(機能はちゃんとしていそうなものの、機能数にドキュメントが見合っていません)。あと、AppleScriptからパラメータを指定しにくいという印象を受けていました(パラメータに指定するオブジェクトにAppleScriptから直接指定できないものがあるので、少しラッパーを書く必要がある)。

その後、各種フィルタを呼び出す汎用ルーチンを整備することで、利用難易度を下げる努力を自主的に行なっています。

・GPUImage3とCoreImageの搭載フィルタ数の比較

GPUImage3:■■■■ 45
CoreImage:■■■■■■■■■■■■■■■■■ 174

そこで、実際に処理速度の面でどうなのか、CIFilterとGPUImageを比較するとどうなのか、調べてみました。

まずは、ざっくりありもののルーチンを引っ張り出してきて実行。どちらも期待どおりの動作をしてくれます。ただし、周辺ルーチンの仕様が違っていたのでそこも合わせます。

乱数ファイル名を作成する定番のshell commandの「uuidgen」はお手軽な反面、呼び出すのに時間がかかるので(手元の時間で0.1秒程度強)、より高速なCocoaのUUIDStringを用いる部品に置き換えました。

それぞれのフレームワークごとの挙動の違いもあります。

経験上、GPUImage.frameworkは初回実行時だけは時間が長くかかる傾向があり(1秒以上かかる)、2回目以降はより短い時間で処理できるようになることを確認しています。一方、CIFilterは初回およびそれ以降の呼び出しでもさほど処理時間が変わりません。

これら2つを実際に同じデータで同一条件下で比較してみたところ、同一の処理(画像の差分計算)を行なったかぎりでは処理時間に差はほとんど有意な差はありませんでした。

Script Geek 2.0.1によるScriptの処理時間比較

First:GPUImage Version , Second:CoreImage Version

MacBookPro10,1,  macOS Version 10.14.6 (Build 18G2012),  10 iterations
         First Run   Total Time    Average  
First        0.969        1.194      0.119
Second       0.121        1.221      0.122
Ratio (excluding first run): 1:1.02

自分のメインマシン(MacBook Pro Retina 2012、Core i7 2.66GHz、RAM 8GB)ではどちらもテストデータ(1192x1684pixel 8bit color image x 2)を0.1〜0.2秒程度で処理できています。個人的には十分なスピードが出ていると感じていますが、不満がある方はデータをRAM Disk上に置いたり、並列処理するとよいのではないでしょうか(シングルスレッド処理が高速なマシンを用意するというのが一番効きそうではあります。iMac 5Kの上位モデルとか)。

すべての類似フィルタで比較を行なったわけではありませんが(どれとどれが類似、という情報を整理するのに手間がかかる)、一番使っている「空白検出のためのヒストグラム計算フィルタ」はGPUImageにしか存在しませんでした(作成当時の話で現在はCoreImageにもCIAreaHistogramなどの機能があります)。

空白検出処理を高速に行えることで巨大なメリットが生じています。用途については枚挙にいとまがありませんが、Markdown書類をPDFにレンダリングした場合に、末尾に無用な空白のページが生じるケースがあり、これを検出しつつ末尾のページを自動削除することで、膨大な無駄手間を削減できています。空白検出処理を高速に行う手段を用意していないと、Photoshopで指定ページをレンダリングしてヒストグラムを計算する必要があるわけで、Photoshopのない環境に進出できなくなります。

空白画像の検出処理はGPUImage.framework抜きで(AppleScriptだけで)2〜3倍高速な処理を行える部品「画像の空白判定 v3」を作成済みなので、GPUImageなしでもさほど困りません。


▲同一環境にて、Photoshop CC 2018、GPUImage、AppleScriptだけで処理している「画像の空白判定 v3」で各種サイズの画像の空白検出を実行(単位:秒)

Objective-C/Swift系の開発者の方々に「GPUImageを経由してGPUのパワーを使って処理するよりも、AppleScript単体で空白の比較演算処理したほうが速かった」という事実をお話しすると、最初は「嘘つけ」というひきつった笑顔の反応なのですが、実際にコードを動かして動作原理を丁寧に説明すると分かっていただけるようです。

–> Download dffFilterDemoPrograms(Two Code-Signed AppleScript Applet Executables with Framework in its bundle)

AppleScript名:CoreImageでCIDifferenceBlendMode.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/22
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "QuartzCore"
use scripting additions

property CIFilter : a reference to current application’s CIFilter
property NSUUID : a reference to current application’s NSUUID
property |NSURL| : a reference to current application’s |NSURL|
property CIImage : a reference to current application’s CIImage
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property NSPNGFileType : a reference to current application’s NSPNGFileType
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep

set mePath to POSIX path of (path to me)
set aImg to mePath & "Contents/Resources/book1_v2.0_0011.jpg"
set bImg to mePath & "Contents/Resources/book1_v2.1_0011.jpg"

–https://developer.apple.com/library/archive/documentation/
–GraphicsImaging/Reference/CoreImageFilterReference/index.html
–#//apple_ref/doc/filter/ci/CIDifferenceBlendMode
set cifilterName to "CIDifferenceBlendMode"

set imgRes to filterBlendImageFiles(aImg, bImg, cifilterName) of me

set outPath to retUUIDfilePath(POSIX path of (path to desktop), "png") of me
set sRes to saveNSImageAtPathAsPNG(imgRes, outPath) of me

–CIFilterをかけたJPEG画像を生成
on filterBlendImageFiles(aPath, bPath, aFilterName)
  –CIImage(A)を生成
  
set aURL to |NSURL|’s fileURLWithPath:aPath –Input
  
set aCIImage to CIImage’s alloc()’s initWithContentsOfURL:aURL
  
  
–CIImage(B)を生成
  
set bURL to |NSURL|’s fileURLWithPath:bPath –Input
  
set bCIImage to CIImage’s alloc()’s initWithContentsOfURL:bURL
  
  
— CIFilter をフィルタの名前で生成
  
set aFilter to CIFilter’s filterWithName:aFilterName
  
aFilter’s setDefaults() –各フィルタのパラメータはデフォルト
  
  
–Blend Filterを実行
  
aFilter’s setValue:(aCIImage) forKey:"inputImage"
  
aFilter’s setValue:(bCIImage) forKey:"inputBackgroundImage"
  
  
set aOutImage to aFilter’s valueForKey:"outputImage"
  
set outNSImage to convCIimageToNSImage(aOutImage) of me
  
return outNSImage
end filterBlendImageFiles

on retUUIDfilePath(aPath, aEXT)
  set aUUIDstr to (NSUUID’s UUID()’s UUIDString()) as string
  
set aPath to ((NSString’s stringWithString:aPath)’s stringByAppendingPathComponent:aUUIDstr)’s stringByAppendingPathExtension:aEXT
  
return aPath
end retUUIDfilePath

on convCIimageToNSImage(aCIImage)
  set aRep to NSBitmapImageRep’s alloc()’s initWithCIImage:aCIImage
  
set tmpSize to aRep’s |size|()
  
set newImg to NSImage’s alloc()’s initWithSize:tmpSize
  
newImg’s addRepresentation:aRep
  
return newImg
end convCIimageToNSImage

on convNSImageToCIimage(aNSImage)
  set tiffDat to aNSImage’s TIFFRepresentation()
  
set aRep to NSBitmapImageRep’s imageRepWithData:tiffDat
  
set newImg to CIImage’s alloc()’s initWithBitmapImageRep:aRep
  
return newImg
end convNSImageToCIimage

–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

★Click Here to Open This Script 

AppleScript名:(比較用)GPUImageによる差分計算.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/22
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "GPUImage" –https://github.com/BradLarson/GPUImage

property NSUUID : a reference to current application’s NSUUID
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 NSPNGFileType : a reference to current application’s NSPNGFileType
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep

set mePath to POSIX path of (path to me)
set aImagePath to mePath & "Contents/Resources/book1_v2.0_0011.jpg"
set bImagePath to mePath & "Contents/Resources/book1_v2.1_0011.jpg"

set imgRes to composeImageWithBlendFilter(aImagePath, bImagePath, "GPUImageDifferenceBlendFilter") of me

set outPath to retUUIDfilePath(POSIX path of (path to desktop), "png") of me
set sRes to saveNSImageAtPathAsPNG(imgRes, outPath) of me

on composeImageWithBlendFilter(aImagePath, bImagePath, filterName)
  set aImage to NSImage’s alloc()’s initWithContentsOfFile:aImagePath
  
set bImage to NSImage’s alloc()’s initWithContentsOfFile:bImagePath
  
  
set aClass to current application’s NSClassFromString(filterName)
  
set blendFilter to aClass’s alloc()’s init()
  
set pictureA to current application’s GPUImagePicture’s alloc()’s initWithImage:aImage
  
pictureA’s addTarget:blendFilter
  
pictureA’s processImage()
  
set imgRes to blendFilter’s imageByFilteringImage:bImage
  
return imgRes
end composeImageWithBlendFilter

on retUUIDfilePath(aPath, aEXT)
  set aUUIDstr to (NSUUID’s UUID()’s UUIDString()) as string
  
set aPath to ((NSString’s stringWithString:aPath)’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

★Click Here to Open This Script 

(Visited 290 times, 2 visits today)
Posted in file filter Image | Tagged 10.14savvy 10.15savvy CIFilter CIImage NSBitmapImageRep NSImage NSPNGFileType NSString NSURL NSUUID | Leave a comment

Appleがいまだに直さない致命的なPDFViewのバグに対処v2

Posted on 11月 22, 2019 by Takaaki Naganoya

macOS 10.13のBetaの時にはなかったのに、Release版がバグだらけでリリース。PDFViewについて多大なる被害を受けております。PDFViewをScripting Bridge経由で使うと、macOS 10.14も10.15も状況は同じです。きちんと動かないので、仕様と言い切ることは難しいところでしょう。未修正のバグが放置されているという状況です。

Developper Supportに報告しても返答も何もないので、PDFViewのScripting Bridgeまわりはバグだらけのまま直すつもりもないのでしょう。Xcode上でプログラムを組みだすと、腹の立つことのオンパレードです。

AppleのDevelopperライセンスの延長時期がやってくると、日頃からバグだらけでOSをリリースするわバグは直さないわで、嫌がらせを受け続けているのになんでこれを契約延長しなくてはならないのか理解に苦しみます。

Apple系のMailing Listでは主流ともいえるCocoa-Dev ML上でもAppleのあり方に疑問を呈したり文句を(ていねいなお言葉で)述べる投稿がここ数週間(macOS 10.15のリリース以降)激増している今日このごろです。

いまいちどPDFViewまわりを確認してみると、PDFViewのcurrentPageを取得できない未修正の特大バグに続いて、goToPreviousPage、goToNextPageも効きません。つまり、現在表示中のページの取得も、前後ページへの移動もできないという状況です。


▲まともにオブジェクトを返してこないcurrentPage

とりあえず、Xcode上でヘッダーファイル「PDFView.h」を確認していると、currentPageのかわりになりそうなものを見つけました。それが、visiblePages。PDFView上で表示中のページを(複数)返してくるわけで、単ページ表示時にはなんとかこれが使えるかも? ということで試してみました。

–> Download pdfviewAgainstAppleBug (Xcode Project)


▲currentPageのかわりに使えそうなvisiblePages。こっちは機能している

これが使えたので応用し、かなり遠回りな処理にはなりますが、表示中のページの前後移動もできるようにしてみました。

ただ、PDFViewをもとにしたクリックスルーなPDFViewを使ってみると、いまひとつ想定どおりに動作してくれません。まだいろいろ試してみる必要がありそうです。
→ クリックスルーPDFViewは結局動作するようになり、Double PDF v2に実装できました

これらのほか、PDFViewはページ変更時のイベントやドキュメント変更時のイベントが送信されないなど、苦労させられまくりです。

(Visited 48 times, 1 visits today)
Posted in Bug GUI PDF | Tagged 10.14savvy 10.15savvy PDFView | Leave a comment

ファイルからのメタデータ情報の取得

Posted on 11月 21, 2019 by Takaaki Naganoya

指定ファイルからのメタデータ情報の取得を行うAppleScriptです。

メタデータの取得はshell commandの「mdls」で行えます。ほぼそれと同じ内容です。ループですぺての属性値を取得するか、属性ラベルを指定して個別に属性値を取り出すことになります。

この方法でメタデータの書き込みや追記が行えないかと調べてみましたが、どうもできないようで「自前でMDImporterを作れ」とか言われてもテーマが大きすぎて困ります……

メタデータの書き込みはshell commandのほうが手っ取り早そうです。

AppleScript名:ファイルからのメタデータ情報の取得 v1scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/21
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSMetadataItem : a reference to current application’s NSMetadataItem

set aFile to POSIX path of (choose file)
set aURL to |NSURL|’s fileURLWithPath:aFile

set aMetaInfo to NSMetadataItem’s alloc()’s initWithURL:aURL
set attrList to (aMetaInfo’s attributes()) as list

set metaList to {}

repeat with i in attrList
  set j to contents of i
  
set aTmpVal to (aMetaInfo’s valueForAttribute:(j))
  
set the end of metaList to {j as string, aTmpVal as {number, string, date, list}}
end repeat

return metaList

★Click Here to Open This Script 

AppleScript名:ファイルからのメタデータ情報の取得 v2a.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/21
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSMetadataItem : a reference to current application’s NSMetadataItem

set aFile to POSIX path of (choose file)
set aURL to |NSURL|’s fileURLWithPath:aFile

set aMetaInfo to NSMetadataItem’s alloc()’s initWithURL:aURL –fixed

–指定した属性ラベルの値だけ一括で取り出す
set metaDict to (aMetaInfo’s valuesForAttributes:{"kMDItemContentTypeTree", "kMDItemContentType"}) as record
–>
(*
(NSDictionary) {
  kMDItemContentTypeTree:{
    "com.apple.application-bundle",
    "com.apple.localizable-name-bundle",
    "com.apple.application-bundle",
    "public.directory",
    "public.executable",
    "com.apple.application",
    "public.item",
    "com.apple.package",
    "com.apple.bundle"
  },
  kMDItemContentType:"com.apple.application-bundle"
}
*)

★Click Here to Open This Script 

(Visited 271 times, 1 visits today)
Posted in file Metadata | Tagged 10.14savvy 10.15savvy NSMetadataItem NSURL | Leave a comment

アラートダイアログ上のWebViewに世界地図を表示 v2b

Posted on 11月 20, 2019 by Takaaki Naganoya

世界地図のSVGをHTMLReader.frameworkでparseして、目的のノードに塗り色の指定を行い、WkWebView上で表示するAppleScriptです。

–> Download selectCountry2(Code-signed AppleScript executable applet)

昨日のものがあくまでSVGのParseと表示が目的の試作品であったのに対し、本Scriptは連続してポップアップメニューから対象を選んで表示するというものです。

同様にmacOS 10.15.1上で作成しましたが、このバージョンのOS環境ではAppleScriptアプレットにFrameworkを入れてAppleScript内から呼び出すことが標準のランタイム(Script Editorから書き出した場合)では行えないようになっており、Script Debuggerから「Application(Enhanced)」で書き出さないと呼び出せないようです(これはちょっとひどいかも、、、、)。

世界地図はWikipediaから拾ってきたもので、ISO国コードではなく名称でIDが振ってあり、日本もJapanではなくHokkaido、Honshu、Shikoku、Kyushuuに分けて登録されています。


▲Script Editor上でサードパーティFramework呼び出しの動作ができているのは、この実行環境でSIPを解除してあるからです

AppleScript名:アラートダイアログ上のWebViewに世界地図を表示 v2b.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/18
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
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 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 HTMLDocument : a reference to current application’s HTMLDocument
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 theResult : 0
property returnCode : 0
property aWebView : missing value
property aLog : missing value
property tmpURL : ""

tell current application
  set mePath to ((path to me) as string) & "Contents:Resources:World_map_-_low_resolution.svg"
  
set svgCon to read (mePath as alias)
  
  
set aWidth to 950
  
set aHeight to 650
  
  
  
set paramObj to {myMessage:"Browse World map", mySubMessage:"This is a sample SVG World map", targContents:svgCon, myWidth:(aWidth), myHeight:(aHeight)}
  
–my browseLocalWebContents:paramObj
  
my performSelectorOnMainThread:"browseLocalWebContents:" withObject:(paramObj) waitUntilDone:true
  
return aLog
end tell

on browseLocalWebContents:paramObj
  set aMainMes to (myMessage of paramObj) as string
  
set aSubMes to (mySubMessage of paramObj) as string
  
set tmpURL to (targContents of paramObj) as string –local contents
  
set aWidth to (myWidth of paramObj) as integer
  
set aHeight to (myHeight of paramObj) as integer
  
  
  
set aView to current application’s NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
  
–Ppopup Buttonをつくる
  
set a1Button to current application’s NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aHeight – 26, 200, 24)) pullsDown:(false)
  
a1Button’s removeAllItems()
  
  
–Menuの中身を作る  
  
set aHTML to current application’s HTMLDocument’s documentWithString:(tmpURL)
  
set fList to (aHTML’s nodesMatchingSelector:"path")’s valueForKeyPath:"attributes.id"
  
set fList to fList’s sortedArrayUsingSelector:"compare:"
  
  
a1Button’s addItemWithTitle:"▼Select"
  
  
repeat with i in fList
    (a1Button’s addItemWithTitle:(i as string))
  end repeat
  
  
a1Button’s setTarget:(me)
  
a1Button’s setAction:("mySelector:")
  
a1Button’s setEnabled:(true)
  
  
set aWebView to makeWebViewAndLoadContents(tmpURL, aWidth, aHeight – 40) of me
  
  
aView’s addSubview:a1Button
  
aView’s addSubview:aWebView
  
  
— 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:aView
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseLocalWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

–Popup Action Handler
on actionHandler:sender
  set aTitle to title of sender as string
end actionHandler:

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 mySelector:aSender
  set targetCountry to (aSender’s title()) as string
  
  
set aHTML to current application’s HTMLDocument’s documentWithString:(tmpURL as string)
  
  
set eList to (aHTML’s nodesMatchingSelector:"path") as list
  
set fList to (aHTML’s nodesMatchingSelector:"path")’s valueForKeyPath:"attributes.id"
  
  
–Search Target Country
  
set aRes to (fList)’s indexOfObject:(targetCountry)
  
if (aRes = current application’s NSNotFound) or (aRes > 9.99999999E+8) then
    error "Target country not found"
  end if
  
  
set aRes to aRes + 1
  
  
–Rewrite target country’s fill color on SVG
  
set tmpNode to contents of item aRes of (eList)
  (
tmpNode’s setObject:"Red" forKeyedSubscript:"fill") –Change Target Country’s fill color
  
  
set svgCon to (tmpNode’s |document|()’s serializedFragment()) as string –HTMLReaderはこういう処理ができるところが好き
  
  
aWebView’s loadHTMLString:svgCon baseURL:(missing value)
end mySelector:

on makeWebViewAndLoadContents(aContents as string, aWidth as integer, aHeight as integer)
  set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定URLのJavaScriptをFetch
  
set jsSource to my fetchJSSourceString(aContents)
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
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
  
aWebView’s setOpaque:false
  
aWebView’s setBackgroundColor:(NSColor’s clearColor())
  
–aWebView’s scrollView()’s setBackgroundColor:(NSColor’s clearColor())
  
  
aWebView’s loadHTMLString:aContents baseURL:(missing value)
  
return aWebView
end makeWebViewAndLoadContents

★Click Here to Open This Script 

(Visited 72 times, 1 visits today)
Posted in dialog geolocation GUI Image SVG | Tagged 10.13savvy 10.14savvy 10.15savvy HTMLDocument NSAlert NSButton NSColor NSImage NSRunningApplication NSScreen NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

SVGの要素を走査するじっけん v2

Posted on 11月 19, 2019 by Takaaki Naganoya

世界地図のSVGをHTMLReader.frameworkでparseして、目的のノードに塗り色の指定を行い、WkWebView上で表示するAppleScriptです。

–> Download countrySel(Code-Signed AppleScript applet executable. Its icon is customized version by Script Debbuger)


▲いかにもなメルカトル図法の世界地図。極地に行くほど巨大に表現される。国によっては国土が小さいために色を変えてもこの縮尺だとわからないことも

SVGをparseするのにXML Parser系のFrameworkを軒並み試してみたのですが、所定の要素を掘り進んでいくまでは楽にできるものの、検索先のnodeまで行って属性値を書き換えたあとでrootまで戻り、属性値を書き換えたXML全体を文字列化するような機能を備えたものは見つかりませんでした。

この手の処理で圧倒的に便利なのがHTMLReader.framework。書き換え要素を検索して、書き換えたあとにrootまで戻り、Document全体を文字列化して返すような処理が楽勝です。この手の処理が楽にできるプログラムは、自分が知っているかぎりではこれだけです。

本ScriptはmacOS 10.15.1上で作って試してみましたが、驚いたことに、アプリケーション書き出ししたときに、Apple純正のランタイムだとAppleScriptアプレット内にバンドルしたフレームワークにアクセスできなくなっていました。

セキュリティを強化したいのは理解できますが、いささかやりすぎではないでしょうか。この先、Script Debuggerを用いて書き出したランタイムまで実行できなくなったとしたらXcode上で作らないと実行できなくなってしまうことでしょう。いささかやりすぎのようにも思えます。

Script Debuggerから「Application(Apple)」で書き出すと、Frameworkにアクセスできないんだか、WkWebViewにアクセスできないんだか不明ですが、macOS 10.15上では地図が表示できません。


▲Script Debugger上でアプレット書き出しするさいに、Applicaion(Enhanced)で書き出さないとバンドル内のフレームワーク呼び出しができなかった。Script Debuggerがないと手も足も出ない


▲ISO国コードから選択。「JP」を選ぶと日本が、「AU」を選ぶとオーストラリアが赤く表示される


▲SVGの世界地図をテキストエディタでオープンしたところ

AppleScript名:SVGの要素を走査するじっけん v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/19
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader
use webDialog : script "webViewLib"

property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument

property textArray : missing value
property anError : missing value

–Choose Target Country
set isoCountry to (current application’s NSLocale’s ISOCountryCodes()) as list
set cRes to choose from list isoCountry with prompt "Select Target Country"

set targetCountry to contents of first item of cRes

–Load SVG World map in this bundle
set mePath to ((path to me) as string) & "Contents:Resources:world-2.svg"
set aData to read (mePath as alias)
set aHTML to current application’s HTMLDocument’s documentWithString:(aData as string)

set eList to (aHTML’s nodesMatchingSelector:"path") as list
set fList to (aHTML’s nodesMatchingSelector:"path")’s valueForKeyPath:"attributes.id"

–Search Target Country
set aRes to (fList)’s indexOfObject:(targetCountry)
if (aRes = current application’s NSNotFound) or (aRes > 9.99999999E+8) then
  error "Target country not found"
end if
set aRes to aRes + 1 — (Cocoa array index begins from 0, AppleScript is 1)

–Rewrite target country’s fill color on SVG
set tmpNode to contents of item aRes of (eList)
(
tmpNode’s setObject:"Red" forKeyedSubscript:"fill") –Change Target Country’s fill color

set svgCon to (tmpNode’s |document|()’s serializedFragment()) as string –HTMLReaderはこういう処理ができるところが好き

–Alert Dialog上でSVGを表示
dispWebViewByString(svgCon, "This is " & targetCountry, "This is your indicated country by 2 character country code") of webDialog

★Click Here to Open This Script 

(Visited 83 times, 1 visits today)
Posted in dialog Image SVG Text XML | Tagged 10.13savvy 10.14savvy 10.15savvy HTMLDocument NSString | 1 Comment

アラートダイアログ上のWebViewに円グラフを表示

Posted on 11月 18, 2019 by Takaaki Naganoya

アラートダイアログ上のWebViewにSVGで作った円グラフを表示するAppleScriptです。

Objective-Cで作られたチャート表示フレームワークなどを呼び出して試していますが、スクリプトエディタ上で作成したAppleScriptから呼び出すと、アニメーションしなかったり表示が行えなかったりといろいろ環境にフィットしていません。

# 逆をいえば、Xcode上でCocoa AppleScriptアプリケーションを作成した場合には割とチャート表示部品をそのまま使えます

そこで、単純なグラフ表示を行うようにレベルを下げ、SVGをWkWebView上に表示する形式にしてみました。

本Scriptでは最低限のサンプルを表示させていますが、SVGの組み立てをもう少し強化してグラフの背景を透明にできればいい感じになるのではないでしょうか。


▲世界地図あたりだといい感じに見えるかもしれません。当該の国だけ色を変えるような処理を仕込めば何かに使えそうです。

AppleScript名:アラートダイアログ上のWebViewに円グラフを表示.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/18
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
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 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 theResult : 0
property returnCode : 0

–set svgCon to read (choose file)
set svgCon to retSampleSVG() of me

set paramObj to {myMessage:"Browse Pie Chart", mySubMessage:"This is a sample pie chart made by SVG", targContents:svgCon}
–my browseLocalWebContents:paramObj
my performSelectorOnMainThread:"browseLocalWebContents:" withObject:(paramObj) waitUntilDone:true

on browseLocalWebContents:paramObj
  set aMainMes to (myMessage of paramObj) as string
  
set aSubMes to (mySubMessage of paramObj) as string
  
set tmpURL to (targContents of paramObj) as string –local contents
  
  
set aWidth to 330
  
set aHeight to 430
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定URLのJavaScriptをFetch
  
set jsSource to my fetchJSSourceString(tmpURL)
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight – 100)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
aWebView’s setOpaque:false
  
aWebView’s setBackgroundColor:(NSColor’s clearColor())
  
–aWebView’s scrollView()’s setBackgroundColor:(NSColor’s clearColor())
  
  
aWebView’s loadHTMLString:tmpURL baseURL:(missing value)
  
  
  
— 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
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseLocalWebContents:

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 retSampleSVG()
  return "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"300\" height=\"300\" fill-opacity=\"0.9\">
<path d=\"M 150,0 A 150,150 0 1,1 141.8986347236027,299.7810664959306 L 150,150 Z\" fill=\"#0153d8\" stroke=\"#fff\"></path>
<text x=\"170\" y=\"150\" fill=\"#fff\" font-size=\"20\">Piyomaru</text>
<text x=\"170\" y=\"190\" fill=\"#fff\" font-size=\"40\">50.86%</text>
</svg>"
end retSampleSVG

★Click Here to Open This Script 

(Visited 101 times, 1 visits today)
Posted in dialog GUI | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSColor NSImage NSRunningApplication NSScreen NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | 1 Comment

checkboxLib v2

Posted on 11月 17, 2019 by Takaaki Naganoya

アラートダイアログで指定の1D List(1次元配列)に入れた項目からのユーザー選択を求めるAppleScript Librariesです。

–> Download checkboxLibv2.scptd(To ~/Library/Script Libraries/)

–> Watch Demo Movie

本ライブラリはAppleScript用語辞書に画像とムービーを含んでおり、ジャスト、この記事に掲載のものを参照しています(この記事とかリンク画像やムービーを削除すると、AppleScript用語辞書にも表示されなくなる仕様)。インターネット接続環境下にない場合には、AppleScript用語辞書内の画像やムービーは表示されません。

そのかわりに、辞書サイズが小さくなっているので、良し悪しかと。

前バージョンからの変更点は、アラートダイアログ表示時にあらかじめ項目選択しておく指定(selection items)を追加した点です。


▲サンプルScriptと、実行時の画面キャプチャとひととおおり実行したときのムービーがAppleScript用語辞書に掲載されています


▲サンプルScriptは、本Blogと同様の仕様で、サンプル下部のリンク「★Click Here to Open This Script」をクリックすればスクリプトエディタ/Script Debuggerに内容が転送されます

AppleScript名:sample 1
— Created 2019-08-07 by Takaaki Naganoya
— 2019 Piyomaru Software
use chkLib : script "checkboxLib"

set tList to {"Carrot", "Burdock", "Radish", "Potato", "Cabege", "Lettuce", "Komatsuna", "Garlic", "Tomato", "bok choy", "Shiitake Mushroom", "Onion"}
set cRes to choose checkbox main message "Main Title" with columns 2 with titles tList checkbox type standard return type item number selection items {true, true, true, true, true, true, true, true, false, false, false, false}
–> {1, 2, 3, 4, 5, 6, 7, 8}–Selected Index numbers (starts from 1)

★Click Here to Open This Script 

(Visited 326 times, 1 visits today)
Posted in dialog GUI Script Libraries sdef | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

再帰でKeynote書類上のフォントを置換する(グループ対応)

Posted on 11月 16, 2019 by Takaaki Naganoya

macOS 10.15でバンドルされなくなった「ヒラギノ角ゴProN W3」「ヒラギノ角ゴProN W6」がKeynote書類中に指定されていたら、それぞれ「ヒラギノ角ゴシック W3」「ヒラギノ角ゴシック W6」に置換するAppleScriptです。

現在オープン中の最前面のKeynote書類を走査して、全スライド中のオブジェクトの内容を取得し、text item、shape、table中に指定されているフォントを置換するようになっています。また、group化されたこれらのオブジェクトを再帰で取得するようになっています。

ただし、グラフ(chart)中の文字のフォントについてはAppleScriptからアクセスできないため、フォントの置換は行えません。このあたりでミソがついて、完全自動でヒラギノ角ゴProNを置換できるわけではないので、少々残念(KeynoteのAppleScript用語辞書の仕様の問題)な結果に。

また、別にこれらのフォントを置換しなくても実害はないので、置換しても単に気分の問題だけでしょう。

AppleScript名:再帰でKeynote書類上のフォントを置換する(グループ対応)
— Created 2019-11-14 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property allText : {}
property allShape : {}
property allTable : {}

set searchFont to {"HiraKakuProN-W6", "HiraKakuProN-W3"}

tell application "Keynote"
  tell front document
    set sCount to count every slide
    
    
repeat with ii from 1 to sCount
      set current slide to slide ii
      
      
tell current slide
        getEveryTextAndShapes() of me
        
        
–Text Item、Shapeのフォント置換ループ
        
set tList to allText & allShape
        
        
repeat with i in tList
          set aClass to class of i
          
–if aClass is not equal to default title item then
          
set aFont to font of object text of i
          
set aText to (object text of i)
          
if aFont is in searchFont and aText is not equal to "" then
            if aFont ends with "-W6" then
              set font of object text of i to "HiraginoSans-W6"
            else if aFont ends with "-W3" then
              set font of object text of i to "HiraginoSans-W3"
            end if
          end if
          
–end if
        end repeat
        
        
        
–Table内の全セルのフォント置換ループ
        
repeat with iii in allTable
          tell iii
            set cList to every cell
            
            
repeat with i in cList –Loop by cells
              set aFont to font name of i
              
set aText to (value of i)
              
              
if aFont is in searchFont then
                if aFont ends with "-W6" then
                  set font name of i to "HiraginoSans-W6"
                else if aFont ends with "-W3" then
                  set font name of i to "HiraginoSans-W3"
                end if
              end if
              
            end repeat
          end tell
        end repeat
        
        
      end tell
    end repeat
  end tell
end tell

on getEveryTextAndShapes()
  set allText to {}
  
set allShape to {}
  
set allTable to {}
  
  
tell application "Keynote"
    tell front document
      tell current slide
        set gList to every group
        
        
set i1List to every text item
        
set i2List to every shape
        
set i3List to every table
        
        
if i1List is not equal to {} then set allText to allText & i1List
        
if i2List is not equal to {} then set allShape to allShape & i2List
        
if i3List is not equal to {} then set allTable to allTable & i3List
        
        
prepareGroup(gList) of me
        
      end tell
    end tell
  end tell
end getEveryTextAndShapes

–Dig into groups by recursive call
on prepareGroup(gList)
  tell application "Keynote"
    tell front document
      tell current slide
        repeat with i in gList
          tell i
            set g2List to every group
            
            
set i1List to every text item
            
set i2List to every shape
            
set i3List to every table
            
            
if i1List is not equal to {} then set allText to allText & i1List
            
if i2List is not equal to {} then set allShape to allShape & i2List
            
if i3List is not equal to {} then set allTable to allTable & i3List
            
            
prepareGroup(g2List) of me
          end tell
        end repeat
      end tell
    end tell
  end tell
end prepareGroup

★Click Here to Open This Script 

(Visited 108 times, 1 visits today)
Posted in Font recursive call | Tagged 10.15savvy Keynote | Leave a comment

指定アプリケーション内の現在のLocaleの指定stringsファイル内の指定キーの値を取得する

Posted on 11月 16, 2019 by Takaaki Naganoya

Bundle IDで指定したアプリケーションのバンドル中(/Contents/Resources/)の現在のLocalizationに存在する指定のstringsファイル内で、指定キーの値を取得するAppleScriptです。

アプリケーションバンドル内の各ローカライズフォルダの名称は一意に決定されているものでもなく、ある程度の「ゆらぎ」が生じています。

/Contents/Resources/Japanese.lproj/
/Contents/Resources/ja.lproj/

NSLocaleからcurrentLocale()を取得すると、「ja-JP」のような識別子が得られます。これと上記のパターンのフォルダとの付け合わせのためのメソッドがどこかに存在しているはずなのですが、現状では見つけられていません(ないと各アプリケーションが正しくメニュー表示できていないので)。

まだいまひとつ、しっくりきていません。

AppleScript名:指定アプリケーション内の現在のLocaleの指定stringsファイル内の指定キーの値を取得する.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/15
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSBundle : a reference to current application’s NSBundle
property NSDictionary : a reference to current application’s NSDictionary
property NSWorkspace : a reference to current application’s NSWorkspace
property NSFileManager : a reference to current application’s NSFileManager
property NSLocaleCountryCode : a reference to current application’s NSLocaleCountryCode
property NSLocaleLanguageCode : a reference to current application’s NSLocaleLanguageCode
property NSLocaleCollatorIdentifier : a reference to current application’s NSLocaleCollatorIdentifier

set targID to "com.apple.iWork.Keynote"
set targFile to "Keynote" –"Keynote.strings" file
set targKey to "Arrange"
set vStr to getAValInASpecifiedStringFileOfAllLocaleInABundle(targID, targFile, targKey) of me
–> "配置"

on getAValInASpecifiedStringFileOfAllLocaleInABundle(targID, targFile, targKey)
  set aPath to retPathFromBundleID(targID) of me
  
  
set aURL to (|NSURL|’s fileURLWithPath:aPath)
  
set aBundle to NSBundle’s bundleWithURL:aURL
  
  
set aLocale to (current application’s NSLocale’s preferredLanguages()’s firstObject()) as string
  
  
set curLocale to current application’s NSLocale’s currentLocale()
  
set aDS11 to (curLocale’s objectForKey:(NSLocaleLanguageCode)) as string
  
set aDS12 to (curLocale’s objectForKey:(NSLocaleCountryCode)) as string
  
set aDS5 to (curLocale’s objectForKey:(NSLocaleCollatorIdentifier)) as string
  
–set bID to (current application’s NSBundle’s mainBundle()’s preferredLocalizations()’s firstObject()) as string
  
  
set langIDList to {aDS11, aLocale, aDS12, aDS5} –> {"ja", "ja-JP", "JP", "ja-JP"}
  
  
repeat with i in langIDList
    set j to contents of i
    
set aRes to (aBundle’s pathForResource:targFile ofType:"strings" inDirectory:"" forLocalization:(j))
    
set aDict to (NSDictionary’s alloc()’s initWithContentsOfFile:aRes)
    
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
        return aVal as string
      end if
    end if
  end repeat
  
  
return false
end getAValInASpecifiedStringFileOfAllLocaleInABundle

on getLocalizationsFromBundleID(aBundleID)
  set aRes to retPathFromBundleID(aBundleID) of me
  
if aRes = false then error "Wrong Bundle ID."
  
return getSpecifiedAppFilesLocalizationListWithDuplication(aRes) of me
end getLocalizationsFromBundleID

–指定アプリケーションファイルの、指定Localeにおけるローカライズ言語リストを求める。重複を許容
on getSpecifiedAppFilesLocalizationListWithDuplication(appPOSIXpath)
  set aURL to (|NSURL|’s fileURLWithPath:appPOSIXpath)
  
set aBundle to NSBundle’s bundleWithURL:aURL
  
set locList to aBundle’s localizations()
  
return locList as list
end getSpecifiedAppFilesLocalizationListWithDuplication

on retPathFromBundleID(aBundleID)
  set aURL to NSWorkspace’s sharedWorkspace()’s URLForApplicationWithBundleIdentifier:aBundleID
  
if aURL = missing value then return false –Error
  
return aURL’s |path|() as string
end retPathFromBundleID

★Click Here to Open This Script 

(Visited 57 times, 1 visits today)
Posted in list System Text URL | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy NSBundle NSDictionary NSFileManager NSLocaleCollatorIdentifier NSLocaleCountryCode NSLocaleLanguageCode NSURL NSWorkspace | 2 Comments

アラートダイアログ上にNSBoxを介してPopup Menuを表示

Posted on 11月 14, 2019 by Takaaki Naganoya

アラートダイアログ上に複数のポップアップメニュー(項目数可変)を表示し、指定リスト(配列)からの選択を行うAppleScriptです。

以前、Segmented Controlで作ったものがありましたが、Segmented Controlだと絶望的に実用性がないので、ポップアップボタンに差し替えてみたものです。

AppleScript名:アラートダイアログ上にNSBoxを介してPopup Menuを表示
— Created 2019-11-14 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSBox : a reference to current application’s NSBox
property NSView : a reference to current application’s NSView
property NSAlert : a reference to current application’s NSAlert
property NSScrollView : a reference to current application’s NSScrollView
property NSRunningApplication : a reference to current application’s NSRunningApplication

property returnCode : 0
property returnSels : {}

set paramObj to {myMessage:"項目選択", mySubMessage:"以下の各項目を選択してください。", segmentMes:{{"Red1", "Blue1", "Yellow1", "Brown1", "White1", "Cyan1", "Grey1"}, {"Red2", "Blue2", "Yellow2", "Brown2", "White2", "Cyan2", "Grey2"}, {"Red3", "Blue3", "Yellow3", "Brown3", "White3", "Cyan3", "Grey3"}, {"Red4", "Blue4", "Yellow4", "Brown4", "White4", "Cyan4", "Grey4"}, {"Red5", "Blue5", "Yellow5", "Brown5", "White5", "Cyan5", "Grey5"}}, segmentTitles:{"1st Segments", "2nd Segments", "3rd Segments", "4th Segments", "5th Segments"}}

–my chooseMultipleSegments:paramObj
my performSelectorOnMainThread:"chooseMultipleSegments:" withObject:paramObj waitUntilDone:true

return my returnSels
–> {1, 2, 3, 4, 5}

on chooseMultipleSegments:paramObj
  set aMainMes to (myMessage of paramObj) as string
  
set aSubMes to (mySubMessage of paramObj) as string
  
set segMes2DList to (segmentMes of paramObj) as list
  
set segTitleList to (segmentTitles of paramObj) as list
  
  
set aTmpY to (length of segMes2DList) * 60
  
  
–BoX + Segmented Control をつくる
  
set segsList to {}
  
set boxLIst to {}
  
set segsCount to 0
  
set tmpMaxX to 400
  
  
set aCount to 1
  
  
repeat with i in segMes2DList
    set a1Button to (current application’s NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, tmpMaxX – 30, 30)) pullsDown:false)
    
a1Button’s removeAllItems()
    (
a1Button’s addItemsWithTitles:(i))
    
    
set aDBounds to a1Button’s |bounds|()
    
set tmpWidth to getWidth(aDBounds) of me
    
    
set aBox to (NSBox’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aTmpY – segsCount – 60, tmpMaxX – 10, 60)))
    (
aBox’s setTitle:(item aCount of segTitleList))
    (
aBox’s addSubview:a1Button)
    (
aBox’s setBorderType:0) –NSNoBorder, this method is depreceted in macOS 10.14. Which is alternative?
    
    
if tmpWidth > tmpMaxX then set tmpMaxX to tmpWidth
    
    
set the end of segsList to a1Button –選択検出用
    
set the end of boxLIst to aBox –表示用
    
    
set segsCount to segsCount + 60
    
set aCount to aCount + 1
  end repeat
  
  
— create a view
  
set theView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, tmpMaxX + 10, aTmpY + 20))
  
theView’s setSubviews:boxLIst
  
  
— create a Scroll View
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, tmpMaxX + 10, 300))
  
aScroll’s setDocumentView:theView
  
aScroll’s documentView()’s scrollPoint:(current application’s NSMakePoint(0, aTmpY + 10)) –Force scroll to top
  
  
theView’s enclosingScrollView()’s setHasHorizontalScroller:false
  
theView’s enclosingScrollView()’s setHasVerticalScroller: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:aScroll
  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
  
  
set my returnSels to {}
  
repeat with i in segsList
    set tmpSegSel to (i’s indexOfSelectedItem()) as number
    
set the end of (my returnSels) to tmpSegSel + 1
  end repeat
end chooseMultipleSegments:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on clickedSeg:aSender
  set aSel to aSender’s selectedSegment()
end clickedSeg:

on getWidth(aDBounds)
  if class of aDBounds = list then
    –macOS 10.13 or later
    
return item 1 of item 1 of aDBounds
  else
    –macOS 10.10….10.12
    
return width of |size| of aDBounds
  end if
end getWidth

★Click Here to Open This Script 

(Visited 157 times, 1 visits today)
Posted in dialog GUI | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy NSAlert NSBox NSRunningApplication NSScrollView NSView | Leave a comment

アラートダイアログ上にカレンダー1か月分を表示して選択 有効日指定あり v3a

Posted on 11月 13, 2019 by Takaaki Naganoya

アラートダイアログ上に指定月のカレンダー1か月分を表示してユーザーの日付選択(複数可)をもとめるAppleScriptです。

NSDatePickerを用いて日付選択のダイアログを作っていたら、日付がとても小さくて現代のMacの画面解像度にとても合っておらず、もっと大きめのカレンダーで選択したいと考えて作ったものです。

(1)カレンダーの表示サイズを大型化

現代のMacの画面にNSDatePickerをそのまま表示すると、とても小さくて見ていられないので、表示サイズを自由に変えられるカレンダー選択部品を作ってみました。どれか1つの日付を選択するものではなく、複数の日付を選択して、リストで結果を返してきます。

▲画面上で見やすいようにカレンダー部品を大型化

(2)選択無効日指定

あらかじめ、日付選択の対象外とする日付を指定できるようにしました。

(3)過去日付の選択無効

過去の日付を表示・選択できないようにする指定です。

▲過去日付を無効に指定すると、現在日時よりも過去の日付は選択できない

(4)曜日を現在のLocale情報から変更

曜日に用いる文字列を現在のLocale情報から取得するようにしてみました。本来であれば、日曜日はじまり「ではない」カレンダーを用いている場所もあるので(香港とかフランスとか?)、どの曜日から表示開始するかを自由選択にしたいところですが、そこまでは作り込んでいません。

▲Localeに合わせた曜日が表示される(ただし、年/月は固定フォーマット)

実用性を考えれば、Calendar.appのように日付選択とスケジュール確認が行えるものが望ましいのですが、そこまで作り込む手間をかけるほどのものでもないですし、表示対象月の移動を行おうとしてclickイベントを拾いつつカレンダー再描画に失敗した「残骸」です。見た目はいいのに完成度がいまひとつというあたりが残念です。

AppleScript名:アラートダイアログ上にカレンダー1か月分を表示して選択 有効日指定あり v3a
— Created 2019-10-15 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSFont : a reference to current application’s NSFont
property NSView : a reference to current application’s NSView
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSButton : a reference to current application’s NSButton
property NSOnState : a reference to current application’s NSOnState
property NSOffState : a reference to current application’s NSOffState
property NSTextField : a reference to current application’s NSTextField
property NSMutableArray : a reference to current application’s NSMutableArray
property NSButtonTypeOnOff : a reference to current application’s NSButtonTypeOnOff
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSKernAttributeName : a reference to current application’s NSKernAttributeName
property NSMutableParagraphStyle : a reference to current application’s NSMutableParagraphStyle
property NSLigatureAttributeName : a reference to current application’s NSLigatureAttributeName
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSUnderlineStyleAttributeName : a reference to current application’s NSUnderlineStyleAttributeName
property NSParagraphStyleAttributeName : a reference to current application’s NSParagraphStyleAttributeName
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName

property theResult : 0
property returnCode : 0
property bArray : {} –Checkbox button object array

property tYear : 0
property tMonth : 0
property theAlert : missing value
property theView : missing value

on run
  set tYear to 2019
  
set tMonth to 11
  
set ignoreP to true
  
set ndList to {2, 3, 4, 9, 10, 13, 16, 17, 23, 24, 25, 30} –選択表示させない日付
  
set paramObj to {myMessage:"", mySubMessage:"適切な日付を以下からえらんでください", targetYear:tYear, targetMonth:tMonth, nodisp:ndList, ignorePast:ignoreP}
  
  
–Detect Past Date Error
  
set curDate to current date
  
set dLimit to getMlen(tYear, tMonth) of me
  
set tmpDate to getDateInternational(tYear, tMonth, dLimit) of me
  
if (tmpDate < curDate) and (ignoreP = true) then error (("Target month is past (" & tYear as string) & "/" & tMonth as string) & "/1 is past. Today is " & date string of curDate & ")"
  
  
–my chooseItemByCheckBox:paramObj –for Debugging
  
my performSelectorOnMainThread:"chooseItemByCheckBox:" withObject:(paramObj) waitUntilDone:true
  
return my sort1DNumList:(my theResult) ascOrder:true
  
–> {1, 3, 5, 7, 9, 11}
end run

on chooseItemByCheckBox:(paramObj)
  set aMainMes to (myMessage of paramObj) as string
  
set aSubMes to (mySubMessage of paramObj) as string
  
set aMatList to (matrixTitleList of paramObj) as list
  
set tYear to (targetYear of paramObj) as integer
  
set tMonth to (targetMonth of paramObj) as integer
  
set noDispList to (nodisp of paramObj) as list
  
set ignoreP to (ignorePast of paramObj) as boolean
  
  
if aMainMes = "" then
    set aMainMes to "日付を選択してください"
  end if
  
  
set theView to makeCalendarView(tYear, tMonth, noDispList, ignoreP) of me
  
  
–Select the first radio button item
  
set my theResult to {}
  
  
— 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:theView
    
    
–for Help Button
    
–its setShowsHelp:(true)
    
its setDelegate:(me)
    
set aWin to its |window|()
  end tell
  
  
aWin’s setLevel:(current application’s NSFloatingWindowLevel)
  
  
— 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
  
end chooseItemByCheckBox:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on clicked:aParam
  set aTag to (tag of aParam) as integer
  
  
–clicked
  
if aTag is not in (my theResult) then
    set the end of (my theResult) to aTag
  else
    set theResult to my deleteItem:aTag fromList:theResult
  end if
end clicked:

on deleteItem:anItem fromList:theList
  set theArray to NSMutableArray’s arrayWithArray:theList
  
theArray’s removeObject:anItem
  
return theArray as list
end deleteItem:fromList:

–1D List(数値)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DNumList:theList ascOrder:aBool
  tell current application’s NSSet to set theSet to setWithArray_(theList)
  
tell current application’s NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_(missing value, true)
  
set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor}
  
return (sortedList) as list
end sort1DNumList:ascOrder:

–Help Button Clicked Event Handler
on alertShowHelp:aNotification
  set aRes to display dialog "Do you change all checkbox state?" buttons {"All Off", "All On", "Cancel"} default button 3 with icon 1
  
set bRes to (button returned of aRes) as string
  
  
if bRes = "All Off" then
    set bLen to bArray’s |count|()
    
set theResult to {}
    
repeat with i from 0 to bLen
      ((bArray’s objectAtIndex:i)’s setState:(current application’s NSOffState))
    end repeat
    
  else if bRes = "All On" then
    set bLen to bArray’s |count|()
    
set theResult to {}
    
repeat with i from 0 to bLen
      ((bArray’s objectAtIndex:i)’s setState:(current application’s NSOnState))
      
set the end of theResult to i + 1
    end repeat
  end if
  
  
return false –trueを返すと親ウィンドウ(アラートダイアログ)がクローズする
end alertShowHelp:

–書式つきテキストを組み立てる
on makeRTFfromParameters(aStr as string, fontName as string, aFontSize as real, aKerning as real, aLineSpacing as real)
  set aVal1 to NSFont’s fontWithName:fontName |size|:aFontSize
  
set aKey1 to (NSFontAttributeName)
  
  
set aVal2 to NSColor’s blackColor()
  
set aKey2 to (NSForegroundColorAttributeName)
  
  
set aVal3 to aKerning
  
set akey3 to (NSKernAttributeName)
  
  
set aVal4 to 0
  
set akey4 to (NSUnderlineStyleAttributeName)
  
  
set aVal5 to 2 –all ligature ON
  
set akey5 to (NSLigatureAttributeName)
  
  
set aParagraphStyle to NSMutableParagraphStyle’s alloc()’s init()
  
aParagraphStyle’s setMinimumLineHeight:(aLineSpacing)
  
aParagraphStyle’s setMaximumLineHeight:(aLineSpacing)
  
set akey7 to (NSParagraphStyleAttributeName)
  
  
set keyList to {aKey1, aKey2, akey3, akey4, akey5, akey7}
  
set valList to {aVal1, aVal2, aVal3, aVal4, aVal5, aParagraphStyle}
  
set attrsDictionary to NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
  
  
set attrStr to NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary
  
return attrStr
end makeRTFfromParameters

on makeNSTextField(xPos as integer, yPos as integer, myWidth as integer, myHeight as integer, editableF as boolean, setVal as string, backgroundF as boolean, borderedF as boolean)
  set aNSString to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(xPos, yPos, myWidth, myHeight))
  
aNSString’s setEditable:(editableF)
  
aNSString’s setStringValue:(setVal)
  
aNSString’s setDrawsBackground:(backgroundF)
  
aNSString’s setBordered:(borderedF)
  
return aNSString
end makeNSTextField

–指定月のカレンダーを1D List(7 days x 6 weeks) で返す
on retListCalendar(tYear, tMonth)
  set mLen to getMlen(tYear, tMonth) of me
  
set aList to {}
  
  
set fDat to getDateInternational(tYear, tMonth, 1) of me
  
tell current application
    set aOffset to (weekday of fDat) as number
  end tell
  
  
–header gap
  
repeat (aOffset – 1) times
    set the end of aList to ""
  end repeat
  
  
–calendar body
  
repeat with i from 1 to mLen
    set the end of aList to (i as string)
  end repeat
  
  
–footer gap
  
repeat (42 – aOffset – mLen + 1) times
    set the end of aList to ""
  end repeat
  
  
return aList
end retListCalendar

–現在のカレンダーで指定年月の日数を返す(国際化対応版)
on getMlen(aYear as integer, aMonth as integer)
  set theNSCalendar to current application’s NSCalendar’s currentCalendar()
  
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:1 hour:0 minute:0 |second|:0 nanosecond:0
  
set theResult to theNSCalendar’s rangeOfUnit:(current application’s NSDayCalendarUnit) inUnit:(current application’s NSMonthCalendarUnit) forDate:theDate
  
return |length| of theResult
end getMlen

–現在のカレンダーで指定年月のdate objectを返す
on getDateInternational(aYear, aMonth, aDay)
  set theNSCalendar to current application’s NSCalendar’s currentCalendar()
  
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:aDay hour:0 minute:0 |second|:0 nanosecond:0
  
return theDate as date
end getDateInternational

–ローカライズされた曜日名称を返す
on getLocalizedDaynames(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s standaloneWeekdaySymbols() as list
  
return dayNames
end getLocalizedDaynames

–ローカライズされた月名称を返す
on getLocalizedMonthnames(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set monthNames to df’s standaloneMonthSymbols() as list
  
return monthNames
end getLocalizedMonthnames

–ローカライズされた曜日の名称を返す
on getLocalizedWeekdaySymbol(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s weekdaySymbols()
  
return dayNames as list
end getLocalizedWeekdaySymbol

–ローカライズされた曜日の名称(短縮版)を返す
on getLocalizedShortWeekdaySymbol(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s shortWeekdaySymbols()
  
return dayNames as list
end getLocalizedShortWeekdaySymbol

–ローカライズされた曜日の名称(短縮記号)を返す
on getLocalizedVeryShortWeekdaySymbol(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s veryShortWeekdaySymbols()
  
return dayNames as list
end getLocalizedVeryShortWeekdaySymbol

–ローカライズされた曜日の名称を返す
on getLocalizedVeryStandaloneWeekdaySymbols(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s standaloneWeekdaySymbols()
  
return dayNames as list
end getLocalizedVeryStandaloneWeekdaySymbols

–ローカライズされた曜日の名称を返す
on getLocalizedShortStandaloneWeekdaySymbols(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s shortStandaloneWeekdaySymbols()
  
return dayNames as list
end getLocalizedShortStandaloneWeekdaySymbols

–ローカライズされた曜日の名称を返す
on getLocalizedVeryShortStandaloneWeekdaySymbols(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s veryShortStandaloneWeekdaySymbols()
  
return dayNames as list
end getLocalizedVeryShortStandaloneWeekdaySymbols

–カレンダー表示ビューを作成
on makeCalendarView(tYear as integer, tMonth as integer, noDispList as list, ignoreP as boolean)
  set colNum to 7
  
set rowNum to 8
  
set aLen to (colNum * rowNum)
  
  
set aButtonCellWidth to 70 –56
  
set aButtonCellHeight to 40
  
  
set viewWidth to aButtonCellWidth * colNum
  
set viewHeight to aButtonCellHeight * rowNum
  
  
–define the matrix size where you’ll put the radio buttons
  
set matrixRect to current application’s NSMakeRect(0.0, 0.0, viewWidth, viewHeight)
  
set aView to NSView’s alloc()’s initWithFrame:(matrixRect)
  
  
set aCount to 1
  
set aFontSize to 30
  
set bArray to current application’s NSMutableArray’s new()
  
  
–Make Header (Month, Year)
  
set x to 1
  
set tmpB to (NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(((x – 1) * aButtonCellWidth), ((aLen – aCount) div colNum) * (aButtonCellHeight), aButtonCellWidth * 4, aButtonCellHeight)))
  (
tmpB’s setEditable:false)
  (
tmpB’s setBordered:false)
  (
tmpB’s setDrawsBackground:false)
  (
tmpB’s setAlignment:(current application’s NSLeftTextAlignment))
  (
tmpB’s setStringValue:((tYear as string) & " / " & tMonth as string))
  (
tmpB’s setFont:(NSFont’s fontWithName:"Times-Roman" |size|:40))
  (
bArray’s addObject:tmpB)
  
  
set aCount to aCount + 1
  
  
  
–Make Header (Weekday)
  
set curLocale to current application’s NSLocale’s currentLocale()
  
set aDS10 to (curLocale’s objectForKey:(current application’s NSLocaleIdentifier)) as string
  
set wdList to getLocalizedShortStandaloneWeekdaySymbols(aDS10) of me
  
set y to 2
  
  
repeat with x from 1 to 7
    set j to contents of item x of wdList
    
set tmpB to (NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(((x – 1) * aButtonCellWidth), ((aLen – aCount) div colNum – 1) * (aButtonCellHeight), aButtonCellWidth, aButtonCellHeight / 2)))
    (
tmpB’s setEditable:false)
    (
tmpB’s setAlignment:(current application’s NSCenterTextAlignment))
    (
tmpB’s setStringValue:(j))
    (
bArray’s addObject:tmpB)
  end repeat
  
  
set aCalList to retListCalendar(tYear, tMonth) of me
  
set aCount to 1
  
  
  
–Make Calendar (Calendar Body)
  
set curDat to current date
  
  
repeat with y from 3 to rowNum
    repeat with x from 1 to colNum
      set j to contents of item aCount of aCalList
      
set tmpB to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(((x – 1) * aButtonCellWidth), ((aLen – aCount) div colNum – 2) * aButtonCellHeight, aButtonCellWidth, aButtonCellHeight)))
      
      
set tmpDate to getDateInternational(tYear, tMonth, j as integer) of me
      
set tmpF to (tmpDate < curDat) as boolean
      
      
if ignoreP = false then
        set dispF to true
      else if ignoreP = true and tmpF = false then
        set dispF to true
      else
        set dispF to false
      end if
      
      
if (j as integer) is not in noDispList then
        if (dispF = true) then
          (tmpB’s setTitle:(j as string))
          (
tmpB’s setFont:(NSFont’s fontWithName:"ArialMT" |size|:aFontSize))
          
–set attrTitle to makeRTFfromParameters((aCount as string), "ArialMT", aFontSize, 0, (aFontSize * 1.2)) of me
          
–(tmpB’s setAttributedTitle:(attrTitle))
          (
tmpB’s setShowsBorderOnlyWhileMouseInside:true)
          (
tmpB’s setAlignment:(current application’s NSCenterTextAlignment))
          (
tmpB’s setEnabled:(j ≠ ""))
          (
tmpB’s setTarget:me)
          (
tmpB’s setAction:("clicked:"))
          (
tmpB’s setButtonType:(NSButtonTypeOnOff))
          (
tmpB’s setHidden:(j = ""))
          
if j is not equal to "" then
            (tmpB’s setTag:(j))
            (
bArray’s addObject:tmpB)
          end if
        end if
      end if
      
set aCount to aCount + 1
    end repeat
  end repeat
  
  (
aView’s setSubviews:bArray)
  
return aView
end makeCalendarView

★Click Here to Open This Script 

(Visited 120 times, 1 visits today)
Posted in Calendar dialog GUI | Tagged 10.14savvy 10.15savvy NSAlert NSButton NSButtonTypeOnOff NSColor NSFont NSFontAttributeName NSForegroundColorAttributeName NSKernAttributeName NSLigatureAttributeName NSMutableArray NSMutableAttributedString NSMutableDictionary NSMutableParagraphStyle NSOffState NSOnState NSParagraphStyleAttributeName NSRunningApplication NSTextField NSUnderlineStyleAttributeName NSView | Leave a comment

Post navigation

  • Older posts

電子書籍(PDF)をオンラインストアで販売中!

Google Search

Popular posts

  • AppleScriptによるWebブラウザ自動操縦ガイド
  • macOS 13, Ventura(継続更新)
  • ドラッグ&ドロップ機能の未来?
  • macOS 12.x上のAppleScriptのトラブルまとめ
  • PFiddlesoft UI Browserが製品終了に
  • macOS 12.3 beta 5、ASの障害が解消される(?)
  • SF Symbolsを名称で指定してPNG画像化
  • 新刊発売:AppleScriptによるWebブラウザ自動操縦ガイド
  • macOS 12.3上でFinder上で選択中のファイルをそのままオープンできない件
  • Pixelmator Pro v2.4.1で新機能追加+AppleScriptコマンド追加
  • Safariで表示中のYouTubeムービーのサムネイル画像を取得
  • macOS 12のスクリプトエディタで、Context Menu機能にバグ
  • 人類史上初、魔導書の観点から書かれたAppleScript入門書「7つの宝珠」シリーズ開始?!
  • UI Browserがgithub上でソース公開され、オープンソースに
  • macOS 12.5(21G72)がリリースされた!
  • Pages v12に謎のバグ。書類上に11枚しか画像を配置できない→解決
  • 新発売:AppleScriptからSiriを呼び出そう!
  • iWork 12.2がリリースされた
  • macOS 13 TTS Voice環境に変更
  • NSCharacterSetの使い方を間違えた

Tags

10.11savvy (1102) 10.12savvy (1243) 10.13savvy (1391) 10.14savvy (586) 10.15savvy (434) 11.0savvy (274) 12.0savvy (174) 13.0savvy (34) CotEditor (60) Finder (47) iTunes (19) Keynote (97) NSAlert (60) NSArray (51) NSBezierPath (18) NSBitmapImageRep (21) NSBundle (20) NSButton (34) NSColor (51) NSDictionary (27) NSFileManager (23) NSFont (18) NSImage (42) NSJSONSerialization (21) NSMutableArray (62) NSMutableDictionary (21) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (118) NSURL (97) NSURLRequest (23) NSUTF8StringEncoding (30) NSUUID (18) NSView (33) NSWorkspace (20) Numbers (55) Pages (36) Safari (41) Script Editor (20) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • Clipboard
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • drive
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • Hex
  • History
  • How To
  • iCloud
  • Icon
  • Image
  • Input Method
  • Internet
  • iOS App
  • JavaScript
  • JSON
  • JXA
  • Keychain
  • Keychain
  • Language
  • Library
  • list
  • Locale
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • PDF
  • Peripheral
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年12月
  • 2019年11月
  • 2019年10月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月
  • 2018年2月

https://piyomarusoft.booth.pm/items/301502

メタ情報

  • 登録
  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org

Forum Posts

  • 人気のトピック
  • 返信がないトピック

メタ情報

  • 登録
  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org
Proudly powered by WordPress
Theme: Flint by Star Verte LLC