Archive for the 'NSDictionary' Category

2017/10/18 QuartzComposerでグラフ表示てすと v4(10.13対応)

QuartzComposerのCompositionを任意のパラメータでレンダリングして表示するAppleScriptのmacOS 10.13.x対応版です。

composition.png

macOS 10.13で変更になったのはQuartzComposerまわりではなく、NSDictionary/NSMutableDictionaryまわりで、キーと値を列挙して、

use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aDict to (current application’s NSMutableDictionary’s dictionaryWithObjectsAndKeys_(1, “aKey”, 2, “bKey”, missing value)) as record
–>  {bKey:2, aKey:1}

★Click Here to Open This Script 

などとNSDictionary/NSMutableDictionaryを作成するタイプのメソッド(末尾にmissing valueがつくもの)です。macOS 10.13上で実行すると、

1013error.jpg

このように(↑)エラーになるので、

use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aDict to (current application’s NSDictionary’s dictionaryWithObjects:{1, 2} forKeys:{“aKey”, “bKey”}) as record
–> {bKey:2, aKey:1}

★Click Here to Open This Script 

などと書き換える必要があります(Thanks Shane!)。

前者の書き方については、書くのが面倒に感じていたので本Blog中でもかぞえるほどしか登場していませんでした。10.13向けの書き換え例としてこれが向いていると判断して掲載してみた次第です。QuartzComposer自体にはとくに思い入れもありません。

なお、表示対象のQuartzCompositionは、本Script Bundle中に入っていることを前提としていますが、バンドル外のものを表示するように書き換えるのも簡単なので実験してみるとよいでしょう。

comp_loc.png

本Script自体はmacOS 10.12上で作成して実行確認しています(当然、10.13.1beta上でも動作確認していますが)。10.13以降で追加になった機能を前提としていません。

–> Download script bundle including Composition

AppleScript名:QuartzComoserでグラフ表示てすと v4(10.13対応)
– Created 2015-11-03 by Takaaki Naganoya
– Modified 2017-10-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “AppKit”
use framework “Carbon” – AEInteractWithUser() is in Carbon
–http://piyocast.com/as/archives/4900

property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSWindowCloseButton : a reference to current application’s NSWindowCloseButton
property NSScreen : a reference to current application’s NSScreen
property NSPredicate : a reference to current application’s NSPredicate
property NSDictionary : a reference to current application’s NSDictionary
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSMutableArray : a reference to current application’s NSMutableArray
property NSTitledWindowMask : a reference to current application’s NSTitledWindowMask
property NSString : a reference to current application’s NSString
property NSWindow : a reference to current application’s NSWindow
property NSNumber : a reference to current application’s NSNumber
property NSNormalWindowLevel : a reference to current application’s NSNormalWindowLevel
property QCView : a reference to current application’s QCView
property NSColor : a reference to current application’s NSColor

if current application’s AEInteractWithUser(-1, missing value, missing value) is not equal to 0 then return

set chartData to NSMutableArray’s new()

–chartData’s addObject:(NSMutableDictionary’s dictionaryWithObjectsAndKeys_(”練馬区”, “label”, 3, “value”, missing value))–older way (Obsolete in 10.13)
chartData’s addObject:(my recWithLabels:{“label”, “value”} andValues:{“練馬区”, 3})
chartData’s addObject:(my recWithLabels:{“label”, “value”} andValues:{“青梅市”, 1})
chartData’s addObject:(my recWithLabels:{“label”, “value”} andValues:{“中野区”, 2})

–上記データの最大値を求める
set aMaxRec to chartData’s filteredArrayUsingPredicate:(NSPredicate’s predicateWithFormat_(“SELF.value == %@.@max.value”, chartData))
set aMax to value of aMaxRec
set aMaxVal to (first item of aMax) as integer

–Scalingの最大値を求める
if aMaxVal 10 then
  set aScaleMax to (10 div aMaxVal)
  
set aScaleMin to aScaleMax div 10
else
  set aScaleMax to (10 / aMaxVal)
  
set aScaleMin to 1
end if

try
  set aPath to path to resource “Chart.qtz”
on error
  return
end try

set qtPath to NSString’s stringWithString:(POSIX path of aPath)

set aView to QCView’s alloc()’s init()
set qtRes to (aView’s loadCompositionFromFile:qtPath)

aView’s setValue:chartData forInputKey:“Data”
aView’s setValue:(NSNumber’s numberWithFloat:(0.5)) forInputKey:“Scale”
aView’s setValue:(NSNumber’s numberWithFloat:(0.2)) forInputKey:“Spacing”
aView’s setAutostartsRendering:true

set maXFrameRate to aView’s maxRenderingFrameRate()

set aWin to (my makeWinWithView(aView, 800, 600, “AppleScript Composition Test”))

(aView’s setValue:(NSNumber’s numberWithFloat:aScaleMax / 10) forInputKey:“Scale”)
delay 5

my closeWin:aWin
aView’s stopRendering() –レンダリング停止

–make Window for Display
on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle)
  set aScreen to NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
  
set aBacking to NSTitledWindowMask
  
  
set aDefer to NSBackingStoreBuffered
  
  
– Window
  
set aWin to NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
aWin’s setBackgroundColor:(NSColor’s whiteColor())
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:false
  
aWin’s setLevel:(NSNormalWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
aWin’s makeKeyAndOrderFront:(me)
  
–aWin’s movableByWindowBackground:true
  
  
– Set Custom View
  
aWin’s setContentView:aView
  
  
–Set Close Button  
  
set closeButton to NSWindow’s standardWindowButton:(NSWindowCloseButton) forStyleMask:(NSTitledWindowMask)
  
  
return aWin
end makeWinWithView

–close win
on closeWin:aWindow
  repeat with n from 10 to 1 by -1
    (aWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
aWindow’s |close|()
end closeWin:

on recWithLabels:theKeys andValues:theValues
  return (NSDictionary’s dictionaryWithObjects:theValues forKeys:theKeys) as record
end recWithLabels:andValues:

★Click Here to Open This Script 

2017/09/24 迷路をRTFで作成して脱出経路を赤く着色する v3

2D迷路の作成プログラム「MazeFinder」(By Toby Jennings)をフレームワーク化したものを呼び出して、文字ベースの迷路データをRTFに変換して脱出経路情報を着色してデスクトップに書き出すAppleScriptのアップデート版です。

迷路データの作成はこの際どうでもよく、文字列の検索を行う部分で問題が起こったことへの対処を行いました。

NSStringの文字検索メソッドrangeOfString: で、検索文字列が見つからなかった場合にNSNotFound(=-1)が返ってくるはずですが、macOS 10.13 betaで動かしてみたところNSNotFoundではなく巨大な数が返ってくることに気づきました。9,223,372,036,854,775,807と巨大すぎてAppleScriptの処理系では数値の精度上限を超えてしまっています。

いろいろ情報収集してみたところ、10.13にかぎらずよく知られた動作のようで、-1ではなく巨大な数を返してしまうパターンがある、と認識しておく必要があるようです(いつものApple仕事)。

AppleScript名:迷路をRTFで作成して脱出経路を赤く着色する v3
– Created 2017-09-19 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “MazeFinder” –https://github.com/tcjennings/MazeFinder
–http://piyocast.com/as/archives/4842

property NSColor : a reference to current application’s NSColor
property Board2D : a reference to current application’s Board2D
property NSUUID : a reference to current application’s NSUUID
property NSDictionary : a reference to current application’s NSDictionary
property NSMutableArray : a reference to current application’s NSMutableArray
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSFont : a reference to current application’s NSFont
property NSString : a reference to current application’s NSString
property NSDocumentTypeDocumentAttribute : a reference to current application’s NSDocumentTypeDocumentAttribute
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName
property Pathfinder : a reference to current application’s Pathfinder
property NSLiteralSearch : a reference to current application’s NSLiteralSearch
–NSNotFoundはプロパティに代入しても認識されなかった

set targFontName to “Courier-Bold” –PostScript Name
set targFontSize to 13 –Point

–迷路テキストデータ作成→Attributed Stringに
set aStr to create2DMazeAndSolveIt(30, 30, 1, 1, 28, 28) of me –Plain Text
set anAttr to changeAttrStrsFontAttribute(aStr, targFontName, targFontSize) of me –Attributed String

–迷路データに着色(参照呼び出し, Call by reference)
markCharOfAttributedString(anAttr, aStr, “!”, (NSColor’s redColor())) of me

–結果のRTFをデスクトップ上に書き出す。ファイル名はUUID.rtf
set targFol to current application’s NSHomeDirectory()’s stringByAppendingPathComponent:“Desktop”
set aRes to my saveStyledTextAsRTF(targFol, anAttr)

–指定のAttributed String内で指定文字列が含まれる箇所に指定の色をつける(結果はメイン側に参照渡し)
on markCharOfAttributedString(anAttr, origStr, aTargStr, aColor)
  set rList to searchWordWithRange(origStr, aTargStr) of me
  
repeat with ii in rList
    (anAttr’s addAttribute:(NSForegroundColorAttributeName) value:aColor range:ii)
  end repeat
end markCharOfAttributedString

–指定の文字列をAttributed Stringに変換して任意のフォントを一括指定
on changeAttrStrsFontAttribute(aStr, aFontPSName, aFontSize)
  set tmpAttr to NSMutableAttributedString’s alloc()’s initWithString:aStr
  
set aRange to current application’s NSMakeRange(0, tmpAttr’s |length|())
  
set aVal1 to NSFont’s fontWithName:aFontPSName |size|:aFontSize
  
tmpAttr’s beginEditing()
  
tmpAttr’s addAttribute:(NSFontAttributeName) value:aVal1 range:aRange
  
tmpAttr’s endEditing()
  
return tmpAttr
end changeAttrStrsFontAttribute

–指定テキストデータ(atargText)内に、指定文字列(aSearchStr)が含まれる範囲情報(NSRange)をすべて取得する
on searchWordWithRange(aTargText, aSearchStr)
  set aStr to NSString’s stringWithString:aTargText
  
set bStr to NSString’s stringWithString:aSearchStr
  
set hitArray to NSMutableArray’s alloc()’s init()
  
set cNum to (aStr’s |length|()) as integer
  
  
set aRange to current application’s NSMakeRange(0, cNum)
  
  
repeat
    set detectedRange to aStr’s rangeOfString:bStr options:NSLiteralSearch range:aRange
    
set aLoc to (detectedRange’s location)
    
–CAUTION !!!! Sometimes aLoc returns not NSNotFound (-1) but a Very large number
    
if (aLoc > 9.999999999E+9) or (aLoc = (current application’s NSNotFound)) then exit repeat
    
    
hitArray’s addObject:detectedRange
    
    
set aNum to aLoc as integer
    
set bNum to (detectedRange’s |length|) as integer
    
    
set aRange to current application’s NSMakeRange(aNum + bNum, cNum - (aNum + bNum))
  end repeat
  
  
return hitArray
end searchWordWithRange

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(targFol, aStyledString)
  set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to NSDictionary’s dictionaryWithObject:“NSRTFTextDocumentType” forKey:(NSDocumentTypeDocumentAttribute)
  
set bRTF to aStyledString’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict
  
  
set theName to (NSUUID’s UUID()’s UUIDString())
  
set thePath to NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“rtf”
  
return (bRTF’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsRTF

–2D迷路を作成して脱出経路を検索して文字列で迷路データを出力する
–迷路サイズ x,y スタート座標 x, y ゴール座標 x,y
on create2DMazeAndSolveIt(xMax, yMax, xStart, yStart, xGoal, yGoal)
  set myBoard to Board2D’s alloc()’s init()
  
myBoard’s setupBoardWithRows:xMax WithColumns:yMax –60×60ぐらいが上限。正方形でないとダメ
  
myBoard’s createMazeFromBoard()
  
  
set myPathfinder to Pathfinder’s alloc()’s init()
  
set myPath to myPathfinder’s findPathThroughMaze:myBoard fromX:xStart fromY:yStart toX:xGoal toY:yGoal
  
  
set aCount to myPath’s |count|()
  
if aCount > 0 then
    set aRes to myBoard’s drawPathThroughMaze:myPath
    
return aRes as string
  else
    return false
  end if
end create2DMazeAndSolveIt

★Click Here to Open This Script 

2017/09/21 迷路をRTFで作成して脱出経路を赤く着色する v2

2D迷路の作成プログラム「MazeFinder」(By Toby Jennings)をフレームワーク化したものを呼び出して、文字ベースの迷路データをRTFに変換して脱出経路情報を着色してデスクトップに書き出すAppleScriptのアップデート版です。

maze1.png

処理結果はとくに前バージョンと変化ありませんし、実行時間については前バージョンよりも0.02秒ほど余計にかかるようになりました。

では、なぜ書き換えたかといえば、各機能の再利用性の向上が目的です。せっかく書いておいても、他の用途に転用するのに手間がかかるようであれば意味がありません。さまざまな用途に転用しやすい構造(サブルーチンとしてまとめているとか)に書いておくことはとても重要です。

再利用したい機能モジュールをよりサブルーチン化するように書き換えました。こうしておくことで、まったく違った用途にもすぐに転用できます。

本Scriptを試す場合には、MazeFinder.frameworkをダウンロードして~/Library/Frameworksフォルダに入れてください。

–> Download Framework Binary

60×60の迷路を作成して着色してファイル書き出しを終了するまでに、開発環境で0.1秒程度かかりました(前バージョンは0.08秒ぐらい)。

AppleScript名:迷路をRTFで作成して脱出経路を赤く着色する v2
– Created 2017-09-19 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “MazeFinder” –https://github.com/tcjennings/MazeFinder
–http://piyocast.com/as/archives/4834

property NSColor : a reference to current application’s NSColor
property Board2D : a reference to current application’s Board2D
property NSUUID : a reference to current application’s NSUUID
property NSDictionary : a reference to current application’s NSDictionary
property NSMutableArray : a reference to current application’s NSMutableArray
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSFont : a reference to current application’s NSFont
property NSString : a reference to current application’s NSString
property NSDocumentTypeDocumentAttribute : a reference to current application’s NSDocumentTypeDocumentAttribute
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName
property Pathfinder : a reference to current application’s Pathfinder
property NSLiteralSearch : a reference to current application’s NSLiteralSearch
–NSNotFoundはプロパティに代入しても認識されなかった

set targFontName to “Courier-Bold” –PostScript Name
set targFontSize to 13 –Point

–迷路テキストデータ作成→Attributed Stringに
set aStr to create2DMazeAndSolveIt(30, 30, 1, 1, 28, 28) of me –Plain Text
set anAttr to changeAttrStrsFontAttribute(aStr, targFontName, targFontSize) of me –Attributed String

–迷路データに着色(参照呼び出し, Call by reference)
markCharOfAttributedString(anAttr, aStr, “!”, (NSColor’s redColor())) of me

–結果のRTFをデスクトップ上に書き出す。ファイル名はUUID.rtf
set targFol to current application’s NSHomeDirectory()’s stringByAppendingPathComponent:“Desktop”
set aRes to my saveStyledTextAsRTF(targFol, anAttr)

–指定のAttributed String内で指定文字列が含まれる箇所に指定の色をつける(結果はメイン側に参照渡し)
on markCharOfAttributedString(anAttr, origStr, aTargStr, aColor)
  set rList to searchWordWithRange(origStr, aTargStr) of me
  
repeat with ii in rList
    (anAttr’s addAttribute:(NSForegroundColorAttributeName) value:aColor range:ii)
  end repeat
end markCharOfAttributedString

–指定の文字列をAttributed Stringに変換して任意のフォントを一括指定
on changeAttrStrsFontAttribute(aStr, aFontPSName, aFontSize)
  set tmpAttr to NSMutableAttributedString’s alloc()’s initWithString:aStr
  
set aRange to current application’s NSMakeRange(0, tmpAttr’s |length|())
  
set aVal1 to NSFont’s fontWithName:aFontPSName |size|:aFontSize
  
tmpAttr’s beginEditing()
  
tmpAttr’s addAttribute:(NSFontAttributeName) value:aVal1 range:aRange
  
tmpAttr’s endEditing()
  
return tmpAttr
end changeAttrStrsFontAttribute

–指定テキストデータ(atargText)内に、指定文字列(aSearchStr)が含まれる範囲情報(NSRange)をすべて取得する
on searchWordWithRange(aTargText, aSearchStr)
  set aStr to NSString’s stringWithString:aTargText
  
set bStr to NSString’s stringWithString:aSearchStr
  
set hitArray to NSMutableArray’s alloc()’s init()
  
set cNum to (aStr’s |length|()) as integer
  
  
set aRange to current application’s NSMakeRange(0, cNum)
  
  
set aCount to 1
  
repeat
    set detectedRange to aStr’s rangeOfString:bStr options:NSLiteralSearch range:aRange
    
if detectedRange’s location is equal to (current application’s NSNotFound) then exit repeat
    
    
hitArray’s addObject:detectedRange
    
    
set aNum to (detectedRange’s location) as integer
    
set bNum to (detectedRange’s |length|) as integer
    
    
set aRange to current application’s NSMakeRange(aNum + bNum, cNum - (aNum + bNum))
    
set aCount to aCount + 1
  end repeat
  
  
return hitArray
end searchWordWithRange

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(targFol, aStyledString)
  set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to NSDictionary’s dictionaryWithObject:“NSRTFTextDocumentType” forKey:(NSDocumentTypeDocumentAttribute)
  
set bRTF to aStyledString’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict
  
  
set theName to (NSUUID’s UUID()’s UUIDString())
  
set thePath to NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“rtf”
  
return (bRTF’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsRTF

–2D迷路を作成して脱出経路を検索して文字列で迷路データを出力する
–迷路サイズ x,y スタート座標 x, y ゴール座標 x,y
on create2DMazeAndSolveIt(xMax, yMax, xStart, yStart, xGoal, yGoal)
  set myBoard to Board2D’s alloc()’s init()
  
myBoard’s setupBoardWithRows:xMax WithColumns:yMax –60×60ぐらいが上限。正方形でないとダメ
  
myBoard’s createMazeFromBoard()
  
  
set myPathfinder to Pathfinder’s alloc()’s init()
  
set myPath to myPathfinder’s findPathThroughMaze:myBoard fromX:xStart fromY:yStart toX:xGoal toY:yGoal
  
  
set aCount to myPath’s |count|()
  
if aCount > 0 then
    set aRes to myBoard’s drawPathThroughMaze:myPath
    
return aRes as string
  else
    return false
  end if
end create2DMazeAndSolveIt

★Click Here to Open This Script 

2017/09/20 迷路をRTFで作成して脱出経路を赤く着色する

2D迷路の作成プログラム「MazeFinder」(By Toby Jennings)をフレームワーク化したものを呼び出して、文字ベースの迷路データをRTFに変換して脱出経路情報を着色してデスクトップに書き出すAppleScriptです。

maze1.png

本Scriptを試す場合には、MazeFinder.frameworkをダウンロードして~/Library/Frameworksフォルダに入れてください。

60×60の迷路を作成して着色してファイル書き出しを終了するまでに、開発環境で0.08秒程度かかりました。

–> Download Framework Binary

迷路作成の処理自体についてはとくに意味はありませんが、迷路プログラム自体にもいろいろあるようです。このMazeFinderについてはいろいろ制約条件がきつく(最大サイズ60×60程度、迷路が正方形でないとクラッシュ)、あまり迷路らしい迷路にもなっていません。

「テキストデータをRTFで出力して特定文字に着色する」というあたりの処理がミソでしょうか。

AppleScript名:迷路をRTFに作成して脱出経路を赤く着色する
– Created 2017-09-19 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “MazeFinder” –https://github.com/tcjennings/MazeFinder
–http://piyocast.com/as/archives/4831

property NSColor : a reference to current application’s NSColor
property Board2D : a reference to current application’s Board2D
property NSUUID : a reference to current application’s NSUUID
property NSDictionary : a reference to current application’s NSDictionary
property NSMutableArray : a reference to current application’s NSMutableArray
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSFont : a reference to current application’s NSFont
property NSString : a reference to current application’s NSString
property NSDocumentTypeDocumentAttribute : a reference to current application’s NSDocumentTypeDocumentAttribute
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName
property Pathfinder : a reference to current application’s Pathfinder
property NSLiteralSearch : a reference to current application’s NSLiteralSearch

set targFontName to “Courier-Bold” –”Courier New”/”Osaka-Mono”

–Create Maze Text
set aStr to create2DMazeAndSolveIt(30, 30, 1, 1, 28, 28) of me
set anAttr to NSMutableAttributedString’s alloc()’s initWithString:aStr

set bList to {“!”} –Mark Target List

–Set Fixed Width Font
set aRange to current application’s NSMakeRange(0, anAttr’s |length|())
set aVal1 to NSFont’s fontWithName:targFontName |size|:13
anAttr’s beginEditing()
anAttr’s addAttribute:(current application’s NSFontAttributeName) value:aVal1 range:aRange
anAttr’s endEditing()

–Change Attribute (red color)
repeat with i in bList
  set rList to searchWordWithRange(aStr, i as string) of me
  
repeat with ii in rList
    (anAttr’s addAttribute:(current application’s NSForegroundColorAttributeName) value:(NSColor’s redColor()) range:ii)
  end repeat
end repeat

–結果のRTFをデスクトップ上に書き出す
set targFol to current application’s NSHomeDirectory()’s stringByAppendingPathComponent:“Desktop”
set aFileName to (NSUUID’s UUID()’s UUIDString() as text)
set aRes to my saveStyledTextAsRTF(aFileName, targFol, anAttr)

on searchWordWithRange(aTargText, aSearchStr)
  set aStr to NSString’s stringWithString:aTargText
  
set bStr to NSString’s stringWithString:aSearchStr
  
set hitArray to NSMutableArray’s alloc()’s init()
  
set cNum to (aStr’s |length|()) as integer
  
  
set aRange to current application’s NSMakeRange(0, cNum)
  
  
set aCount to 1
  
repeat
    set detectedRange to aStr’s rangeOfString:bStr options:NSLiteralSearch range:aRange
    
if detectedRange’s location is equal to (current application’s NSNotFound) then exit repeat
    
    
hitArray’s addObject:detectedRange
    
    
set aNum to (detectedRange’s location) as integer
    
set bNum to (detectedRange’s |length|) as integer
    
    
set aRange to current application’s NSMakeRange(aNum + bNum, cNum - (aNum + bNum))
    
set aCount to aCount + 1
  end repeat
  
  
return hitArray
end searchWordWithRange

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(aFileName, targFol, aStyledString)
  –Convert NSMutableStyledStrings to RTF
  
set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to NSDictionary’s dictionaryWithObject:“NSRTFTextDocumentType” forKey:(NSDocumentTypeDocumentAttribute)
  
set bRTF to aStyledString’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict
  
  
– Build Path
  
set theName to NSString’s stringWithString:aFileName
  
–set theName to theName’s stringByReplacingOccurrencesOfString:”/” withString:”_”
  
–set theName to theName’s stringByReplacingOccurrencesOfString:”:” withString:”_”
  
set thePath to NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“rtf”
  
  
return (bRTF’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsRTF

–2D迷路を作成して脱出経路を検索して文字列で迷路データを出力する
–迷路サイズ x,y スタート座標 x, y ゴール座標 x,y
on create2DMazeAndSolveIt(xMax, yMax, xStart, yStart, xGoal, yGoal)
  set myBoard to Board2D’s alloc()’s init()
  
myBoard’s setupBoardWithRows:xMax WithColumns:yMax –60×60ぐらいが上限。正方形でないとダメ
  
myBoard’s createMazeFromBoard()
  
  
set myPathfinder to Pathfinder’s alloc()’s init()
  
set myPath to myPathfinder’s findPathThroughMaze:myBoard fromX:xStart fromY:yStart toX:xGoal toY:yGoal
  
  
set aCount to myPath’s |count|()
  
if aCount > 0 then
    set aRes to myBoard’s drawPathThroughMaze:myPath
    
return aRes as string
  else
    return false
  end if
end create2DMazeAndSolveIt

★Click Here to Open This Script 

2017/09/08 iTunes Library上のsongでライブラリへの追加年を集計してKeynote書類上にグラフ作成

iTunesのMusic Libraryで楽曲のライブラリへの追加年で集計を行ってKeynote上にグラフを作成するAppleScriptです。6,775曲が登録されている自分のライブラリで集計→グラフ作成で3秒程度です。

itunes_usic.png

iTunes LibraryへのアクセスをiTunesLibrary framework経由で行い、NSCountedSetで集計を行うことで高速に処理を行ないます。

iTunesの基礎的な操作については電子書籍「iTunes Control」にて、Keynoteのグラフ作成については、電子書籍「Keynote Control with AppleScript」 △脳楮戮望匆陲靴討い泙后6縮がある方はぜひお買い求めください。

年々、楽曲を聴かない&買わなくなっている様子が見てとれますが、ほかの人はどんなもんなのか興味があります。

AppleScript名:iTunes Library上のsongでライブラリへの追加年で集計してKeynote書類上にグラフ作成
– Created 2017-09-06 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “iTunesLibrary”
–http://piyocast.com/as/archives/4816

property NSString : a reference to current application’s NSString
property NSArray : a reference to current application’s NSArray
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSDictionary : a reference to current application’s NSDictionary
property NSCountedSet : a reference to current application’s NSCountedSet
property ITLibrary : a reference to current application’s ITLibrary
property NSMutableArray : a reference to current application’s NSMutableArray

set yRec to retSongAddedYear() of me
–>  {{theName:2005, numberOfTimes:1907}….}

–楽曲のiTunesライブラリへの追加「年」のみ抽出
set yList to ((NSArray’s arrayWithArray:yRec)’s valueForKeyPath:“theName”) as list
–>  {2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017}

–楽曲のiTunesライブラリへの追加「年」ごとのカウントを抽出
set vList to ((NSArray’s arrayWithArray:yRec)’s valueForKeyPath:“numberOfTimes”) as list
–>  {1907, 1125, 853, 319, 638, 353, 351, 241, 605, 344, 71, 76, 28}

tell application “Keynote”
  set adoc to (make new document with properties {document theme:theme “ホワイト”, height:768, width:1024}) –Caution: theme name is **localized** (”White”)
  
tell front document
    set base slide of current slide to master slide “空白” –Caution: master slide name is **localized** (”Blank”)
    
tell current slide
      add chart row names {“ライブラリ追加年”} column names yList data {vList} type vertical_bar_2d group by chart row –row name is “iTunes Library Added Year”
    end tell
  end tell
  
activate
end tell

on retSongAddedYear()
  set library to ITLibrary’s libraryWithAPIVersion:“1.0″ |error|:(missing value)
  
if library is equal to missing value then return {}
  
  
set allTracks to library’s allMediaItems()
  
set allCount to allTracks’s |count|()
  
  
set anEnu to allTracks’s objectEnumerator()
  
set newArray to NSMutableArray’s alloc()’s init()
  
  
repeat
    set aPL to anEnu’s nextObject()
    
if aPL = missing value then exit repeat
    
try
      set aKind to (aPL’s mediaKind) as integer
      
if (aKind as integer) is equal to 2 then –Music, Song
        set pMonth to ((aPL’s addedDate() as date)’s year) as integer
        
newArray’s addObject:(pMonth)
      end if
    on error
      set aLoc to (aPL’s location’s |path|()) as string
    end try
  end repeat
  
  
return countItemsByItsAppearance(newArray) of me
end retSongAddedYear

–出現回数で集計
on countItemsByItsAppearance(aList)
  set aSet to NSCountedSet’s alloc()’s initWithArray:aList
  
set bArray to NSMutableArray’s array()
  
set theEnumerator to aSet’s objectEnumerator()
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
bArray’s addObject:(NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{“theName”, “numberOfTimes”})
  end repeat
  
  
–出現回数(numberOfTimes)で降順ソート
  
set theDesc to NSSortDescriptor’s sortDescriptorWithKey:“theName” ascending:true
  
bArray’s sortUsingDescriptors:{theDesc}
  
  
return bArray as list
end countItemsByItsAppearance

★Click Here to Open This Script 

2017/08/17 japaneseTokenizeのじっけん

macOSの日本語形態素解析の機能を呼び出して日本語テキストをParseするCocoa Framework「japaneseTokenize.framework」を作成しました。それを呼び出すAppleScriptです。

「japaneseTokenize.framework」はゼロから書いたはじめてのObjective-Cのプログラムでもあります(ほぼコピペで作成してありますが)。Header Fileなんて書かないので、見よう見真似&XcodeのWarning Messageのいいなりで試行錯誤していました。

CFStringTokenizer経由で形態素解析してふりがな、元テキスト、ローマ字ふりがなを取得する「parseString:」と、NSLinguisticTagger経由で形態素解析して元テキスト、品詞を取得する「parseStringWithLinguisticTag:」の2つのメソッドを用意してみました。

これら2つの形態素解析機能のparseの結果が矛盾しているかどうかは未確認です(短い文章では同じことを確認してありますが、長い文章でも同じかどうかは未確認。多分同じだとは思いますけれども)。

(CFStringTokenizer)parseString:
(*これ, ら, 2, つ, の, 形態, 素, 解析, 機能, の, parse, の, 結果, が, 矛盾, し, て, いる, か, どう, か, は, 未, 確認, です, 。, 短い, 文章, で, は, 同じ, こと, を, 確認, し, て, あり, ます, が, 、, 長い, 文章, で, も, 同じ, か, どう, か, は, 未, 確認, 。, 多分, 同じ, だ, と, は, 思い, ます, けれど, も, 。*)

(NSLinguisticTagger) parseStringWithLinguisticTag:
(*これら, 2つ, の, 形態素, 解析, 機能, の, parse, の, 結果, が, 矛盾, し, て, いる, か, どう, か, は, 未, 確認, です, 。, 短い, 文章, で, は, 同じ, こと, を, 確認, し, て, あり, ます, が, 、, 長い, 文章, で, も, 同じ, か, どう, か, は, 未, 確認, 。, 多分, 同じ, だ, と, は, 思い, ます, けれど, も, 。*)

(ご参考) AppleScriptの「words of」の実行結果
(*これ, ら, 2, つ, の, 形態, 素, 解析, 機能, の, parse, の, 結果, が, 矛盾, し, て, いる, か, どう, か, は, 未, 確認, です, 短い, 文章, で, は, 同じ, こと, を, 確認, し, て, あり, ます, が, 長い, 文章, で, も, 同じ, か, どう, か, は, 未, 確認, 多分, 同じ, だ, と, は, 思い, ます, けれど, も*)

# うわ、まさかの「微妙に形態素解析結果が違っている」パターンが来た、、、(ーー; macOS 10.13 Betaで試してみたところ、CFStringTokenizer側の形態素解析結果に合わせてNSLinguisticTagger側の出力結果を修正している模様

NSLinguisticTaggerが返す品詞については、いまひとつしっくりこないですし、ユーザーが定義したユーザー定義辞書を考慮して形態素解析したりしないので、実用性についてはさっぱりな印象です。さまざまなWeb APIをAppleScriptから呼び出してみた印象からいえば、Apitoreの形態素解析APIが一番納得できる内容に見えます(Googleの形態素解析APIはまだ呼んでいません)。

jparsers.png

Yahoo!日本語形態素解析Web APIによる解析結果:
–> {ResultSet:{attributes:{xmlns:”urn:yahoo:jp:jlp”, |xsi:schemalocation|:”urn:yahoo:jp:jlp https://jlp.yahooapis.jp/MAService/V1/parseResponse.xsd”, |xmlns:xsi|:”http://www.w3.org/2001/XMLSchema-instance”}, ma_result:{total_count:{|contents|:”8″}, filtered_count:{|contents|:”8″}, word_list:{|word|:{{surface:{|contents|:”来週”}, reading:{|contents|:”らいしゅう”}, pos:{|contents|:”名詞”}}, {surface:{|contents|:”の”}, reading:{|contents|:”の”}, pos:{|contents|:”助詞”}}, {surface:{|contents|:”水曜日”}, reading:{|contents|:”すいようび”}, pos:{|contents|:”名詞”}}, {surface:{|contents|:”に”}, reading:{|contents|:”に”}, pos:{|contents|:”助詞”}}, {surface:{|contents|:”会議”}, reading:{|contents|:”かいぎ”}, pos:{|contents|:”名詞”}}, {surface:{|contents|:”を”}, reading:{|contents|:”を”}, pos:{|contents|:”助詞”}}, {surface:{|contents|:”予約”}, reading:{|contents|:”よやく”}, pos:{|contents|:”名詞”}}, {surface:{|contents|:”。”}, reading:{|contents|:”。”}, pos:{|contents|:”特殊”}}}}}}}

Apitore 日本語形態素解析【新語対応】 ipadic neologdによる解析結果:
–> {startTime:”1502971949537″, tokens:{{partOfSpeechLevel1:”名詞”, baseForm:”来週”, pronunciation:”ライシュー”, position:0, partOfSpeechLevel3:”*”, reading:”ライシュウ”, surface:”来週”, known:true, allFeatures:”名詞,副詞可能,*,*,*,*,来週,ライシュウ,ライシュー”, conjugationType:”*”, partOfSpeechLevel2:”副詞可能”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “副詞可能”, “*”, “*”, “*”, “*”, “来週”, “ライシュウ”, “ライシュー”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”の”, pronunciation:”ノ”, position:2, partOfSpeechLevel3:”*”, reading:”ノ”, surface:”の”, known:true, allFeatures:”助詞,連体化,*,*,*,*,の,ノ,ノ”, conjugationType:”*”, partOfSpeechLevel2:”連体化”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “連体化”, “*”, “*”, “*”, “*”, “の”, “ノ”, “ノ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”水曜日”, pronunciation:”スイヨービ”, position:3, partOfSpeechLevel3:”*”, reading:”スイヨウビ”, surface:”水曜日”, known:true, allFeatures:”名詞,副詞可能,*,*,*,*,水曜日,スイヨウビ,スイヨービ”, conjugationType:”*”, partOfSpeechLevel2:”副詞可能”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “副詞可能”, “*”, “*”, “*”, “*”, “水曜日”, “スイヨウビ”, “スイヨービ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”に”, pronunciation:”ニ”, position:6, partOfSpeechLevel3:”一般”, reading:”ニ”, surface:”に”, known:true, allFeatures:”助詞,格助詞,一般,*,*,*,に,ニ,ニ”, conjugationType:”*”, partOfSpeechLevel2:”格助詞”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “格助詞”, “一般”, “*”, “*”, “*”, “に”, “ニ”, “ニ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”会議”, pronunciation:”カイギ”, position:7, partOfSpeechLevel3:”*”, reading:”カイギ”, surface:”会議”, known:true, allFeatures:”名詞,サ変接続,*,*,*,*,会議,カイギ,カイギ”, conjugationType:”*”, partOfSpeechLevel2:”サ変接続”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “サ変接続”, “*”, “*”, “*”, “*”, “会議”, “カイギ”, “カイギ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”を”, pronunciation:”ヲ”, position:9, partOfSpeechLevel3:”一般”, reading:”ヲ”, surface:”を”, known:true, allFeatures:”助詞,格助詞,一般,*,*,*,を,ヲ,ヲ”, conjugationType:”*”, partOfSpeechLevel2:”格助詞”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “格助詞”, “一般”, “*”, “*”, “*”, “を”, “ヲ”, “ヲ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”予約”, pronunciation:”ヨヤク”, position:10, partOfSpeechLevel3:”*”, reading:”ヨヤク”, surface:”予約”, known:true, allFeatures:”名詞,サ変接続,*,*,*,*,予約,ヨヤク,ヨヤク”, conjugationType:”*”, partOfSpeechLevel2:”サ変接続”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “サ変接続”, “*”, “*”, “*”, “*”, “予約”, “ヨヤク”, “ヨヤク”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”記号”, baseForm:”。”, pronunciation:”。”, position:12, partOfSpeechLevel3:”*”, reading:”。”, surface:”。”, known:true, allFeatures:”記号,句点,*,*,*,*,。,。,。”, conjugationType:”*”, partOfSpeechLevel2:”句点”, conjugationForm:”*”, allFeaturesArray:{”記号”, “句点”, “*”, “*”, “*”, “*”, “。”, “。”, “。”}, partOfSpeechLevel4:”*”}}, endTime:”1502971949537″, |log|:”", processTime:”0″}

japaneseTokenize.frameworkをmacOS 10.10以降用にビルドしたバイナリを用意しましたので、自己責任で~/Library/Frameworksフォルダに入れて使ってみてください。

→ Download japaneseTokenize framework Binary

AppleScript名:japaneseTokenizeのじっけん
– Created 2017-08-17 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “japaneseTokenize”
–https://github.com/murakami/workbook/tree/master/mac/Ruby
–http://d.hatena.ne.jp/shu223/20130318/1363566717

–http://piyocast.com/as/archives/4778

set targString to “来週の水曜日に会議を予約。” –”Make a meeting on next Wednesday.” in Japanese

set aRes to current application’s jTokenize’s parseString:targString
–> {{token:”来週”, romaji:”raishuu”, hurigana:”らいしゅう”}, {token:”の”, romaji:”no”, hurigana:”の”}, {token:”水曜”, romaji:”suiyou”, hurigana:”すいよう”}, {token:”日”, romaji:”hi”, hurigana:”ひ”}, {token:”に”, romaji:”ni”, hurigana:”に”}, {token:”会議”, romaji:”kaigi”, hurigana:”かいぎ”}, {token:”を”, romaji:”wo”, hurigana:”を”}, {token:”予約”, romaji:”yoyaku”, hurigana:”よやく”}, {token:”。”, romaji:”。”, hurigana:”。”}}

set aList to (aRes’s valueForKeyPath:“hurigana”) as list –ふりがな
–>  {”らいしゅう”, “の”, “すいよう”, “ひ”, “に”, “かいぎ”, “を”, “よやく”, “。”}

set bList to (aRes’s valueForKeyPath:“token”) as list –元のテキスト
–>  {”来週”, “の”, “水曜”, “日”, “に”, “会議”, “を”, “予約”, “。”}

set cList to (aRes’s valueForKeyPath:“romaji”) as list –hurigana (romaji)
–>  {”raishuu”, “no”, “suiyou”, “hi”, “ni”, “kaigi”, “wo”, “yoyaku”, “。”}

set bRes to current application’s jTokenize’s parseStringWithLinguisticTag:targString
set dList to (bRes’s valueForKeyPath:“scheme”) as list
–>  {”Noun”, “Particle”, “Noun”, “Noun”, “Particle”, “Noun”, “Particle”, “Noun”, “SentenceTerminator”}

return bRes as list
–> {{token:”来週”, |scheme|:”Noun”}, {token:”の”, |scheme|:”Particle”}, {token:”水曜”, |scheme|:”Noun”}, {token:”日”, |scheme|:”Noun”}, {token:”に”, |scheme|:”Particle”}, {token:”会議”, |scheme|:”Noun”}, {token:”を”, |scheme|:”Particle”}, {token:”予約”, |scheme|:”Noun”}, {token:”。”, |scheme|:”SentenceTerminator”}}

★Click Here to Open This Script 

2017/07/23 指定の画像をASCII ART化してTextEditでオープン v3

jp2aを利用して指定の画像を色付きHTML形式のアスキーアート化して出力し、HTMLをRTFに変換してTextEditでオープンしてフォントを変更するAppleScriptの改良版です。

指定のJPEG画像をアスキーアート化するjp2aは、Homebrew経由でインストールしてください。

asciiart_gc1_resized.png

画像種別をとくに問わないように対応してみました。ただし、PNG画像については背景が透過している場合には画像余白トリミングフレームワーク「KGPixelBoundsClipKit」を用いてトリミングし、JPEG画像に変換します。

最大の変更点は、TextEditに対して命令を投げてフォントを指定していたものから、NSMutableAttributedStringに対してCocoaの機能を利用してフォント種別を指定するように変更したところです(意外と翻訳元となるObjective-Cの記述例が見つからない)。

テストする際には、KGPixelBoundsClipKitフレームワークのバイナリを~/Library/Frameworksフォルダに入れてお試しください。

–> Download Framework Binary

AppleScript名:指定の画像をASCII ART化してTextEditでオープン v3
– Created 2017-07-23 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “KGPixelBoundsClipKit” –https://github.com/kgn/KGPixelBoundsClip
–http://piyocast.com/as/archives/4740

set targFontName to “Osaka-Mono” –”Courier New”

set aFile to choose file of type {“public.image”}
tell application “System Events”
  set aType to type identifier of aFile –get UTI
end tell

if aType is equal to “public.png” then
  –PNGの場合、画像の余白をトリミング(背景が透過している場合にかぎる)
  
set anImage to (current application’s NSImage’s alloc()’s initWithContentsOfFile:(POSIX path of aFile))
  
set bImage to anImage’s imageClippedToPixelBounds()
  
  
–トリミング結果をデスクトップにJPEG形式で保存
  
set aDesktopPath to (current application’s NSProcessInfo’s processInfo()’s environment()’s objectForKey:(“HOME”))’s stringByAppendingString:“/Desktop/”
  
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.jpg”)
  
set fRes to saveNSImageAtPathAsJPG(bImage, savePath, 100) of me
  
set aaFile to (POSIX file (savePath as string)) as alias
  
else if aType is equal to “public.jpeg” then
  –JPEGの場合
  
copy aFile to aaFile
  
else
  –PNGとJPEG以外の場合には読み込んでJPEGに変換
  
set aImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:(POSIX path of aFile)
  
set fRes to retUUIDfilePath(POSIX path of aFile, “jpg”) of me
  
set sRes to saveNSImageAtPathAsJPG(aImage, fRes, 100) of me
  
set aaFile to (POSIX file (fRes as string)) as alias
  
end if

–ASCII ARTに変換してHTMLとして出力
set htmlRes to jpegToAsciiArt(aaFile, 120) of me

–出力されたHTMLデータを評価してスタイル付きテキストに変換
set htmlData to current application’s NSString’s stringWithString:htmlRes
set keyList to {current application’s NSDocumentTypeDocumentAttribute, current application’s NSCharacterEncodingDocumentAttribute}
set valList to {current application’s NSHTMLTextDocumentType, current application’s NSUTF8StringEncoding}
set optDict to current application’s NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList

set aStyledStr to current application’s NSMutableAttributedString’s alloc()’s initWithData:(htmlData’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)) options:optDict documentAttributes:(missing value) |error|:(missing value)

–フォント種別およびサイズを指定してみた
set aRange to current application’s NSMakeRange(0, aStyledStr’s |length|())
set aVal1 to current application’s NSFont’s fontWithName:targFontName |size|:11
aStyledStr’s beginEditing()
aStyledStr’s addAttribute:(current application’s NSFontAttributeName) value:aVal1 range:aRange
aStyledStr’s endEditing()

–スタイル付きテキストをRTFとしてデスクトップに保存
set targFol to POSIX path of (path to desktop)
set aUUID to current application’s NSUUID’s UUID()’s UUIDString() as text
set bRes to my saveStyledTextAsRTF(aUUID, targFol, aStyledStr) –PDFで書き出す
set newPath to targFol & aUUID & “.rtf”

–Macの画面(メインスクリーン)の高さを取得する
set dRec to ((current application’s NSScreen’s mainScreen())’s deviceDescription()’s NSDeviceSize) as record
set dHeight to (height of dRec) as integer

–保存したRTFをTextEditでオープンして等幅フォント設定して、Window横幅を変更
tell application “TextEdit”
  activate
  
open (POSIX file newPath) as alias
  
  
tell window 1
    set {x1, y1, x2, y2} to bounds
    
set bounds to {x1, y1, (x1 + 1024), dHeight}
  end tell
  
  
tell document 1
    save
  end tell
end tell

–指定ファイルパスと同一階層にファイル名をUUID、拡張子を指定したものを作成して返す
on retUUIDfilePath(aPath, aEXT)
  set aUUIDstr to (current application’s NSUUID’s UUID()’s UUIDString()) as string
  
set aPath to ((current application’s NSString’s stringWithString:aPath)’s stringByDeletingLastPathComponent()’s stringByAppendingPathComponent:aUUIDstr)’s stringByAppendingPathExtension:aEXT
  
return aPath
end retUUIDfilePath

–NSImageを指定パスにJPEG形式で保存
on saveNSImageAtPathAsJPG(anImage, outPath, qulityNum as real)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSJPEGFileType) |properties|:{NSImageCompressionFactor:qulityNum})
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –true/false
end saveNSImageAtPathAsJPG

–与えられたファイルパスのJPEG画像をASCII ARTに変換して返す
on jpegToAsciiArt(anImageAlias, digitNum as integer)
  set sText to “/usr/local/bin/jp2a -f –html-raw –colors –width=” & (digitNum as string) & ” -i “ & quoted form of POSIX path of anImageAlias
  
set tRes to do shell script sText
  
return tRes
end jpegToAsciiArt

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(aFileName, targFol, aStyledString)
  set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to current application’s NSDictionary’s dictionaryWithObject:“NSRTFTextDocumentType” forKey:(current application’s NSDocumentTypeDocumentAttribute)
  
set bRTF to aStyledString’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict
  
  
set theName to current application’s NSString’s stringWithString:aFileName
  
set theName to theName’s stringByReplacingOccurrencesOfString:“/” withString:“_”
  
set theName to theName’s stringByReplacingOccurrencesOfString:“:” withString:“_”
  
set thePath to current application’s NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“rtf”
  
  
return (bRTF’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsRTF

★Click Here to Open This Script 

2017/07/21 指定のPNG画像をASCII ART化してTextEditでオープン v2

jp2aを利用して指定のPNG画像を色付きHTML形式のアスキーアート化して出力し、HTMLをRTFに変換してTextEditでオープンしてフォントを変更するAppleScriptです。

指定のJPEG画像をアスキーアート化するjp2aは、Homebrew経由でインストールしてください。

asciiart4_resized.png

asciiart3_resized.png
▲このように縦長で余白の多い画像から、自動で余白部分をトリミングして処理

asciiart_z.png
▲左側はPNG画像の余白トリミング処理を行ったもの、右側はトリミング処理を行わなかったもの

アスキーアート化するにあたって、元画像の余白部分をトリミングできたほうが良好な結果が得られるため、処理対象をJPEG画像からPNG画像(背景透過)に変更し、以前に使った画像余白トリミングフレームワーク「KGPixelBoundsClipKit」を用いてトリミングしてJPEG画像に変換。

トリミングしたJPEG画像をjp2aでHTMLのアスキーアートに変換し、さらにHTMLをスタイル付きテキスト(NSAttributedString)に変換。

スタイル付きテキストをRTF(リッチテキストフォーマット)に変換してファイル出力。RTFになればTextEditで扱えるので、TextEditでオープンして本文のフォントを等幅フォント(Osaka-mono)に指定してウィンドウのサイズを変更しています。

テストする際には、KGPixelBoundsClipKitフレームワークのバイナリを~/Library/Frameworksフォルダに入れてお試しください。

–> Download Framework Binary

AppleScript名:指定のPNG画像をASCII ART化してTextEditでオープン v2
– Created 2017-07-21 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “KGPixelBoundsClipKit” –https://github.com/kgn/KGPixelBoundsClip
–http://piyocast.com/as/archives/4736

set aFile to choose file of type {“public.png”}

–PNG画像の余白をトリミング
set anImage to (current application’s NSImage’s alloc()’s initWithContentsOfFile:(POSIX path of aFile))
set bImage to anImage’s imageClippedToPixelBounds()

–トリミング結果をデスクトップにJPEG形式で保存
set aDesktopPath to (current application’s NSProcessInfo’s processInfo()’s environment()’s objectForKey:(“HOME”))’s stringByAppendingString:“/Desktop/”
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.jpg”)
set fRes to saveNSImageAtPathAsJPG(bImage, savePath, 100) of me

–ASCII ARTに変換してHTMLとして出力
set anAlias to (POSIX file (savePath as string)) as alias
set htmlRes to jpegToAsciiArt(anAlias, 120) of me

–出力されたHTMLデータを評価してスタイル付きテキストに変換
set htmlData to current application’s NSString’s stringWithString:htmlRes
set keyList to {current application’s NSDocumentTypeDocumentAttribute, current application’s NSCharacterEncodingDocumentAttribute}
set valList to {current application’s NSHTMLTextDocumentType, current application’s NSUTF8StringEncoding}
set optDict to current application’s NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
set aStyledStr to current application’s NSAttributedString’s alloc()’s initWithData:(htmlData’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)) options:optDict documentAttributes:(missing value) |error|:(missing value)

–スタイル付きテキストをRTFとしてデスクトップに保存
set targFol to POSIX path of (path to desktop)
set aUUID to current application’s NSUUID’s UUID()’s UUIDString() as text
set bRes to my saveStyledTextAsRTF(aUUID, targFol, aStyledStr) –PDFで書き出す
set newPath to targFol & aUUID & “.rtf”

–保存したRTFをTextEditでオープンして等幅フォント設定して、Window横幅を変更
tell application “TextEdit”
  activate
  
open (POSIX file newPath) as alias
  
  
tell text of document 1
    set font of every attribute run to “Osaka-Mono”
  end tell
  
  
tell window 1
    set {x1, y1, x2, y2} to bounds
    
set bounds to {x1, y1, (x1 + 800), y2}
  end tell
end tell

–NSImageを指定パスにJPEG形式で保存
on saveNSImageAtPathAsJPG(anImage, outPath, qulityNum as real)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSJPEGFileType) |properties|:{NSImageCompressionFactor:qulityNum})
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –true/false
end saveNSImageAtPathAsJPG

–与えられたファイルパスのJPEG画像をASCII ARTに変換して返す
on jpegToAsciiArt(anImageAlias, digitNum as integer)
  set sText to “/usr/local/bin/jp2a -f –html-raw –colors –width=” & (digitNum as string) & ” -i “ & quoted form of POSIX path of anImageAlias
  
set tRes to do shell script sText
  
return tRes
end jpegToAsciiArt

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(aFileName, targFol, aStyledString)
  –Convert NSMutableStyledStrings to RTF
  
set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to current application’s NSDictionary’s dictionaryWithObject:“NSRTFTextDocumentType” forKey:(current application’s NSDocumentTypeDocumentAttribute)
  
set bRTF to aStyledString’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict
  
  
– build path based on title
  
set theName to current application’s NSString’s stringWithString:aFileName
  
set theName to theName’s stringByReplacingOccurrencesOfString:“/” withString:“_”
  
set theName to theName’s stringByReplacingOccurrencesOfString:“:” withString:“_”
  
set thePath to current application’s NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“rtf”
  
  
return (bRTF’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsRTF

★Click Here to Open This Script 

2017/04/15 リストをクラス名でフィルタする v2

リストをクラス名でフィルタするAppleScriptです。指定クラスに合致するデータをリスト中から抽出します。

修正:listに対して簡単に直接フィルターする方法については別途記述しておきます。本Scriptは他の用途に転用するような場合の記述例として掲載しておきます

NSArrayに入れてNSPredicateで抽出を行う方法があります。ただし、これだとクラス名がCocoaとAppleScriptで合わないので、いまひとつ使えません。

そこで、ひたすら原始的ではありますが、リストをループで回してクラス名を照合して別リストに追加、という処理を回してみました。超高級言語のAppleScriptですが、たまーにこういう泥くさいチェック処理を書く瞬間があります。

そのままだと知性のカケラもなんにもないので、せめてクラス名の同義語辞書を定義して、クラス名の表記ゆらぎ(というよりも、クラス間の内包関係。integerとrealはnumberに含まれるなど)に対応させてみました。

AppleScript名:リストをクラス名でフィルタする v2
– Created 2017-04-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aList to {1, “ABC”, 0.3, 5, {1, 2, 3}, {abc:“record”}, false}
set bList to filterListByClass(aList, “integer”)
–> {1, 5}
set cList to filterListByClass(aList, “number”)
–> {1, 0.3, 5}
set dList to filterListByClass(aList, “real”)
–> {0.3}
set eList to filterListByClass(aList, “string”)
–> {”ABC”}
set fList to filterListByClass(aList, “record”)
–> {{abc:”record”}}
set gList to filterListByClass(aList, “boolean”)
–> {false}

on filterListByClass(aList as list, aClass as string)
  set classNameList to getClassNameConsideringSynonyms(aClass) of me
  
  
set newList to {}
  
repeat with i in aList
    set j to contents of i
    
set myClass to (class of j) as string
    
if myClass is in classNameList then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterListByClass

on getClassNameConsideringSynonyms(aClassString)
  set smallClass to ((current application’s NSString’s stringWithString:aClassString)’s lowercaseString()) as string
  
set classRec to {|list|:{“list”}, |record|:{“record”}, |number|:{“number”, “integer”, “real”}, |integer|:{“integer”}, |real|:{“real”}, |text|:{“text”, “string”, “unicode text”}, |string|:{“text”, “string”, “unicode text”}, |unicode text|:{“text”, “string”, “unicode text”}, |boolean|:{“boolean”}}
  
set classDict to current application’s NSDictionary’s dictionaryWithDictionary:classRec
  
set aVal to (classDict’s valueForKey:smallClass) as list
  
if aVal = {missing value} then error “Unexpected class name string”
  
return aVal
end getClassNameConsideringSynonyms

★Click Here to Open This Script 

2017/01/07 iTunesライブラリの曲のアーティスト名を集計

iTunesライブラリ中に入っている「曲」(song)のアーティスト名を集計するAppleScriptです。

iTunesLibraryフレームワークを用いてライブラリにアクセスしているので、iTunes.appが起動している必要はありません。

アーティスト名については、ライブラリ中にかなりイレギュラーなデータが存在しているため、対策が必要でした。

・初期のiTunesで、CDからリッピングしたものの、CDDBに登録がなかったため、アーティスト名などが登録されていない→ エラートラップで対処

・アーティスト名で姓(last name)と名(first name)の間に空白が入っていたりいなかったりするなど、表記ゆらぎが存在していたため、ゆらぎを吸収

もう少し高速に実行できてもよさそうですが、ライブラリ中のtrackが8,100程度のときに、10回実行時の平均は2.8秒程度です(MacBook Pro Retina 2012)。

AppleScript名:iTunesライブラリの曲のアーティスト名を集計
– Created 2017-01-07 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “iTunesLibrary”
–http://piyocast.com/as/archives/4379

set library to current application’s ITLibrary’s libraryWithAPIVersion:“1.0″ |error|:(missing value)
if library is equal to missing value then return

set allTracks to library’s allMediaItems()
set allCount to allTracks’s |count|()

set anEnu to allTracks’s objectEnumerator()
set newArray to current application’s NSMutableArray’s alloc()’s init()

repeat
  set aPL to anEnu’s nextObject()
  
if aPL = missing value then exit repeat
  
try
    set aKind to (aPL’s mediaKind) as integer
    
    
if (aKind as integer) is equal to 2 then –Music, Song
      set plName to aPL’s artist’s |name| as string
      
set pl2Name to (my changeThis:” “ toThat:“” inString:plName) –日本語アーティスト名で姓と名の間にスペースが入っているものがある(表記ゆらぎ)ので対策
      
newArray’s addObject:(pl2Name)
    end if
  on error
    set aLoc to (aPL’s location’s |path|()) as string
    
log aLoc
  end try
end repeat

set aRes to countItemsByItsAppearance(newArray) of me
–>  {{theName:”浜田省吾”, numberOfTimes:442}, {theName:”B’z”, numberOfTimes:379}, {theName:”渡辺岳夫・松山祐士”, numberOfTimes:199}, {theName:”VariousArtists”, numberOfTimes:192}, {theName:”菅野よう子”, numberOfTimes:108}, {theName:”布袋寅泰”, numberOfTimes:100}, {theName:”三枝成彰”, numberOfTimes:95}, {theName:”宇多田ヒカル”, numberOfTimes:94}, {theName:”宮川泰”, numberOfTimes:81}, {theName:”MichaelJackson”, numberOfTimes:78}, {theName:”稲葉浩志”, numberOfTimes:73}, …

–出現回数で集計
on countItemsByItsAppearance(aList)
  set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bArray to current application’s NSMutableArray’s array()
  
set theEnumerator to aSet’s objectEnumerator()
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
bArray’s addObject:(current application’s NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{“theName”, “numberOfTimes”})
  end repeat
  
  
–出現回数(numberOfTimes)で降順ソート
  
set theDesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:“numberOfTimes” ascending:false
  
bArray’s sortUsingDescriptors:{theDesc}
  
  
return bArray as list
end countItemsByItsAppearance

on changeThis:findString toThat:repString inString:someText
  set theString to current application’s NSString’s stringWithString:someText
  
set theString to theString’s stringByReplacingOccurrencesOfString:findString withString:repString options:(current application’s NSRegularExpressionSearch) range:{location:0, |length|:length of someText}
  
return theString as text
end changeThis:toThat:inString:

★Click Here to Open This Script 

2016/12/17 ネットワークデバイスからactiveなものだけをピックアップする

ネットワークデバイスから、activeなものだけをピックアップするAppleScriptです。

DHCPのネットワークアドレスのリフレッシュを試みたときに、接続中のネットワークデバイス名が必要になるので、試しに作ってみました。

試作品レベルなので、実用性についてはいろいろ問題があります。

まず、ネットワーク接続が切れているとまともに動かないので、ネットワーク接続確認は別途行なっておく必要があります。

さらに、複数のネットワークインタフェース(USB-Ethernetアダプタと本体内蔵WiFiとか)がアクティブになっている場合の結果が正しいことは保証しません(まだ、このあたりの詰めが必要)。

本プログラムでは、複数返ってきた場合には最初の項目を返してくるので、自分のマシン環境でも「これはいかがなものか」という状態です(USB-Ethernetアダプタで有線接続しつつ、位置情報を取得するためにWiFiをオンにすることがあるので)。

正規表現の鬼のような人だと、もう少し美しく短いプログラムにまとめられると思います。自分が短く書くために選んだ道具はtext item delimiters。

text item delimitersに複数(2よりも多い複数)の項目を指定できるので、あらかじめ各デバイス情報の1行目だけをピックアップしておき、これをtext item delimitersに指定してifconfigの処理結果をリスト化し、欠けた各デバイス情報の1行目を順次補っていくという、かなり頭のおかしなプログラムです。

AppleScript名:ネットワークデバイスからactiveなものだけをピックアップする
– Created 2016-12-17 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4367

set aDevRes to getActiveNetworkInterfaceDeviceName() of me
set aDevName to devName of aDevRes
–>  ”en3″

–ifconfigからactiveなデバイス名だけをピックアップする
on getActiveNetworkInterfaceDeviceName()
  set aRes to (do shell script “ifconfig”)
  
set aList to paragraphs of aRes
  
  
set devNameList to {}
  
repeat with i in aList
    set j to contents of i
    
set bRes to regexMatches(j, “^[^\\t]*”) of me
    
if bRes is not equal to {{“”}} then
      set the end of devNameList to contents of item 1 of item 1 of bRes
    end if
  end repeat
  
  
–Parse ifconfig results by device name list
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to devNameList –かなりトリッキー
  
set tmpList to text items of aRes
  
set AppleScript’s text item delimiters to curDelim
  
  
–initialize
  
set bList to rest of tmpList –remove blank item at top
  
set aCount to 1
  
set aResList to current application’s NSMutableArray’s alloc()’s init()
  
  
repeat with i in bList
    set aCon to contents of i
    
set aDat to contents of item aCount of devNameList
    
–Device Name
    
set aDevName to retStrFromTopToAstr(aDat, “:”) of me
    
    
set bCon to paragraphs 2 thru -1 of aCon
    
set cCon to aDat & retDelimedText(bCon, return) of me
    
    
–Activeなdeviceを抽出するための条件付け
    
set activeF1 to cCon contains “status: active”
    
set activeF2 to cCon does not contain “media: autoselect (<unknown type>)”
    
    
set aRec to (current application’s NSDictionary’s dictionaryWithDictionary:{devName:aDevName, isActive:(activeF1 and activeF2), ifconfigRes:cCon})
    (
aResList’s addObject:aRec)
    
set aCount to aCount + 1
  end repeat
  
  
set activeIF to filterRecListByLabel(aResList, “isActive == [c]%@”, {true}) of me
  
(*
  {{devName:”en3″, ifconfigRes:”en3: flags=8863 mtu 1500\toptions=4\r\tether XX:Xx:xX:Xx:XX:xX \r\tinet6 xxXX::XxX:XXXX:XXXx:Xxxx%en3 prefixlen 64 secured scopeid 0×4 \r\tinet 192.168.0.5 netmask 0xffffff00 broadcast 192.168.0.255\r\tinet6 XXXx:XX:XXxX:X:xxX:XXXX:XXXx:XXxX prefixlen 64 autoconf secured \r\tinet6 XXXx:XX:XXxX:X:XXx:XXXX:XXXx:xXXx prefixlen 64 autoconf temporary \r\tnd6 options=201 \r\tmedia: autoselect (100baseTX )\r\tstatus: active”, isActive:true}}
*)
  return first item of activeIF –Multiple Device Name list may return. Now, I choose one.
end getActiveNetworkInterfaceDeviceName

–http://qiita.com/szk-3/items/8bbe841eb0295caee6b0
on regexMatches(aText as text, pattern as text)
  set regularExpression to current application’s NSRegularExpression’s regularExpressionWithPattern:pattern options:0 |error|:(missing value)
  
set aString to current application’s NSString’s stringWithString:aText
  
set matches to regularExpression’s matchesInString:aString options:0 range:{location:0, |length|:aString’s |length|()}
  
set matchResultList to {}
  
repeat with match in matches
    set mRes to {}
    
repeat with i from 0 to (match’s numberOfRanges as integer) - 1
      set end of mRes to (aString’s substringWithRange:(match’s rangeAtIndex:i)) as text
    end repeat
    
set end of matchResultList to mRes
  end repeat
  
return matchResultList
end regexMatches

–リストを指定デリミタを入れつつテキスト化
on retDelimedText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retDelimedText

–先頭から指定キャラクタまでを抽出して返す
on retStrFromTopToAstr(aStr, aTarg)
  set aLen to length of aTarg
  
set anOffset to offset of aTarg in aStr
  
set bStr to text 1 thru (anOffset - aLen) of aStr
  
return bStr
end retStrFromTopToAstr

–リストに入れたレコードを、指定の属性ラベルの値で抽出(predicateとパラメータを分離)
on filterRecListByLabel(aRecList, aPredicate, aParam)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate argumentArray:aParam
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
set bList to filteredArray as list
  
return bList
end filterRecListByLabel

★Click Here to Open This Script 

2016/12/14 レコードのうち、最大の値を持つKeyを返す

レコードのうち、最大の値を持つキーを返すAppleScriptです。

AppleScriptからMicrosoftの表情認識APIを呼び出せるようになったはいいものの、得られたデータからどの表情の可能性が高いかを判定する必要があり、そのために書いてみたものです。

Cocoaの機能を用いて、レコードのキーを取り出したり、さまざまな処理を行っています。こうした処理が手軽にできるようになったのは、実にいいことです。

さらに、画像から顔認識を行い、表情を読み取ってデータ化できるというのは、実に素晴らしいと思うものです。

ただ、いろいろ実験を行ってみたところ・・・恐れとか悲しみとか軽蔑といった微妙な感情については検出しづらいことがわかってきました。最大の値のものをピックアップするという方法ではなく、微妙な感情については別途評価を行う必要がありそうです。

mona_lisa_by_leonardo_da_vinci_from_c2rmf_retouched-1.jpg
–> “neutral”

donaldtrump61815_resized.png
–> “anger”

AppleScript名:レコードのうち、最大の値を持つKeyを返す
– Created 2016-12-14 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4359

set aDict to current application’s NSDictionary’s dictionaryWithDictionary:{sadness:0.01133416, anger:1.03975857E-4, happiness:2.90919736E-4, fear:2.28432211E-4, neutral:0.9830475, contempt:2.4698046E-4, disgust:1.02946949E-4, surprise:0.00464509334}
set aMacKey to retMaxValueKey(aDict) of me
–>  ”neutral”

on retMaxValueKey(aDict)
  set aValList to aDict’s allValues()
  
set maxVal to (sort1DNumList(aValList, false) of me)’s firstObject()
  
set keyList to (aDict’s allKeys()) as list
  
  
repeat with i in keyList
    set j to contents of i
    
set aTmp to (aDict’s valueForKey:j)
    
set aRes to compareNumerically(maxVal, aTmp) of me
    
if aRes = true then return j
  end repeat
  
  
return false
end retMaxValueKey

–Numerical Strings Compare
on compareNumerically(aText as text, bText as text)
  set aStr to current application’s NSString’s stringWithString:aText
  
return (aStr’s compare:bText options:(current application’s NSNumericSearch)) = current application’s NSOrderedSame
end compareNumerically

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

★Click Here to Open This Script 

2016/12/13 顔認識結果のデータを加工

Microsoftの顔認識APIを呼び出して、その結果を加工して表情認識APIを呼び出すために、顔認識APIの実行結果を加工するAppleScriptです。

まだ表情認識APIは呼び出せていませんが、その途中で作ったものです。

典型的なデータ加工の処理なので、ほかにも(もう少しうまい)やり方がありそうです。

AppleScript名:顔認識結果のデータを加工
– Created 2016-12-13 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4357

set aList to current application’s NSArray’s arrayWithArray:{{faceId:"c49883a0-c4ee-4671-ad06-6f7f8370ab20", faceRectangle:{top:68, width:40, |left|:336, height:40}}, {faceId:"93459b48-4c19-4cc7-85e6-b38b8d0fc73b", faceRectangle:{top:81, width:38, |left|:92, height:38}}, {faceId:"9c796619-c654-47dd-b7b0-c382dc6bda84", faceRectangle:{top:63, width:38, |left|:214, height:38}}, {faceId:"94a2ceec-c089-494c-982e-a213579342b6", faceRectangle:{top:92, width:38, |left|:462, height:38}}, {faceId:"18e8dad0-fe46-4c5c-81c3-3ba483129512", faceRectangle:{top:89, width:37, |left|:700, height:37}}, {faceId:"4031f4bd-4e47-4050-89a0-f66e2e4e9142", faceRectangle:{top:45, width:37, |left|:570, height:37}}}

set aRes to retFaceArray(aList) of me
–>  "336,68,40,40;92,81,38,38;214,63,38,38;462,92,38,38;700,89,37,37;570,45,37,37"

on retFaceArray(aList)
  set a1Res to (aList’s valueForKeyPath:"faceRectangle.top") as list
  
set a2Res to (aList’s valueForKeyPath:"faceRectangle.width") as list
  
set a3Res to (aList’s valueForKeyPath:"faceRectangle.left") as list
  
set a4Res to (aList’s valueForKeyPath:"faceRectangle.height") as list
  
  
set aLen to length of a1Res
  
set aRes to {}
  
  
repeat with i from 1 to aLen
    set aLeft to (contents of item i of a3Res) as string
    
set aTop to (contents of item i of a1Res) as string
    
set aWidth to (contents of item i of a2Res) as string
    
set aHeight to (contents of item i of a4Res) as string
    
set tmpRes to aLeft & "," & aTop & "," & aWidth & "," & aHeight
    
set the end of aRes to tmpRes
  end repeat
  
  
set allRes to retStrFromArrayWithDelimiter(aRes, ";") of me
  
  
return allRes
end retFaceArray

–リストを指定デリミタをはさんでテキスト化
on retStrFromArrayWithDelimiter(aList, aDelim)
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set aRes to anArray’s componentsJoinedByString:aDelim
  
return aRes as text
end retStrFromArrayWithDelimiter

★Click Here to Open This Script 

2016/11/05 XMLをNSDictionaryに

オープンソースのXMLDictionary(By Nick Lockwood)をFramework化した「XmlToDictKit」を呼び出して、XMLをNSDictionaryにするAppleScriptです。

XMLをNSDictionaryにするのには、なかなか手こずらされており、依然としてSatimageのXMLLib OSAXが手放せない状況ですが、OSAXを使わずになんとかする方法についてはつねに模索しておりました。

「XML Parser」などをキーワードにGithub上でいろいろ物色していたところ、そんなに気合の入ったキーワードでなくても、「XML NSDictionary」ぐらいでいろいろ見つかりました。

それらを人気順でソートし上から順番に物色。条件が合って手軽にフレームワーク化に成功したのがこの「XMLDictionary」です。

XMLをNSDictionaryに変換し、さらにNSDictionaryをrecordまで変換すればAppleScriptで簡単に取り扱えます(NSDictionaryの属性値ラベルに空白などが入っていなければ)。

フレームワークについては、例によってOS X 10.10をターゲットにしてビルドしてみました。~/Library/Frameworksに入れてご利用ください(あくまで自己責任で)。

XMLそのものよりも、RSSのParseが割と手間だったので、RSSを手軽に扱えるようになったことのメリットが大きいと感じています。

→ FrameworkのZipアーカイブのダウンロード(30KB)

AppleScript名:XMLをDictionaryに(remote file)
– Created 2016-11-05 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “XmlToDictKit” –https://github.com/nicklockwood/XMLDictionary
–http://piyocast.com/as/archives/4304

set aURL to current application’s |NSURL|’s alloc()’s initWithString:“http://www.ibiblio.org/xml/examples/shakespeare/all_well.xml”
set xmlString to current application’s NSString’s alloc()’s initWithContentsOfURL:aURL encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)
if xmlString = missing value then return false
set xmlDoc to (current application’s NSDictionary’s dictionaryWithXMLString:xmlString) as record

★Click Here to Open This Script 

AppleScript名:XMLをDictionaryに(local file)
– Created 2016-11-05 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “XmlToDictKit” –https://github.com/nicklockwood/XMLDictionary
–http://piyocast.com/as/archives/4304

set aFile to POSIX path of (choose file)
set aURL to current application’s |NSURL|’s fileURLWithPath:aFile
set xmlString to current application’s NSString’s alloc()’s initWithContentsOfURL:aURL encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)
if xmlString = missing value then return false
set xmlDoc to (current application’s NSDictionary’s dictionaryWithXMLString:xmlString) as record

★Click Here to Open This Script 

AppleScript名:RSSをDictionaryに(remote file)
– Created 2016-11-05 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “XmlToDictKit” –https://github.com/nicklockwood/XMLDictionary
–http://piyocast.com/as/archives/4304

set aURL to current application’s |NSURL|’s alloc()’s initWithString:“http://piyocast.com/as/feed”
set xmlString to current application’s NSString’s alloc()’s initWithContentsOfURL:aURL encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)
if xmlString = missing value then return false
set xmlDoc to (current application’s NSDictionary’s dictionaryWithXMLString:xmlString) as record
set aChannel to |item| of channel of xmlDoc
set aDoc1 to first item of aChannel
–>  {category:{”Application Control”, “10.10 savvy”, “10.11 savvy”, “10.12 savvy”}, dc:creator:”maro”, comments:”http://piyocast.com/as/archives/4304#comments”, title:”XMLをNSDictionaryに”, link:”http://piyocast.com/as/archives/4304″, pubDate:”Sat, 05 Nov 2016 21:21:17 +0900″, description:”オープンソースのXMLDictionary(By Nick Lockwood)をFramework化した「XmlToDictKit」を呼び出して、XMLをNSDictionaryにするAppleScr…”, guid:{__text:”http://piyocast.com/as/archives/4304″, _isPermaLink:”false”}, wfw:commentRss:”http://piyocast.com/as/archives/4304/feed/”}

★Click Here to Open This Script 

2016/11/02 iTunesライブラリ中の楽曲のジャンルを集計して多い順にソートして出力

iTunesライブラリ中の楽曲のジャンルを集計して多い順にソートして返すAppleScriptです。

集計部分をCocoaで行っているので、集計部分自体が相当に高速なのですが、手元のMacBook Pro Retina 2012(Core i7 2.6GHz)で音声データが6,861件iTunesに登録されている環境で処理したところ、

  アプリケーション(iTunes)を直接呼び出し:3.5秒
  すべてフレームワーク経由で処理:0.03秒

と、アプリケーションを直接操作しないでフレームワーク経由で楽曲の情報を取得して処理するとアプリケーションへの問い合わせを行うよりも100倍以上高速です。

iTunes Music Library.xmlを読み取って処理してもだいたいフレームワーク経由の処理と同じかやや高速なぐらいに落ち着くと思われます。
補足:XML経由の処理はAppleScriptだと(Cocoaの機能を使っても)ムチャクチャ時間がかかりました。参考までに

ただ、処理結果が方法によってほんの微妙に変わるのはジャンル判定処理が異なるためでしょうか。やや、気になります。

GUIアプリ経由で情報を取得するのと、フレームワークを呼び出して情報を取得するのと、XMLを自力で解析するのとでは、提供してくれる機能が違うので、用途に応じて適切なものを取捨選択することになります。「現在再生中の曲」「曲リスト中で選択中のもの」といった情報が必要な場合にはGUIアプリ(iTunes)に問い合わせるのが正解です。

AppleScript名:iTunesライブラリ中の楽曲のジャンルを集計して多い順にソートして出力(アプリケーション呼び出し)
– Created 2016-10-30 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4301

tell application “iTunes”
  –set aList to genre of (every file track whose media kind is equal to song and genre is not equal to “”)
  
set aList to genre of every file track
end tell

set aRes to countItemsByItsAppearance(aList) of me
return aRes
–> {{theName:”サウンドトラック”, numberOfTimes:1721}, {theName:”ロック”, numberOfTimes:942}, {theName:”クラシック”, numberOfTimes:539},

–ジャンルのリストを出現回数で集計
on countItemsByItsAppearance(aList)
  set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bArray to current application’s NSMutableArray’s array()
  
set theEnumerator to aSet’s objectEnumerator()
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
bArray’s addObject:(current application’s NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{“theName”, “numberOfTimes”})
  end repeat
  
  
–出現回数(numberOfTimes)で降順ソート
  
set theDesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:“numberOfTimes” ascending:false
  
bArray’s sortUsingDescriptors:{theDesc}
  
  
return bArray as list
end countItemsByItsAppearance

★Click Here to Open This Script 

AppleScript名:iTunesライブラリ中の楽曲のジャンルを集計して多い順にソートして出力(フレームワーク呼び出し)
– Created 2016-11-02 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “iTunesLibrary”
–http://piyocast.com/as/archives/4301

set library to current application’s ITLibrary’s libraryWithAPIVersion:“1.0″ |error|:(missing value)
if library is equal to missing value then return

set playLists to library’s allPlaylists()
set gArray to library’s allMediaItems()’s genre
set aRes to countItemsByItsAppearance(gArray) of me
–> {{theName:”サウンドトラック”, numberOfTimes:1722}, {theName:”ロック”, numberOfTimes:956}, {theName:”Podcast”, numberOfTimes:755},

–ジャンルのリストを出現回数で集計
on countItemsByItsAppearance(aList)
  set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bArray to current application’s NSMutableArray’s array()
  
set theEnumerator to aSet’s objectEnumerator()
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
bArray’s addObject:(current application’s NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{“theName”, “numberOfTimes”})
  end repeat
  
  
–出現回数(numberOfTimes)で降順ソート
  
set theDesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:“numberOfTimes” ascending:false
  
bArray’s sortUsingDescriptors:{theDesc}
  
  
return bArray as list
end countItemsByItsAppearance

★Click Here to Open This Script 

2016/10/27 感情推定【極性判定】

Apitore「感情推定」APIを呼び出して、指定の日本語の文章がPositive(肯定的)かNegative(否定的)かを判定するAppleScriptです。

実行前にapitoreにユーザー登録を行い(無料)、Web上でアクセストークンを取得。そのトークンをretAccessToken()内で返すように書いておく必要があります(掲載のリストのまま実行すると、エラーになります。かならずアクセストークンを取得してください)。

用途は割といろいろあって、ちょっと考えただけでも、

「メールの文面をチェックして、日本語であれば(NSLinguisticTaggerを使って判定)感情推定APIを呼び出し、Negativeと判定されたらメールの一覧に赤く色をつける」

とかいうAppleScriptはかんたんに書けますし、便利だと思います(色付きメールを読みたくなくなる、とかいう心理的なフィードバックが発生することについてはさておき)。

また、

Safariの閲覧履歴を取得して、各URLにアクセスして本文のみ取得。読んだ内容がPositveかNegativeかの内訳をグラフで表示」

とかいうのも面白そうです。

テストしてみたところ、たまたまサーバー側で問題を起こしていた最中のようで、サンプルプログラム中に記述してある「かならずPositive(肯定的)と判定される例文」がNegative(否定的)と出てきて焦りましたが、じきに安定することでしょう。

AppleScript名:感情推定【極性判定】
– Created 2016-10-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4289

set aText to "おめでとう!カブスが4勝2敗でドジャースを下し、2016年ナ・リーグの覇者に!次は水曜日(10月26日)に行われるワールドシリーズでア・リーグの覇者インディアンスと対決!"

set reqURLStr to "https://api.apitore.com/api/11/sentiment/predict"
set accessToken to retAccessToken() —Access Token
set aRec to {access_token:accessToken, |text|:aText}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–>  {endTime:"1477617363491", processTime:"44", text:"おめでとう!カブスが4勝2敗でドジャースを下し、2016年ナ・リーグの覇者に!次は水曜日(10月26日)に行われるワールドシリーズでア・リーグの覇者インディアンスと対決!", log:"Success.", predict:{score:0.520746946335, sentiment:"positive"}, startTime:"1477617363447", sentimens:{{score:0.520746946335, sentiment:"positive"}, {score:0.479253053665, sentiment:"negative"}}}

–set aRESCode to (responseCode of aRes) as integer
–>  200

–set aRESHeader to (responseHeader of aRes) as record
–>  {Content-Type:"application/json;charset=UTF-8", Access-Control-Allow-Origin:"*", Pragma:"no-cache", X-XSS-Protection:"1; mode=block, 1; mode=block", Server:"nginx/1.10.1", Transfer-Encoding:"Identity", Expires:"0", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Date:"Thu, 27 Oct 2016 03:22:11 GMT", Strict-Transport-Security:"max-age=31536000; includeSubDomains;", Connection:"keep-alive", X-Content-Type-Options:"nosniff, nosniff", X-Frame-Options:"DENY, SAMEORIGIN"}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:"application/json" forHTTPHeaderField:"Accept"
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

on retAccessToken()
  return "xxxXxxXx-XXXX-XXXX-XxXX-XXxXXxxXXxxx" –API Tore Access Token
end retAccessToken

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

★Click Here to Open This Script 

2016/10/10 URLにリソースが存在するかチェック v2

指定したURLにリソース(ファイル)が存在するかを確認するAppleScriptです。

Webサーバーなどのリモート環境を指しているURLをファイル名までフルに記述して、画像ファイルなどの存在確認を行います。

ただし、「存在確認だけ」を行うことができないようで、確認すると実際にデータも取得できてしまいます。

本来なら、このような処理は並列で同時に行いたいところ。強制的に並列化するツールも作って実験していますが、同時に大量のURLの存在確認を行うような処理はとてもありえそうです。

ただ、shell commandで行なっても割と手軽にできそうで、Cocoaのサービスを呼び出すのか、実際に処理速度を計測して選択したいところです。

AppleScript名:URLにリソースが存在するかチェック v2
– Created 2016-10-10 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4254

set aStr to “http://piyocast.com/as/wp-content/uploads/2016/10/xfinder2.jpg.pagespeed.ic.jFDNAr4CuI.jpg”

set aURL to (current application’s |NSURL|’s URLWithString:aStr)
set {exRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me

exRes
–> true / false

headerRes
–> (NSDictionary) {Connection:”Keep-Alive”, Content-Type:”image/jpeg”, Server:”Apache”, Last-Modified:”Mon, 10 Oct 2016 03:43:53 GMT”, Expires:”Tue, 10 Oct 2017 03:43:53 GMT”, Cache-Control:”max-age=31536000″, Accept-Ranges:”bytes”, Date:”Mon, 10 Oct 2016 05:24:38 GMT”, Keep-Alive:”timeout=1, max=100″, Content-Length:”4383″, Etag:”W/”0″”}

aData
–> (NSData)

set conType to (headerRes’s valueForKey:“Content-Type”) as string
–>  ”image/jpeg”

set modDate to (headerRes’s valueForKey:“Last-Modified”) as string
–>  ”Mon, 10 Oct 2016 03:43:53 GMT”

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
set hRes to (bRes’s allHeaderFields())
  
set aResCode to (bRes’s statusCode()) as integer
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

★Click Here to Open This Script 

2016/06/30 recordのlistでKeynoteに表を作成する v1.5

recordのlistでKeynote v6.6.2のドキュメント上に表を作成するAppleScriptの高速化改良版です。

Keynote v6.6.xでtable(表)を作成するのに、セルに値が入った状態で作成できないかと試してみましたが、ダメでした(T_T)

そこで、アプリケーションに対しての操作を高速化させるため、非同期実行モードでセルへの値の設定とフォントサイズの変更を行ってみました。だいたいこれで2倍速ぐらいです。

keynote0.png

keynotes2.png

AppleScript名:recordのlistでKeynoteに表を作成する v1.5
– Created 2016-06-29 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

property aFontSize : 12

set aList to {{pathStr:“book1_0.1.pdf”, creationDate:“2016年6月17日金曜日”, pageCount:222, countChars:127978, fileSize:“12027660″}, {pathStr:“book1_0.2.pdf”, creationDate:“2016年6月17日金曜日”, pageCount:230, countChars:129506, fileSize:“11109818″}, {pathStr:“book1_0.210.pdf”, creationDate:“2016年6月18日土曜日”, pageCount:254, countChars:147119, fileSize:“22832000″}, {pathStr:“book1_0.211.pdf”, creationDate:“2016年6月18日土曜日”, pageCount:254, countChars:147123, fileSize:“22831931″}, {pathStr:“book1_0.212.pdf”, creationDate:“2016年6月18日土曜日”, pageCount:241, countChars:134856, fileSize:“22273252″}, {pathStr:“book1_0.213.pdf”, creationDate:“2016年6月18日土曜日”, pageCount:241, countChars:134845, fileSize:“22271667″}, {pathStr:“book1_0.214.pdf”, creationDate:“2016年6月18日土曜日”, pageCount:241, countChars:134850, fileSize:“22270980″}, {pathStr:“book1_0.220.pdf”, creationDate:“2016年6月18日土曜日”, pageCount:242, countChars:134870, fileSize:“21098301″}, {pathStr:“book1_0.222.pdf”, creationDate:“2016年6月18日土曜日”, pageCount:243, countChars:135694, fileSize:“21146421″}, {pathStr:“book1_0.300.pdf”, creationDate:“2016年6月20日月曜日”, pageCount:251, countChars:142787, fileSize:“21427502″}, {pathStr:“book1_0.301.pdf”, creationDate:“2016年6月20日月曜日”, pageCount:251, countChars:142784, fileSize:“21421107″}, {pathStr:“book1_0.302.pdf”, creationDate:“2016年6月20日月曜日”, pageCount:256, countChars:142827, fileSize:“22593201″}, {pathStr:“book1_0.303.pdf”, creationDate:“2016年6月20日月曜日”, pageCount:257, countChars:142845, fileSize:“22616595″}, {pathStr:“book1_0.400.pdf”, creationDate:“2016年6月22日水曜日”, pageCount:281, countChars:162419, fileSize:“22430779″}, {pathStr:“book1_0.500.pdf”, creationDate:“2016年6月23日木曜日”, pageCount:309, countChars:178210, fileSize:“27611566″}, {pathStr:“book1_0.600.pdf”, creationDate:“2016年6月24日金曜日”, pageCount:326, countChars:194751, fileSize:“26820825″}, {pathStr:“book1_0.700.pdf”, creationDate:“2016年6月24日金曜日”, pageCount:310, countChars:195943, fileSize:“26408415″}, {pathStr:“book1_0.701.pdf”, creationDate:“2016年6月24日金曜日”, pageCount:310, countChars:195926, fileSize:“26406738″}, {pathStr:“book1_0.702.pdf”, creationDate:“2016年6月24日金曜日”, pageCount:310, countChars:195924, fileSize:“26406703″}, {pathStr:“book1_0.703.pdf”, creationDate:“2016年6月24日金曜日”, pageCount:311, countChars:196594, fileSize:“26416223″}, {pathStr:“book1_1.0.pdf”, creationDate:“2016年6月25日土曜日”, pageCount:311, countChars:196594, fileSize:“26075419″}}

set anItem to contents of first item of aList
set aDict to (current application’s NSMutableArray’s arrayWithObject:anItem)’s firstObject()
set aKeyList to aDict’s allKeys() as list
set aKeyCount to length of aKeyList
set aRowCount to length of aList

tell application “Keynote”
  tell document 1
    set aNewSlide to make new slide
    
    
tell aNewSlide
      set aTable to make new table with properties {column count:aKeyCount + 1, row count:aRowCount + 1}
      
tell aTable
        –ヘッダー行を作成(ラベルで埋める)
        
tell row 1
          repeat with i from 2 to aKeyCount + 1
            set aKey to item (i - 1) of aKeyList
            
–非同期実行ここから
            
ignoring application responses
              set value of cell i to aKey
              
set font size to aFontSize
            end ignoring
            
–非同期実行ここまで
          end repeat
        end tell
        
        
–各行のデータを埋める
        
repeat with ii from 2 to aRowCount + 1
          set aRecRow to item (ii - 1) of aList
          
tell row ii
            repeat with iii from 2 to (aKeyCount + 1)
              tell cell iii
                set aKey to item (iii - 1) of aKeyList
                
–非同期実行ここから
                
ignoring application responses
                  set value to retValueForKey(aRecRow, aKey) of me
                  
set font size to aFontSize
                end ignoring
                
–非同期実行ここまで
              end tell
            end repeat
          end tell
        end repeat
        
      end tell
    end tell
    
  end tell
end tell

on retValueForKey(aRec, aLabel)
  set tmpDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
return (tmpDic’s valueForKey:aLabel) as string
end retValueForKey

★Click Here to Open This Script 

2016/03/17 barCodeKitのじっけん

Oliver Drobnik氏によるオープンソースのフレームワーク「BarCodeKit」を利用してCode39のバーコード画像をデスクトップにPNG形式で出力するAppleScriptです。

あくまで実験レベルなので、オプション指定の内容に間違いが存在している可能性もあります。

BarCodeKitがサポートしているバーコード形式は、

–EAN-13/UPC-A
–EAN-8
–UPC-E
–Codabar
–Code 11
–Code 39 (plain, mod 43, Full ASCII plain and mod 43)
–Code 93 (with mod 47)
–Code 128
–Interleaved 2 of 5
–MSI - Modified Plessey (plain, mod 10, mod 11, mod 1010, mod 1011)
–Standard/Industrial 2 of 5
–Facing Identification Mark (FIM)
–EAN-2 and EAN-5 supplement codes
–ISBN (10 and 13 digits)
–ISMN
–ISSN
–POSTNET

とのことで、一番難易度の低いCode39でテストを行ってみたというところです(チェックサム・ディジットがないので簡単)。

出力した画像をKeynote書類に貼り付けてレーザープリンターで印刷し、バーコードリーダーでスキャンして指定したデータを取得できることを確認しました。

6423b354-4d0f-4307-9ef4-c26dddc7d822.png
▲本AppleScriptで出力したCode39画像

img_3342_resized.png

img_3343_resized.png

screens.png

OS X 10.10以降用にビルドしたフレームワークのバイナリを用意しておきました。興味のある方は自己責任で~/Library/Frameworksフォルダに入れてお試しください。

–> Download Framework Binary

AppleScript名:barCodeKitのじっけん
– Created 2016-03-17 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “QuartzCore”
use framework “barCodeKit”

–Generate Barcode Image (Code 39)
set aBarcode to current application’s BCKCode39Code’s alloc()’s initWithContent:“PIYOMARU” |error|:(missing value)

set aRec to current application’s NSDictionary’s dictionaryWithObjectsAndKeys_(2.0, current application’s BCKCodeDrawingBarScaleOption, false, current application’s BCKCodeDrawingFillEmptyQuietZonesOption, true, current application’s BCKCodeDrawingPrintCaptionOption, false, current application’s BCKCodeDrawingMarkerBarsOverlapCaptionPercentOption, true, current application’s BCKCodeDrawingShowCheckDigitsOption, (current application’s NSColor’s whiteColor()), current application’s BCKCodeDrawingBackgroundColorOption, missing value)

set anNSImage to current application’s NSImage’s imageWithBarCode:aBarcode options:aRec

–Save Barcode Image as PNG
set aDesktopPath to (current application’s NSProcessInfo’s processInfo()’s environment()’s objectForKey:(“HOME”))’s stringByAppendingString:“/Desktop/”
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.png”)
saveNSImageAtPathAsPNG(anNSImage, savePath) of me

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsPNG(anImage, outPath)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes
end saveNSImageAtPathAsPNG

★Click Here to Open This Script 

2016/02/28 Safariの履歴を読んでトップ10をテキストで出力する

SafariのHistory.plistを読み込んで、アクセス回数のトップ10をテキスト出力するAppleScriptです。

Safari 9.1+OS X 10.11環境を前提としています。plistの内容については、Safariのバージョンごとに変更が加わってもおかしくないので、メジャーバージョンアップ時には動作確認する必要があることでしょう。

他のアプリケーションの.plistファイルにアクセスするのはかなり野蛮な処理ですが(Sandbox環境では許可されない)、場合によっては有用なこともあるでしょう。

ちなみに、Scriptの実行例はサブマシン(MacBook Air 2011)で実行したものです。

AppleScript名:Safariの履歴を読んでトップ10をテキストで出力する
– Created 2016-02-27 by Takaaki Naganoya
– Piyomaru Software 2016
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set libPath to (POSIX path of (path to library folder from user domain)) & “Safari/History.plist”
set aRec to retDictFromPlist(libPath) of me
set bRecList to aRec’s valueForKeyPath:“WebHistoryDates”

set bArray to sortRecListByLabel(bRecList, “visitCount”, false) of me
set outStr to “”
set aCount to 0

repeat with i from 0 to 100
  set anItem to (bArray’s objectAtIndex:i)
  
  
set aURL to (anItem’s valueForKeyPath:“”) as string
  
set aTitle to (anItem’s valueForKeyPath:“title”) as string
  
set aDispTItle to (anItem’s valueForKeyPath:“displayTitle”) as string
  
set aVisitCount to (anItem’s valueForKeyPath:“visitCount”) as string
  
set redirectURLs to (anItem’s valueForKeyPath:“redirectURLs”) as list
  
set lastVisitedDate to (anItem’s valueForKeyPath:“lastVisitedDate”) as string
  
  
if aURL does not start with “http://piyocast.com” then –自分のところのサイト関連を除外
    set aStr to ((aCount + 1) as string) & “:(” & (aVisitCount as string) & “)” & aTitle & return
    
set outStr to outStr & aStr
    
    
set aCount to aCount + 1
    
if aCount = 10 then exit repeat
    
  end if
  
  
end repeat

return outStr

(*
–>  ”1:(7657)radiko.jp
2:(608)Apple
3:(416)ソフトバンクWi-Fiスポット
4:(156)公式Apple Store(日本)- iPad Air、MacBook Pro、ほかにもたくさん
5:(125)Yahoo! JAPAN
6:(108)Mac整備済製品 - Apple Store (Japan)
7:(54)Apple-Style \”アップルなBlogをリンク\”
8:(44)PC Watch
9:(31)Facebook
10:(28)アップル - Mac Pro

*)

–Read plist
on retDictFromPlist(aPath as text)
  set thePath to current application’s NSString’s stringWithString:aPath
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theDict to current application’s NSDictionary’s dictionaryWithContentsOfFile:thePath
  
return theDict
end retDictFromPlist

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList, aLabelStr, ascendF)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set sortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF
  
set sortDescArray to current application’s NSArray’s arrayWithObjects:sortDesc
  
set sortedArray to aArray’s sortedArrayUsingDescriptors:sortDescArray
  
return sortedArray
end sortRecListByLabel

★Click Here to Open This Script 

2016/01/08 レコードのリストからラベル値のみ抽出してユニーク化してソート

Cocoaの機能を用いて、レコードのリストからラベル値のみ抽出して、ユニーク化してソートして返すAppleScriptです。

AppleScript名:レコードのリストからラベル値のみ抽出してユニーク化してソート
– Created 2016-01-08 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set aDic to {{field1:"test 10", field2:"test 20"}, {field1:"test 11", field2:"test 21"}, {field1:"test 12", field2:"test 22"}, {field1:"test 13", field2:"test 23"}, {field1:"test 14", field2:"test 24"}, {field1:"test 15", field2:"test 25"}, {field1:"test 16", field2:"test 26"}, {field1:"test 17", field2:"test 27"}, {field1:"test 18", field2:"test 28"}, {field1:"test 19", field2:"test 29"}, {field1:"test 10", field2:"test 20"}, {field1:"test 11", field2:"test 21"}, {field1:"test 12", field2:"test 22"}, {field1:"test 13", field2:"test 23"}, {field1:"test 14", field2:"test 24"}, {field1:"test 15", field2:"test 25"}, {field1:"test 16", field2:"test 26"}, {field1:"test 17", field2:"test 27"}, {field1:"test 18", field2:"test 28"}, {field1:"test 19", field3:"test 29"}}

set theDataSource to current application’s NSMutableArray’s arrayWithArray:aDic
set kList to retEveryKeys(theDataSource) of me
–>  {"field1", "field2", "field3"}

–リストになったRecordのすべてのアイテムのkey値を取得してユニーク化してソートして返す
on retEveryKeys(aDic)
  set aLen to aDic’s |count|()
  
set tmpKeys to {}
  
  
repeat with i from 0 to (aLen - 1)
    set aRec to (aDic’s objectAtIndex:i)
    
set keyList to (aRec’s allKeys()) as list
    
set tmpKeys to tmpKeys & keyList
  end repeat
  
  
set aRes to uniquifyAndSort1DList(tmpKeys, true) of me
  
return aRes
end retEveryKeys

–1D Listをユニーク化してソート
on uniquifyAndSort1DList(theList, aBool as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
set aDdesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"self" ascending:aBool selector:"compare:"
  
set cArray to bArray’s sortedArrayUsingDescriptors:{aDdesc}
  
set bList to cArray as list
  
return bList
end uniquifyAndSort1DList

★Click Here to Open This Script 

2015/09/28 NSPredicateによる正規表現を利用した部分一致抽出

Cocoaの機能を用いて、リストのレコードから正規表現による要素の抽出を行うAppleScriptです。実行にはShane StanleyのAppleScript Library「BridgePlus」のインストールが必要になります。

NSPredicateや複数条件を併記するNSCompoundPredicateで、リストに入ったレコードを抽出するのが楽すぎて、もはやこれなしにデータの抽出ができなくなりつつあります。ゴリゴリにPure AppleScriptで記述できないこともないのですが、NSPredicateが使えるだけでもASOCを覚える価値があると思えるほどです。

そんな中、徐々に記述レベルが上がってくると、無茶な抽出にもチャレンジしてみたくなるもので・・・

  「98」で始まる8桁の数字が入った要素をリストアップ。ただし、途中に出現するパターンも含む

という抽出にチャレンジしてみました(仕事で必要だったもので)。完全一致ならなんとか書けるのですが、上記の条件の文字列を「含む」ものまで抽出することを考えると、とたんに難易度が上がります。

結局、AppleのPredicate Programming Guideを総チェックして、「.*」で囲めば「条件に合うものを含む」という状態を抽出できることを見つけました(プログラミングではなくて、情報収集とかパズルのレベルですね)。

AppleScript名:ASOCでNSPredicateによる正規表現を併用した抽出
– Created 2015-09-28 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlus : script “BridgePlus” —Shane Stanley’s BridgePlus

set sampleList to {{textData:“Piyomaru”, uID:1}, {textData:“Xx Piyomaru x”, uID:2}, {textData:“xxxxx 11111111 98 x xxxxxxxx.”, uID:3}, {textData:“98x Xxxxxx (xx xxxxxxxxxx)”, uID:4}, {textData:“< < 98158113 >>”, uID:5}, {textData:“#98158084 Xxxxx Xxxxx xxxx”, uID:6}, {textData:“#98158084 Xxxxx Xxxxx xxxx”, uID:7}, {textData:“Office # 98158107″, uID:8}, {textData:“ID#98158087″, uID:9}, {textData:“98158089″, uID:10}, {textData:“00158098″, uID:11}}

–全文一致で抽出
set aRes to my filterRecListByLabel1(sampleList, “textData == ’Piyomaru’”)
–>  {​​​​​{​​​​​​​textData:”Piyomaru”, ​​​​​​​uID:1​​​​​}​​​}

–部分一致で抽出
set bRes to my filterRecListByLabel1(sampleList, “textData contains ’Piyomaru’”)
–>  {​​​​​{​​​​​​​textData:”Piyomaru”, ​​​​​​​uID:1​​​​​}, ​​​​​{​​​​​​​textData:”Xx Piyomaru x”, ​​​​​​​uID:2​​​​​}​​​}

–正規表現で抽出(8桁の数字)
set cRes to my filterRecListByLabel1(sampleList, “textData MATCHES ’\\\\d{8}’”)
–>  {​​​​​{​​​​​​​textData:”98158089″, ​​​​​​​uID:10​​​​​}, ​​​​​{​​​​​​​textData:”00158089″, ​​​​​​​uID:11​​​​​}​​​}

set dRes to my filterRecListByLabel1(sampleList, “textData MATCHES ’98\\\\d{6}’”)
–>  {​​​​​{​​​​​​​textData:”98158089″, ​​​​​​​uID:10​​​​​}​​​}

set eRes to my filterRecListByLabel1(sampleList, “textData LIKE ’*98??????*’”)
–>  {​​​​​{​​​​​​​textData:”xxxxx 11111111 98 x xxxxxxxx.”, ​​​​​​​uID:3​​​​​}, ​​​​​{​​​​​​​textData:”98x Xxxxxx (xx xxxxxxxxxx)”, ​​​​​​​uID:4​​​​​}, ​​​​​{​​​​​​​textData:”< < 98158113 >>”, ​​​​​​​uID:5​​​​​}, ​​​​​{​​​​​​​textData:”#98158084 Xxxxx Xxxxx xxxx”, ​​​​​​​uID:6​​​​​}, ​​​​​{​​​​​​​textData:”#98158084 Xxxxx Xxxxx xxxx”, ​​​​​​​uID:7​​​​​}, ​​​​​{​​​​​​​textData:”Office # 98158107″, ​​​​​​​uID:8​​​​​}, ​​​​​{​​​​​​​textData:”ID#98158087″, ​​​​​​​uID:9​​​​​}, ​​​​​{​​​​​​​textData:”98158089″, ​​​​​​​uID:10​​​​​}​​​}

set fRes to my filterRecListByLabel1(sampleList, “textData LIKE ’*\”98\”[0-9][0-9][0-9][0-9][0-9][0-9]*’”) –Oops!!
–>  {}

set gRes to my filterRecListByLabel1(sampleList, “textData LIKE ’*[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]*’”) –Oops!!
–>  {}

set hRes to my filterRecListByLabel1(sampleList, “textData MATCHES ’.*[98]\\\\d{6}.*’”) –OK!!
–>  {​​​​​{​​​​​​​textData:”< < 98158113 >>”, ​​​​​​​uID:5​​​​​}, ​​​​​{​​​​​​​textData:”#98158084 Xxxxx Xxxxx xxxx”, ​​​​​​​uID:6​​​​​}, ​​​​​{​​​​​​​textData:”#98158084 Xxxxx Xxxxx xxxx”, ​​​​​​​uID:7​​​​​}, ​​​​​{​​​​​​​textData:”Office # 98158107″, ​​​​​​​uID:8​​​​​}, ​​​​​{​​​​​​​textData:”ID#98158087″, ​​​​​​​uID:9​​​​​}, ​​​​​{​​​​​​​textData:”98158089″, ​​​​​​​uID:10​​​​​}​​​}

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel1(aRecList as list, aPredicate as string)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
set bList to ASify from filteredArray as list
  
return bList
end filterRecListByLabel1

★Click Here to Open This Script 

2015/09/22 クリップボードの内容をRTFとPDFとHTMLで書き出す

Cocoaの機能を用いて、クリップボードの内容をデスクトップにRTFとPDFで書き出すAppleScriptの改訂版です。

前バージョンのAppleScriptでは、スタイル付きテキスト(NSAttributedString)をHTMLに書き出すと、HTML内のタグでは「UTF-8」になっていながらも、HTMLのテキスト自体のエンコーディングがShift JISというたいへん不思議な状態になっていました。

スタイル付きテキスト(NSAttributedString)の取得部分に問題がないことを確認。スタイル付きテキストをPDFやRTFに書き出した場合には問題なし。HTMLの書き出しに固有の根の深い問題があるのかと疑っていましたが・・・難易度でいえば、それほど難しくない話でした。

修正部分はたった1箇所。最後にHTMLをファイルに書き込む際に、UTF-8(NSUTF8StringEncoding)を指定する記述を追加しただけです。

テキストエンコーディングの省略時にはかならず「UTF-8」が指定されるものとばかり思っていましたが、明示的に指定しないとダメということがよくわかりました。

AppleScript名:クリップボードの内容をRTFとPDFとHTMLで書き出す v2
– Created 2015-09-20 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit” – for NSPasteboard, which is the clipboard

–クリップボードの内容をNSAttributedStringに
set anAttr to my getClipboardASStyledText()

–保存先とファイル名を求める
set targFol to POSIX path of (path to desktop)
set aUUID to current application’s NSUUID’s UUID()’s UUIDString() as text

set aRes to my saveStyledTextAsRTF(aUUID, targFol, anAttr) –RTFで書き出す
set bRes to my saveStyledTextAsPDF(aUUID, targFol, anAttr) –PDFで書き出す
set cRes to my saveStyledTextAsHTML(aUUID, targFol, anAttr) –HTMLで書き出す

– クリップボードの内容をNSAttributedStringとして取り出して返す
on getClipboardASStyledText()
  set theNSPasteboard to current application’s NSPasteboard’s generalPasteboard()
  
set theAttributedStringNSArray to theNSPasteboard’s readObjectsForClasses:({current application’s NSAttributedString}) options:(missing value)
  
set theNSAttributedString to theAttributedStringNSArray’s objectAtIndex:0
  
return theNSAttributedString
end getClipboardASStyledText

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(aFileName, targFol, aStyledString)
  –Convert NSMutableStyledStrings to RTF
  
set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to current application’s NSDictionary’s dictionaryWithObject:“NSRTFTextDocumentType” forKey:(current application’s NSDocumentTypeDocumentAttribute)
  
set bRTF to aStyledString’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict
  
  
– build path based on title
  
set theName to current application’s NSString’s stringWithString:aFileName
  
set theName to theName’s stringByReplacingOccurrencesOfString:“/” withString:“_”
  
set theName to theName’s stringByReplacingOccurrencesOfString:“:” withString:“_”
  
set thePath to current application’s NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“rtf”
  
  
return (bRTF’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsRTF

–スタイル付きテキストを指定フォルダ(POSIX path)にPDFで書き出し
on saveStyledTextAsPDF(aFileName, targFol, aStyledString)
  – get page size being used for printing
  
set printInfo to current application’s NSPrintInfo’s sharedPrintInfo()
  
set pageSize to printInfo’s paperSize()
  
set theLeft to printInfo’s leftMargin()
  
set theTop to printInfo’s topMargin()
  
  
– make a text view
  
set theView to current application’s NSTextView’s alloc()’s initWithFrame:{origin:{x:0, y:0}, |size|:pageSize}
  
theView’s setTextContainerInset:{theLeft, theTop}
  
  
– put in the text
  
theView’s textStorage()’s setAttributedString:aStyledString
  
set theData to theView’s dataWithPDFInsideRect:{origin:{x:0, y:0}, |size|:pageSize}
  
  
– build path based on title
  
set theName to current application’s NSString’s stringWithString:aFileName
  
set theName to theName’s stringByReplacingOccurrencesOfString:“/” withString:“_”
  
set theName to theName’s stringByReplacingOccurrencesOfString:“:” withString:“_”
  
set thePath to current application’s NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“pdf”
  
  
return (theData’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsPDF

–スタイル付きテキストを指定フォルダ(POSIX path)にHTMLで書き出し
on saveStyledTextAsHTML(aFileName, targFol, aStyledString)
  –Convert NSMutableStyledStrings toHTML
  
set theNSDictionary to current application’s NSMutableDictionary’s dictionaryWithObject:(current application’s NSHTMLTextDocumentType) forKey:(current application’s NSDocumentTypeDocumentAttribute)
  
set theNSData to aStyledString’s dataFromRange:{location:0, |length|:aStyledString’s |length|()} documentAttributes:theNSDictionary |error|:(missing value)
  
set aHTML to current application’s NSString’s alloc()’s initWithData:theNSData encoding:(current application’s NSUTF8StringEncoding)
  
  
– build path based on title
  
set theName to current application’s NSString’s stringWithString:aFileName
  
set theName to theName’s stringByReplacingOccurrencesOfString:“/” withString:“_”
  
set theName to theName’s stringByReplacingOccurrencesOfString:“:” withString:“_”
  
set thePath to current application’s NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“html”
  
  
return (aHTML’s writeToFile:thePath atomically:true encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)) as boolean
  
end saveStyledTextAsHTML

★Click Here to Open This Script 

2015/09/20 クリップボードの内容をRTFとPDFで書き出す

Cocoaの機能を用いて、クリップボードの内容をデスクトップにRTFとPDFで書き出すAppleScriptです。

HTMLでも書き出せるのですが、日本語の文字化け(UTF-8で書き出したつもりがShift JISになっていた問題)が解決されていないため、とりあえずこんなもんで。

AppleScript名:クリップボードの内容をRTFとPDFで書き出す
– Created 2015-09-20 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit” – for NSPasteboard, which is the clipboard

–クリップボードの内容をNSAttributedStringに
set anAttr to my getClipboardASStyledText()

–保存先とファイル名を求める
set targFol to POSIX path of (path to desktop)
set aUUID to current application’s NSUUID’s UUID()’s UUIDString() as text

set aRes to my saveStyledTextAsRTF(aUUID, targFol, anAttr) –RTFで書き出す
set bRes to my saveStyledTextAsPDF(aUUID, targFol, anAttr) –PDFで書き出す

– クリップボードの内容をNSAttributedStringとして取り出して返す
on getClipboardASStyledText()
  set theNSPasteboard to current application’s NSPasteboard’s generalPasteboard()
  
set theAttributedStringNSArray to theNSPasteboard’s readObjectsForClasses:({current application’s NSAttributedString}) options:(missing value)
  
set theNSAttributedString to theAttributedStringNSArray’s objectAtIndex:0
  
return theNSAttributedString
end getClipboardASStyledText

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(aFileName, targFol, aStyledString)
  –Convert NSMutableStyledStrings to RTF
  
set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to current application’s NSDictionary’s dictionaryWithObject:“NSRTFTextDocumentType” forKey:(current application’s NSDocumentTypeDocumentAttribute)
  
set bRTF to aStyledString’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict
  
  – build path based on title
  
set theName to current application’s NSString’s stringWithString:aFileName
  
set theName to theName’s stringByReplacingOccurrencesOfString:“/” withString:“_”
  
set theName to theName’s stringByReplacingOccurrencesOfString:“:” withString:“_”
  
set thePath to current application’s NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“rtf”
  
  return (bRTF’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsRTF

–スタイル付きテキストを指定フォルダ(POSIX path)にPDFで書き出し
on saveStyledTextAsPDF(aFileName, targFol, aStyledString)
  – get page size being used for printing
  
set printInfo to current application’s NSPrintInfo’s sharedPrintInfo()
  
set pageSize to printInfo’s paperSize()
  
set theLeft to printInfo’s leftMargin()
  
set theTop to printInfo’s topMargin()
  
  – make a text view
  
set theView to current application’s NSTextView’s alloc()’s initWithFrame:{origin:{x:0, y:0}, |size|:pageSize}
  
theView’s setTextContainerInset:{theLeft, theTop}
  
  – put in the text
  
theView’s textStorage()’s setAttributedString:aStyledString
  
set theData to theView’s dataWithPDFInsideRect:{origin:{x:0, y:0}, |size|:pageSize}
  
  – build path based on title
  
set theName to current application’s NSString’s stringWithString:aFileName
  
set theName to theName’s stringByReplacingOccurrencesOfString:“/” withString:“_”
  
set theName to theName’s stringByReplacingOccurrencesOfString:“:” withString:“_”
  
set thePath to current application’s NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“pdf”
  
  return (theData’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsPDF

★Click Here to Open This Script 

2015/09/01 ASOCでエイリアエス書類のオリジナルファイル名およびフルパスを取得

Cocoaの機能を使って、エイリアス書類からオリジナルのファイル名およびフルパスを取得するAppleScriptです。

alias_doc.png

オリジナルはShaneがAppleScript Users MLに投稿したもの(オリジナルのファイル名を取得)ですが、フルパスが分からないと困るのでフルパスを求める機能を追加しました(フルパスを求めるKeyがなかなか見つからずに検索しまくりました)。

本Scriptのみどころは、まいどまいど「current application’s」と書いていた記述を、tellブロックで省略し、各行で「its ….」と書くことで省略記述を行う実験を(Shaneが)したところです。「なるほど、こう書けるのか〜」と感心しました。

Pure AppleScriptで書くと実にシンプルに書けるのですが、Finderに依存しすぎると困ることもあるので(Xcode上でAppleScriptObjCのプログラムを書く場合とか)、地道にこうしたルーチンを書き貯めていくのは重要なことです。

AppleScript名:ASOCでエイリアエスファイルのオリジナルファイル名およびフルパスを取得
– Created 2015-09-01 by Shane Stanley
– Modified 2015-09-01 by Takaaki Naganoya
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aFile to POSIX path of (choose file)
–>  ”/Users/me/Desktop/ma_VRD175A.pdf のエイリアス”–alias file

set aRes to my nameOfOriginalFileForAlias:aFile
–>  ”ma_VRD175A.pdf”–name

set bRes to my fullpathOfOriginalFileForAlias:aFile
–>  ”/Users/me/Desktop/ma_VRD175A.pdf”–full path

on nameOfOriginalFileForAlias:posixPath
  
  
tell current application’s class “NSURL”
    – make URL
    
set anNSURL to its fileURLWithPath:posixPath
    
–>  (NSURL) file:///Users/me/Desktop/ma_VRD175A.pdf%20%E…..
    
    
– load data from alias file
    
set theData to its bookmarkDataWithContentsOfURL:anNSURL |error|:(missing value)
    
–>  (NSData) <626f6f6b dc720900 00000410 <
>    

    
    
– get value as dictionary from data
    
set theResult to its resourceValuesForKeys:{current application’s NSURLLocalizedNameKey} fromBookmarkData:theData
    
–>  (NSDictionary) {​​​​​NSURLLocalizedNameKey:”ma_VRD175A.pdf”​​​}
    
  end tell
  
  
– extract name and coerce to text
  
return (theResult’s objectForKey:(current application’s NSURLLocalizedNameKey)) as text
  
end nameOfOriginalFileForAlias:

on fullpathOfOriginalFileForAlias:posixPath
  
  
tell current application’s class “NSURL”
    – make URL
    
set anNSURL to its fileURLWithPath:posixPath
    
–>  (NSURL) file:///Users/me/Desktop/ma_VRD175A.pdf%20%….
    
    
– load data from alias file
    
set theData to its bookmarkDataWithContentsOfURL:anNSURL |error|:(missing value)
    
–>  (NSData) <626f6f6b dc720900 00000410 <
>    

    
    
– get value as dictionary from data
    
set theResult to its resourceValuesForKeys:{current application’s NSURLPathKey} fromBookmarkData:theData
    
–>  (NSDictionary) {​​​​​_NSURLPathKey:”/Users/me/Desktop/ma_VRD175A.pdf”​​​}
    
  end tell
  
  
– extract name and coerce to text
  
return (theResult’s objectForKey:(current application’s NSURLPathKey)) as text
  
end fullpathOfOriginalFileForAlias:

★Click Here to Open This Script 

2015/08/15 ASOCでRTFの内容を読み取って指定文字を置換してファイルに保存する

Cocoaの機能を利用して、既存のRTF(リッチテキストフォーマット)の内容を読み取って、指定文字を置換するAppleScriptです。置換したあとのスタイル付きテキストをファイルに保存するところまでの処理を追加しました。

前バージョンを掲載したところ、(自分的には目的にかなう内容であったものの)Shaneからツッコミ。「ファイルに書かないと置換した内容の確認のしようがないじゃん(意訳)」という指摘により、保存処理を追加しました。

AppleScript名:ASOCでRTFの内容を読み取って指定文字を置換してファイルに保存する
– Created 2015-08-15 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–Input
set aFile to POSIX path of (choose file of type {“public.rtf”})
set aFilePath to current application’s NSString’s stringWithString:aFile

–Output
set bFile to POSIX path of (choose file name with prompt “Choose replaced new RTF to save (with \”.rtf\” extension)”)
set bFilePath to current application’s NSString’s stringWithString:bFile

–Read RTF to NSData
set aData to current application’s NSData’s dataWithContentsOfFile:aFilePath options:0 |error|:(missing value)
set theStyledText to current application’s NSMutableAttributedString’s alloc()’s initWithData:aData options:(missing value) documentAttributes:(null) |error|:(missing value)
set astyledLength to theStyledText’s |string|()’s |length|()

–Replace Tag with String
theStyledText’s mutableString()’s replaceOccurrencesOfString:“<name>” withString:“長野谷” options:(current application’s NSCaseInsensitiveSearch) range:(current application’s NSMakeRange(0, astyledLength))

–Convert NSMutableStyledStrings to RTF
set bstyledLength to theStyledText’s |string|()’s |length|()
set bDict to current application’s NSDictionary’s dictionaryWithObject:“NSRTFTextDocumentType” forKey:(current application’s NSDocumentTypeDocumentAttribute)
–>  (NSDictionary) {​​​​​DocumentType:”NSRTFTextDocumentType”​​​}

set bRTF to theStyledText’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict

–Save to File
bRTF’s writeToFile:bFilePath atomically:true

★Click Here to Open This Script 

2015/08/12 ASOCでScript Editorの構文色分け情報を設定ファイルから取り出す v2

Cocoaの機能を用いて、AppleScriptの構文色分け(色+フォント)情報が入っているplistから情報を取り出し、RGBの各8ビットの値のリストにまとめるAppleScriptです。

NSDeviceRGBColorからRGBの各値を取り出すテストを行ったものです。

AppleScript名:ASOCでScript Editorの構文色分け情報を設定ファイルから取り出す v2
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set AppleScriptFontFile to “~/Library/Preferences/com.apple.applescript.plist”
set aRec to retDictFromPlist(AppleScriptFontFile) of me

set asAttr to AppleScriptSourceAttributes of aRec
set colList to {}
set aMAX to 255 –or 65535 (AS Color は0〜65535 あまり意味はないが、、、)

repeat with i in asAttr
  set aCol to NSColor of i
  
–>  {{(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.568627 0.156863 0.564706 1….}
  
set aColO to (current application’s NSUnarchiver’s unarchiveObjectWithData:aCol)
  
set the end of colList to retColListFromNSColor(aColO, aMAX)
end repeat
colList
–aMAX=255の場合
–> {{128, 0, 128}, {95, 94, 94}, {14, 62, 251}, {120, 52, 203}, {252, 42, 28}, {0, 0, 0}, {145, 82, 17}, {18, 18, 18}, {39, 201, 201}, {15, 62, 251}, {31, 182, 252}, {129, 58, 217}, {93, 54, 146}, {9, 55, 187}, {8, 55, 187}, {9, 55, 186}, {86, 55, 189}, {52, 32, 99}}

–aMax=65535の場合
–> {{32768, 0, 32768}, {24415, 24158, 24158}, {3598, 15934, 64507}, {30840, 13364, 52171}, {64764, 10794, 7196}, {0, 0, 0}, {37265, 21074, 4369}, {4721, 4721, 4721}, {10023, 51657, 51657}, {3855, 15934, 64507}, {7967, 46774, 64764}, {33153, 14906, 55769}, {23901, 13878, 37522}, {2313, 14135, 48059}, {2056, 14135, 48059}, {2313, 14135, 47802}, {22102, 14135, 48573}, {13364, 8224, 25443}}

–Read plist as record
on retDictFromPlist(aPath as text)
  set thePath to current application’s NSString’s stringWithString:aPath
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theDict to current application’s NSDictionary’s dictionaryWithContentsOfFile:thePath
  
return theDict as record
end retDictFromPlist

–NSColorからrgbの8bitの値を取り出す
on retColListFromNSColor(aCol, aMAX as integer)
  set aRed to round ((aCol’s redComponent()) * aMAX) rounding as taught in school
  
set aGreen to round ((aCol’s greenComponent()) * aMAX) rounding as taught in school
  
set aBlue to round ((aCol’s blueComponent()) * aMAX) rounding as taught in school
  
return {aRed, aGreen, aBlue}
end retColListFromNSColor

★Click Here to Open This Script 

2015/08/10 使用中のMacの製品呼称を取得する v2

使用中のMacの製品呼称を取得するAppleScriptです。

@fixdotさんにTwitterで教えていただいた ここの情報 でplistから検索するように変更してみました。

ただ、やはり製品が新しくなってもマシンの世代が変わっていないものについては、違いを検出できないため、決定的なものにはなっていません。製品のシリアル番号から生産年と生産週は取得できるため、このあたりをからめて(モデルごとの生産年・週の境目がわかれば)、擬似的な判定は可能と思われます。

AppleScript名:使用中のMacの製品呼称を取得する v2
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgeP : script “BridgePlus”

set pListPath to “/System/Library/PrivateFrameworks/ServerInformation.framework/Versions/A/Resources/English.lproj/SIMachineAttributes.plist”
set aRec to retDictFromPlist(pListPath) of me

set hwName to (do shell script “sysctl -n hw.model”) as text
–>  ”MacBookPro10,1″

set aMachineRec to retRecordByLabel(aRec, hwName)
–>  {​​​​​”x86_64″, ​​​​​”/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/com.apple.macbookpro-15-retina-display.icns”, ​​​​​{​​​​​​​marketingModel:”MacBook Pro with Retina display, Intel Core i7, 15\” (Mid 2012)”, ​​​​​​​model:”MacBook Pro”, ​​​​​​​description:”15\” MacBook Pro with Retina display, dual-core Intel Core i7 processor and aluminum unibody, introduced mid 2012.”, ​​​​​​​processor:”Intel Core i7″​​​​​}​​​}

set macName to marketingModel of (last item of aMachineRec)
–>  ”MacBook Pro with Retina display, Intel Core i7, 15\” (Mid 2012)”

–Read plist as record
on retDictFromPlist(aPath)
  set thePath to current application’s NSString’s stringWithString:aPath
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theDict to current application’s NSDictionary’s dictionaryWithContentsOfFile:thePath
  
return theDict as record
end retDictFromPlist

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel(aRecList as list, aPredicate as string)
  –ListからNSArrayへの型変換
  
set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
  –抽出
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
  –NSArrayからListに型変換して返す
  
set bList to (ASify from filteredArray) as list
  
return bList
end filterRecListByLabel

–指定レコードの指定ラベルの値を取得する
on retRecordByLabel(aRec as record, aKey as string)
  set aDic to current application’s NSDictionary’s dictionaryWithDictionary:aRec
  
set aVal to aDic’s valueForKey:aKey
  
set aValNum to (ASify from aVal) as list
  
return aValNum
end retRecordByLabel

★Click Here to Open This Script 

2015/08/04 ASOCで画像+文字作成テスト_v2

Cocoaの機能を用いて指定サイズの単色塗り画像を作成し、指定の文字列を描画してPNG形式の画像ファイルに書き出すAppleScriptの別バージョンです。

test3.png
▲こんな画像(test.png)がデスクトップに書き出されます

多くの場合、バージョンアップすると機能を増やしたり強化したりしていますが、このv2は初版と機能面で差はありません。出力される画像の色やサイズを変更していることには、とくに意味はありません。

本件についてShane Stanleyと週をまたいでメールのやりとりをしていて、ようやく「なるほど」という落着点を見出せたので掲載にいたっています。

今をさかのぼること10年以上昔、Classic Mac OSの時代に、AppleScriptのサブルーチン(ハンドラ)呼び出しなどで参照渡し(call by reference)によるデータのやりとりを行っていました。当時はまだCPUも遅く、AppleScriptの処理系もいまほど高速ではなかったので、高速化手法のひとつとして参照渡しは割と使われていたテクニックでした。

AppleScript名:参照渡しのテスト
set aList to {1, 2, 3}
modList(aList)
log aList
–> {1, 2, 3, 4}

–Call By Reference
on modList(someList)
  set end of someList to 4
end modList

★Click Here to Open This Script 

ただ、プログラムがわかりにくくなる上にバグが入り込む隙間が大きいので、自分は当時から各種サブルーチンを「値渡し」(call by value)で記述するようにスタイルを固定して今日にいたっています。おかげで、巨大なプログラムを作っても割とトラブル知らずでやってこれたように思います(偏見)。

AppleScript名:値渡しのテスト
set aList to {1, 2, 3}
set aList to modList(aList)
log aList
–> {1, 2, 3, 4}

–Call By Value
on modList(someList)
  set newList to {}
  
copy someList to newList –deep copy
  
set end of newList to 4
  
return newList
end modList

★Click Here to Open This Script 

今回、Shaneが「こういう書き方はどう?」と提案してきた書き方は、この「参照渡し」によるものでしたが、てっきり

 「Cocoaのオブジェクト生成はAppleScriptの範疇とは別で管理されている(ものもある)のか?」

と勘違いしてしまったものでした(MacScripterでたまに見かける記述で、首をひねっていた)。ここ、自分は間違って理解していたので、あえて自分の勘違いも含めて書いておきます。

Shaneによる変更点は、_蔀呂良分の塗りのグラフィックを生成 のあとの、 ▲哀薀侫ックに文字を塗りで描画する の部分で,離哀薀侫ック(aImage1)をハンドラに渡したあと、実行結果を変数aImage1に受け取っている部分です(参照渡し)。

Shaneがここで、判読しにくくなる危険をおかしてでも参照渡しでデータをやりとりした理由は、

「本来は同じ値の変数で処理の段階が異なるものが複数存在していた場合、間違って最新のもの以外を利用してしまう危険が発生する。なるべく同じデータであれば1つの変数に格納しておくべき」

というものでした。メモリー使用量の削減には効果は大してなく、処理速度の問題でもない、と。

内容と使うべき理由について、よく理解できたので掲載しておきます(でも、自分は使用済みゴミ変数を撒き散らしつつ値渡しで書くでしょう、、、)。

海外のMLやBBS(とくに、MacScripter.net)でこのような書き方が見られるケースがありますので、参考にしてください。

AppleScript名:ASOCで画像+文字作成テスト_v2
– Created 2015-07-31 by Takaaki Naganoya
– Modified 2015-08-01 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

set aWidth to 400.0 –幅
set aHeight to 200.0 –高さ
set outPath to “~/Desktop/test.png” –書き出し先のファイルパス
set fillColor to current application’s NSColor’s blackColor –塗り色
set drawColor to current application’s NSColor’s whiteColor –文字色
set aText to “ぴよまるソフトウェア”
set {xPos, yPos} to {1, 5}

–新規画像を作成して背景を塗る
set aImage1 to makeImageWithFilledColor(aWidth, aHeight, outPath, fillColor) of me

–画像に文字を塗る(参照渡し(call by reference)で、結果はaImage1に入る)
drawStringsOnImage(aImage1, aText, “HiraKakuStd-W8″, 36.0, drawColor, xPos, yPos) of me

–ファイル保存
set aRes to saveImageRepAtPathAsPNG(aImage1, outPath) of me

–画像のうえに指定の文字を描画して画像を返す
on drawStringsOnImage(anImage, aText, aFontName, aPoint, drawColor)
  
  
set aString to current application’s NSString’s stringWithString:aText
  
set aDict to current application’s NSDictionary’s dictionaryWithObjects:{current application’s NSFont’s fontWithName:aFontName |size|:aPoint, drawColor} forKeys:{current application’s NSFontAttributeName, current application’s NSForegroundColorAttributeName}
  
set imageSize to anImage’s |size|()
  
set textSize to aString’s sizeWithAttributes:aDict
  
set xPos to ((width of imageSize) - (width of textSize)) / 2
  
set yPos to ((height of imageSize) - (height of textSize)) / 2
  
–文字描画開始
  
anImage’s lockFocus()
  
aString’s drawAtPoint:(current application’s NSMakePoint(xPos, yPos)) withAttributes:aDict
  
anImage’s unlockFocus()
  
end drawStringsOnImage

–指定サイズの画像を作成し、背景を指定色で塗る
on makeImageWithFilledColor(aWidth, aHeight, outPath, fillColor)
  
  
–Imageの作成  
  
set anImage to current application’s NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
  
–描画開始
  
anImage’s lockFocus()
  
  
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
  
set theNSBezierPath to current application’s NSBezierPath’s bezierPath
  
theNSBezierPath’s appendBezierPathWithRect:theRect
  
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
  
anImage’s unlockFocus()
  
–描画ここまで
  
  
return anImage –画像を返す
  
end makeImageWithFilledColor

–画像を指定パスにPNG形式で保存
on saveImageRepAtPathAsPNG(anImage, outPath)
  
  
–画像のRaw画像を作成
  
set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
  
–書き出しファイルパス情報を作成
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
  
–書き出し
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
  
return aRes –成功ならtrue、失敗ならfalseが返る
  
end saveImageRepAtPathAsPNG

★Click Here to Open This Script 

2015/07/27 ASOCでAppleScript設定ファイルの読み込み

Cocoaの機能を用いてScript Editor自身の書式設定ファイル(plist)を読み込むAppleScriptです。

とくに特殊な処理は必要なく、一般的なplistファイルに記録されたDictionaryをrecordに読み込んで、最終的にNSDataから各種データに復元しています。もうちょっとこなれた書き方もありそうですが、とりあえずデータを取り出すレベルまで書いてみた次第です。

Scriptが返している各種Cocoaのオブジェクトについては、Apple純正Script Editorでは表示されず、ASObjC Explorer 4で表示されるものを記載しています。

本当に色とフォント種別(+サイズほか関連情報)しか入っていないのにはびっくりです。

AppleScript名:ASOCでAppleScript設定ファイルの読み込み
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set AppleScriptFontFile to “~/Library/Preferences/com.apple.applescript.plist”
set pathString to current application’s NSString’s stringWithString:AppleScriptFontFile
set newPath to pathString’s stringByExpandingTildeInPath()
set aRec to retDictFromPlist(newPath) of me

set asAttr to AppleScriptSourceAttributes of aRec
set asAttrArray to {}

repeat with i in asAttr
  
  set aCol to NSColor of i
  
set aFont to NSFont of i
  
  set aColO to (current application’s NSUnarchiver’s unarchiveObjectWithData:aCol)
  
set aFonO to (current application’s NSUnarchiver’s unarchiveObjectWithData:aFont)
  
  set the end of asAttrArray to {aColO, aFonO}
  
end repeat

asAttrArray
–>  {​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.568627 0.156863 0.564706 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.372549 0.368627 0.368627 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.054902 0.243137 0.984314 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.470588 0.203922 0.796079 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.988235 0.164706 0.109804 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0 0 0 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.568627 0.321569 0.0666667 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0 0 0 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.152941 0.788235 0.788235 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.0588235 0.243137 0.984314 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.121569 0.713726 0.988235 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.505882 0.227451 0.85098 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.364706 0.211765 0.572549 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.0352941 0.215686 0.733333 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.0313726 0.215686 0.733333 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.0352941 0.215686 0.729412 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.337255 0.215686 0.741176 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}, ​​​​​{​​​​​​​(NSDeviceRGBColor) NSDeviceRGBColorSpace 0.203922 0.12549 0.388235 1, ​​​​​​​(NSFont) “Osaka 12.00 pt. P [] (0×600000249cc0) fobj=0×6000005e9800, spc=3.33″​​​​​}​​​}

–Read plist as record
on retDictFromPlist(aPath)
  set thePath to current application’s NSString’s stringWithString:aPath
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theDict to current application’s NSDictionary’s dictionaryWithContentsOfFile:thePath
  
return theDict as record
end retDictFromPlist

★Click Here to Open This Script