Archive for the 'NSFont' Category

2017/09/25 書式つきテキストを組み立ててサイズを取得して画像書き出し v2

複数行にわたる書式付きテキストを組み立てて、描画サイズを取得して画像書き出しするAppleScriptです。

スタイル付きテキスト(NSAttributedString)を作成し、その描画エリアのサイズを取得。そんなもん、こんな手軽に求められるとは思ってもみませんでした。

描画エリアのサイズをもとに空白画像を作成して、そこにスタイル付きテキストを描画。結果の画像を指定パス名で書き出します。

test9999.png
▲本Scriptの実行結果(macOS 10.12)。出力用の文字列を長くしても、描画サイズを調べて画像化しているので、途中で途切れたりはしません

ただし、意外なところでOSバージョンによる挙動の差が出ました。書式付きテキストの描画サイズの取得ではなく、下地の塗りつぶし(白)についてです(下図参照)。

1013_strange_behavior.png
▲macOS 10.12(上)とmacOS 10.13GM(下)の本Scriptの実行結果。検証のために文字データを変更(途中の改行を減らしている)

macOS 10.13のRelease Build(Build 17A365)でも同様の結果になりました。macOS 10.10で実験したら10.12と同様の結果に。何か(トンでもない場所の)仕様が変わったのだろうか?

→ macOS 10.13のバグでした。対応版を掲載しています

AppleScript名:書式つきテキストを組み立ててサイズを取得して画像書き出し v2
– Created 2017-09-25 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
–http://piyocast.com/as/archives/4843

property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSBezierPath : a reference to current application’s NSBezierPath
property NSMutableParagraphStyle : a reference to current application’s NSMutableParagraphStyle
property NSPNGFileType : a reference to current application’s NSPNGFileType
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSKernAttributeName : a reference to current application’s NSKernAttributeName
property NSLigatureAttributeName : a reference to current application’s NSLigatureAttributeName
property NSFont : a reference to current application’s NSFont
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSUnderlineStyleAttributeName : a reference to current application’s NSUnderlineStyleAttributeName
property NSImage : a reference to current application’s NSImage
property NSParagraphStyleAttributeName : a reference to current application’s NSParagraphStyleAttributeName
property NSString : a reference to current application’s NSString
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep
property NSColor : a reference to current application’s NSColor

set outPath to “~/Desktop/test9999.png”
set fillColor to NSColor’s whiteColor –塗り色
set aFontSize to 48
set aString to “Takaaki” & return & “Naganoya” & return & “長野谷” & return & “隆昌”

set anAssrStr to makeRTFfromParameters(aString, “HiraMinProN-W3″, aFontSize, -2, (aFontSize * 1.5)) of me
set aSize to anAssrStr’s |size|()
–>  {width:408.0, height:187.2}

set attrStrWidth to width of aSize
set attrStrHeight to height of aSize

set {xPos, yPos} to {0, 0}

–下地の画像を作成
set tmpImg1 to makeImageWithFilledColor(attrStrWidth, attrStrHeight, fillColor) of me

–下地の画像の上にAttributed Stringを描画
set tmpImg2 to drawAttributedStringsOnImage(tmpImg1, anAssrStr, xPos, yPos) of me

–PNG形式でファイルに保存
set aRes to saveImageRepAtPathAsPNG(tmpImg2, outPath) of me

–画像のうえに指定のスタイル付きテキストを描画して画像を返す
on drawAttributedStringsOnImage(anImage, anAssrStr, xPos, yPos)
  anImage’s lockFocus()
  
anAssrStr’s drawAtPoint:(current application’s NSMakePoint(xPos, yPos))
  
anImage’s unlockFocus()
  
return anImage
end drawAttributedStringsOnImage

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

–指定サイズの画像を作成し、背景を指定色で塗る
on makeImageWithFilledColor(aWidth, aHeight, fillColor)
  set anImage to 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 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)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep
  
  
set pathString to NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
  
set myNewImageData to (aRawimg’s representationUsingType:(NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
  
return aRes
end saveImageRepAtPathAsPNG

★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/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/05/27 書式つきテキストを組み立てて、クリップボードに設定(影をつける)

書式つきテキスト(NSAttributedString)を組み立てて、クリップボードに設定するAppleScriptの改良版です。影(NSShadow)の追加指定を行ってみました。

stylet2.png

AppleScript名:書式つきテキストを組み立てて、クリップボードに設定(影をつける)
– Created 2017-05-26 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
–http://piyocast.com/as/archives/4664

set anAttrStr to makeRTFfromParameters("ぴよまるソフトウェア", 2.0, 36) of me

set attrList to {anAttrStr}
restoreClipboard(attrList) of me –set the clipboard to rtf_data

–書式つきテキストを組み立てる
on makeRTFfromParameters(aStr as string, outlineNum as real, aFontSize as real)
  –フォント
  
set aVal1 to current application’s NSFont’s fontWithName:"HiraKakuStdN-W8" |size|:aFontSize
  
set aKey1 to (current application’s NSFontAttributeName)
  
  
–色
  
set aVal2 to current application’s NSColor’s blackColor()
  
set aKey2 to (current application’s NSForegroundColorAttributeName)
  
  
–カーニング
  
set aVal3 to -2.0
  
set akey3 to (current application’s NSKernAttributeName)
  
  
–アンダーライン
  
set aVal4 to 0
  
set akey4 to (current application’s NSUnderlineStyleAttributeName)
  
  
–リガチャ
  
set aVal5 to 2 –全てのリガチャを有効にする
  
set akey5 to (current application’s NSLigatureAttributeName)
  
  
–枠線(アウトライン)
  
set aVal6 to outlineNum
  
set akey6 to (current application’s NSStrokeWidthAttributeName)
  
  
–Shadow
  
set aVal7 to current application’s NSShadow’s alloc()’s init()
  
aVal7’s setShadowOffset:(current application’s CGSizeMake(1.0, 1.0)) –影のサイズ
  
aVal7’s setShadowColor:(current application’s NSColor’s blackColor()) –影の色
  
aVal7’s setShadowBlurRadius:2.0 –ぼかしの半径
  
set akey7 to (current application’s NSShadowAttributeName)
  
  
set keyList to {aKey1, aKey2, akey3, akey4, akey5, akey6, akey7}
  
set valList to {aVal1, aVal2, aVal3, aVal4, aVal5, aVal6, aVal7}
  
set attrsDictionary to current application’s NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
  
  
set attrStr to current application’s NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary
  
return attrStr
  
end makeRTFfromParameters

–From Shane Stanley’s Book "Everyday AppleScriptObjC"
on restoreClipboard(theArray as list)
  set thePasteboard to current application’s NSPasteboard’s generalPasteboard()
  
thePasteboard’s clearContents()
  
thePasteboard’s writeObjects:theArray
end restoreClipboard

★Click Here to Open This Script 

2017/05/26 書式つきテキストを組み立てて、クリップボードに設定

書式つきテキスト(NSAttributedString)を組み立てて、クリップボードに設定するAppleScriptです。

作成した書式つきテキストは、そのままKeynoteなどのアプリケーションにペーストして利用することが可能です。グラフィックではないため、アプリケーション上での再編集や影の指定、色の変更などが可能です。

styles.png

Keynoteでアウトライン文字を使いたいことはままあるので、このように手軽にクリップボードに転送して利用できると実用性が高いことでしょう。

後日談:という紹介をしたら、KeynoteのヘビーユーザーからKeynoteのGUI上からアウトライン文字の書式を指定できることを教えてもらいました。

AppleScript名:書式つきテキストを組み立てて、クリップボードに設定
– Created 2017-05-26 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
–http://piyocast.com/as/archives/4662

set anAssrStr to makeRTFfromParameters(“ぴよまるソフトウェア”, 3.0, 72) of me

set attrList to {anAssrStr}
restoreClipboard(attrList) of me –set the clipboard to rtf_data

–書式つきテキストを組み立てる
on makeRTFfromParameters(aStr as string, outlineNum as real, aFontSize as real)
  –フォント
  
set aVal1 to current application’s NSFont’s fontWithName:“HiraKakuStdN-W8″ |size|:aFontSize
  
set aKey1 to (current application’s NSFontAttributeName)
  
  
–色
  
set aVal2 to current application’s NSColor’s blueColor()
  
set aKey2 to (current application’s NSForegroundColorAttributeName)
  
  
–カーニング
  
set aVal3 to -2.0
  
set akey3 to (current application’s NSKernAttributeName)
  
  
–アンダーライン
  
set aVal4 to 0
  
set akey4 to (current application’s NSUnderlineStyleAttributeName)
  
  
–リガチャ
  
set aVal5 to 2 –全てのリガチャを有効にする
  
set akey5 to (current application’s NSLigatureAttributeName)
  
  
–枠線(アウトライン)
  
set aVal6 to outlineNum
  
set akey6 to (current application’s NSStrokeWidthAttributeName)
  
  
set keyList to {aKey1, aKey2, akey3, akey4, akey5, akey6}
  
set valList to {aVal1, aVal2, aVal3, aVal4, aVal5, aVal6}
  
set attrsDictionary to current application’s NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
  
  
set attrStr to current application’s NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary
  
return attrStr
  
end makeRTFfromParameters

–From Shane Stanley’s Book “Everyday AppleScriptObjC”
on restoreClipboard(theArray as list)
  set thePasteboard to current application’s NSPasteboard’s generalPasteboard()
  
thePasteboard’s clearContents()
  
thePasteboard’s writeObjects:theArray
end restoreClipboard

★Click Here to Open This Script 

2016/02/01 指定の名称のフォントの見本を表示

指定のPostScript名称のフォントの見本をウィンドウ表示するAppleScriptです。

Script Editor上ではControl+Command+Rで実行する必要があります。

NSFont経由で指定フォントが含む文字セットを取得し、どの文字が含まれているのかをチェックしたい、という目的のために作成したものです。ウィンドウを作成して文字表示しているのは、あくまで「おまけ」です。

font1.png

NSFontにcoveredCharacterSet()で指定フォントが持っている文字セットを取得。この文字セットの中に含まれている文字を、1〜65535の数値で(文字を作ってチェックしたらダメで、数値)存在チェックしています。ここだけ、ループでいちいち調べているので時間がかかります(MacBook Pro Retina 2012で4秒ぐらい)。ここは、もうちょっとなんとかならないかと思っています。

また、OS標準のFont Book.appで調べたグリフ数とNSFont→NSCharacterSet経由で存在確認して得られるCharacter数は異なっているため、自分としてはちょっと肩透かしをくらいました。Font Book.appだと各フォントが含んでいる文字といった細かい情報が取得できないため、NSFont経由で調査してみたのですが・・・フォント内の各文字(コード)が実際にグリフを持っているかどうかは、文字セット中の文字を実際にレンダリングしてみないとダメそうな気配がしています(文字コードだけ宣言しておいて何も割り当てグリフがないというケースとか、同じ文字コードに複数のグリフが割り当てられているケースなど(「高」と「癲廖覆呂靴瓦世)など)、深入りするとトンでもないものがありそう)。

AppleScript中で指定している「TheLittleBirdFONT」は、手書き風日本語文字フォントの傑作「ことり文字ふぉんと」(自分が使っているのは大昔に無償配布されていたバージョン)です。OS標準でインストールされているわけではないため、動作チェックには他のものを指定したほうがよいでしょう。

font2.png

ことり文字ふぉんとの独特の特殊記号がどこに入っているかを忘れてしまったため、とりあえず文字セット中の文字をすべてことり文字ふぉんとで表示して「簡易フォント見本帖」のように使ってみたりもしました。

AppleScript名:ASOCでテキストビュー+ボタンを作成(フォント指定)
– Created 2016-02-01 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “Carbon” – AEInteractWithUser() is in Carbon

property windisp : false

set aFontName to “TheLittleBirdFONT”
set aWidth to 450
set aHeight to 600

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

set aTitle to “テキストビューのじっけん/TextView Test” –Window Title
set aButtonMSG to “OK” –Button Title

–表示用テキストの作成
set aRes to checkExistenceOfFont(aFontName) of me
if aRes = false then
  display dialog “There is no < " & aFontName & “> font. Designate another one.” –No font
  
return
end if
set bRes to retDefinedCharactersInFont(aFontName) of me
set dispStr to listToStringUsingTextItemDelimiter(bRes, “, “) of me

dispTextView(aWidth, aHeight, aTitle, dispStr, aButtonMSG, 180, aFontName, 36) of me

on dispTextView(aWidth as integer, aHeight as integer, aTitle as text, dispStr, aButtonMSG as text, timeOutSecs as number, fontID, fontSize)
  
  
set aColor to current application’s NSColor’s colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:1.0
  
set (my windisp) to true
  
  
–Text View+Scroll Viewをつくる
  
set aScroll to current application’s NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
set aView to current application’s NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
aView’s setRichText:true
  
aView’s useAllLigatures:true
  
aView’s setTextColor:(current application’s NSColor’s yellowColor()) –cyanColor
  
aView’s setFont:(current application’s NSFont’s fontWithName:fontID |size|:fontSize) –ヒラギノ明朝Pro W3
  
aView’s setBackgroundColor:aColor
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
–Buttonをつくる
  
set bButton to (current application’s NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, 40)))
  
bButton’s setTitle:aButtonMSG
  
bButton’s setTarget:me
  
bButton’s setAction:(“clicked:”)
  
  
–SplitViewをつくる
  
set aSplitV to current application’s NSSplitView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aHeight, aWidth))
  
aSplitV’s setVertical:false
  
  
aSplitV’s addSubview:aScroll
  
aSplitV’s addSubview:bButton
  
aSplitV’s setNeedsDisplay:true
  
  
–WindowとWindow Controllerをつくる
  
set aWin to makeWinWithView(aSplitV, aWidth, aHeight, aTitle, 0.9)
  
aWin’s makeKeyAndOrderFront:(missing value)
  
set wController to current application’s NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
aWin’s makeFirstResponder:aView
  
aView’s setString:dispStr
  
wController’s showWindow:me
  
  
set aCount to timeOutSecs * 10 –timeout seconds * 10
  
repeat aCount times
    if (my windisp) = false then
      exit repeat
    end if
    
delay 0.1
    
set aCount to aCount - 1
  end repeat
  
  
my closeWin:aWin
  
end dispTextView

–Button Clicked Event Handler
on clicked:aSender
  set (my windisp) to false
end clicked:

–make Window for Input
on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle, alphaV)
  set aScreen to current application’s NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
set aBacking to current application’s NSTitledWindowMask –NSBorderlessWindowMask
  
set aDefer to current application’s NSBackingStoreBuffered
  
  
– Window
  
set aWin to current application’s NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
–aWin’s setBackgroundColor:(current application’s 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:(current application’s NSNormalWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setAlphaValue:alphaV –append
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
–aWin’s makeKeyAndOrderFront:(me)
  
  
– Set Custom View
  
aWin’s setContentView:aView
  
  
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:

–指定PostScript名称のフォントがコンピューター上に存在するかどうかチェック
on checkExistenceOfFont(fontName as string)
  if fontName = “” then return false
  
set aFont to current application’s NSFont’s fontWithName:fontName |size|:9.0
  
if aFont = missing value then
    return false
  else
    return true
  end if
end checkExistenceOfFont

–指定Postscript名称のフォントに定義されている文字数を数えて返す
on countDefinedCharactersInFont(fontName as string)
  
  
script spdF
    property aList : {}
  end script
  
  
set aFont to current application’s NSFont’s fontWithName:fontName |size|:9.0
  
if aFont = missing value then return false
  
  
set aSet to aFont’s coveredCharacterSet()
  
  
set aList of spdF to {}
  
  
repeat with i from 1 to 65535
    set aRes to (aSet’s characterIsMember:i) as boolean
    
if aRes = true then
      set the end of aList of spdF to (string id i)
    end if
  end repeat
  
  
return length of (aList of spdF)
  
end countDefinedCharactersInFont

–指定Postscript名称のフォントに定義されている文字を返す
on retDefinedCharactersInFont(fontName as string)
  
  
script spdG
    property aList : {}
  end script
  
  
set aFont to current application’s NSFont’s fontWithName:fontName |size|:24.0
  
set aSet to aFont’s coveredCharacterSet()
  
  
set aList of spdG to {}
  
  
repeat with i from 1 to 65535
    set aRes to (aSet’s characterIsMember:i) as boolean
    
if aRes = true then
      set the end of aList of spdG to (string id i)
    end if
  end repeat
  
  
return (aList of spdG)
  
end retDefinedCharactersInFont

on listToStringUsingTextItemDelimiter(sourceList, textItemDelimiter)
  set the CocoaArray to current application’s NSArray’s arrayWithArray:sourceList
  
set the CocoaString to CocoaArray’s componentsJoinedByString:textItemDelimiter
  
return (CocoaString as string)
end listToStringUsingTextItemDelimiter

★Click Here to Open This Script 

2015/08/28 ASOCでNSFont,NSFontManagerのじっけん

AppleScriptでNSFontやNSFontManagerを操作して情報を取得する実験です。

このあたり、Cocoaを呼べるからものすごい処理ができるぞ(TTSの音声検索なんかはわりとすごい)、とかいうことはなくて・・・普通にPure AppleScriptでFontBook.appを操作する方が有意義な感じがします。

Photoshop書類のテキストレイヤーからフォント情報を取り出してまとめて出力するAppleScriptを組んだときには、FontBookを用いてフォント情報の付け合わせを行いましたが・・・ここであえてNSFontやNSFontManagerを呼び出してみたところで、イレギュラーなフォントについてはまともに名前などの情報を返してこないケースもありますし、Photoshopのテキストレイヤー上に複数のフォントを指定してしまうとScript側からは正しく取得できないので困ります。

AppleScript名:ASOCでNSFontのじっけん
– Created 2015-08-27 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

set aFont to current application’s NSFont’s fontWithName:“HiraKakuStd-W8″ |size|:16
–>  (NSFont) “HiraKakuStd-W8 16.00 pt. P [] (0×600001457340) fobj=0×6180001f2800, spc=5.33″

aFont’s displayName()
–>  (NSString) “ヒラギノ角ゴ Std W8″

aFont’s familyName()
–>  (NSString) “Hiragino Kaku Gothic Std”

aFont’s fontName()
–>  (NSString) “HiraKakuStd-W8″

aFont’s coveredCharacterSet()
–>  (__NSCFCharacterSet) <__nscfcharacterset : 0x6000004472c0>

aFont’s fontDescriptor()
(*)
–>  (NSCTFontDescriptor) NSCTFontDescriptor <0×61800009cb60> = {
NSFontNameAttribute = “HiraKakuStd-W8″;
NSFontSizeAttribute = 16;
}
*)

aFont’s mostCompatibleStringEncoding()
–>  2.147483649E+9 –???

aFont’s renderingMode()
–>  1
(*
typedef enum NSFontRenderingMode : NSUInteger {
NSFontDefaultRenderingMode = 0,
NSFontAntialiasedRenderingMode = 1,
NSFontIntegerAdvancementsRenderingMode = 2,
NSFontAntialiasedIntegerAdvancementsRenderingMode = 3
} NSFontRenderingMode;
*)

aFont’s printerFont()
–>  (NSFont) “HiraKakuStd-W8 16.00 pt. P [] (0×600001457340) fobj=0×6180001f2800, spc=5.33″

aFont’s screenFont()
–>  (NSFont) “HiraKakuStd-W8 16.00 pt. S [] (0×600001457340) fobj=0×6180001f2800, spc=5.00″

aFont’s numberOfGlyphs()
–>  9354

★Click Here to Open This Script 

AppleScript名:ASOCでNSFontManagerのじっけん
– Created 2015-08-27 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

set aFontMan to current application’s NSFontManager’s sharedFontManager()’s availableFontFamilies()
–>  (NSArray) {​​​​​”01FLOPDESIGN”, ​​​​​”A-OTF Shin Go Pr6N”, ​​​​​”A-OTF Shin Go Pro”, ​​​​​”Abadi MT Condensed Extra Bold”, ​​​​​”Abadi MT Condensed Light”, ​​​​​”AGENDAJinmeiGyoshotaiL1″, ​​​​​”AGENDAJinmeiSeikaishotaiL1″, ​​​​​”Akubin”,….}

set aFontMan to current application’s NSFontManager’s sharedFontManager()’s availableMembersOfFontFamily:“MS Mincho”
–>  (NSArray) {​​​​​{​​​​​​​”MS-Mincho”, ​​​​​​​”Regular”, ​​​​​​​1, ​​​​​​​0​​​​​}​​​}

set aFontMan to current application’s NSFontManager’s sharedFontManager()’s availableMembersOfFontFamily:“Times”
–>  (NSArray) {​​​​​{​​​​​​​”Times-Roman”, ​​​​​​​”Regular”, ​​​​​​​1, ​​​​​​​0​​​​​}, ​​​​​{​​​​​​​”Times-Italic”, ​​​​​​​”Italic”, ​​​​​​​1, ​​​​​​​1​​​​​}, ​​​​​{​​​​​​​”Times-Bold”, ​​​​​​​”Bold”, ​​​​​​​1, ​​​​​​​2​​​​​}, ​​​​​{​​​​​​​”Times-BoldItalic”, ​​​​​​​”Bold Italic”, ​​​​​​​1, ​​​​​​​3​​​​​}​​​}

set aFontMan to current application’s NSFontManager’s sharedFontManager()’s localizedNameForFamily:“Osaka” face:“Regular-Mono”
–>  (NSString) “レギュラー−等幅”

★Click Here to Open This Script 

2015/08/20 ASOCで動的にWindowを作成

Cocoaの機能を用いて動的にWindowを作成し、メッセージを表示したあとにWindowを消すAppleScriptです。

dispcustomwin.png

Mac OS X登場当時から、こうしたカスタムメッセージ表示用の部品の必要性がひろくscripterに認識されており、さまざまな実装が試されたなか・・・OS Xのnotification center(display notificationでAppleScriptからも表示可能)に集約されていったという歴史があります。

notification.png

オリジナルは、edama2さんの「Okaeri(シンプル版)」のコードで、そこから大幅に機能を簡略化し、当時のCocoa AppleScript Appletから、OS X 10.10上のAppleScriptObjC向けに書き換えたものです。

dispcustomwin2_resized.png

AppleScript側から汎用的にメッセージを表示させるサブルーチンに変更してみました。かなり手軽に使えます。ASOCはARC環境で動いているので、Windowオブジェクトを明示的にReleaseしてあげる必要はないはずですが・・・さて?

# 連続して実行すると3回目に表示がおかしくなるのは、、、何か足りないかも、、、まだ油断できないレベルです

Shaneから「foreground/main threadから実行する必要があるよ」という指摘があり、ASObjC Explorer 4では問題なく連続して何回でも実行できることを確認。Script EditorだとCommand-Control-Rを実行して、表示がすぐに消えたりやっぱり3回目にScript Editorごとクラッシュしたりと不思議な現象が(ーー;;;

AppleScript名:ASOCで動的にWindowを作成
– Created 2012-06-13 by edama2
– Modified 2015-08-20 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

if not (current application’s NSThread’s isMainThread()) as boolean then
  display alert “This script must be run from the main thread (Command-Control-R in Script Editor).” buttons {“Cancel”} as critical
  
error number -128
end if

set aWin to makeWinWithMessage(“Piyomaru Software”, “Custom Message From Takaaki Naganoya”)
tell current application
  delay 5
end tell
my closeWin:aWin

–ウィンドウを作成
on makeWinWithMessage(aTitle, aMes)
  
  
set aScreen to current application’s NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {800, 250}}
  
set aBacking to current application’s NSTitledWindowMask
  
set aDefer to current application’s NSBackingStoreBuffered
  
  
– Window
  
set aWin to current application’s NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen) –’s autorelease()
  
aWin’s setBackgroundColor:(current application’s NSColor’s whiteColor())
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:true
  
aWin’s setLevel:(current application’s NSNormalWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
aWin’s makeKeyAndOrderFront:(me)
  
  
– Custom View
  
set aCustView to current application’s NSView’s alloc()
  
aCustView’s initWithFrame:aFrame
  
aCustView’s setNeedsDisplay:true
  
set {origin:{x:x, y:y}, |size|:{width:w, height:h}} to aCustView’s |bounds|()
  
aWin’s setContentView:aCustView
  
  
– Text View
  
set aTV2 to current application’s NSTextView’s alloc()
  
  
set titleHeight to 26
  
set y2 to h - titleHeight - (titleHeight / 6)
  
set y3 to h - titleHeight
  
set y3 to h - y3 - (y3 / 6)
  
  
aTV2’s initWithFrame:{{0, y3}, {w, y2}}
  
aTV2’s insertText:aMes
  
aTV2’s setAlignment:(current application’s NSCenterTextAlignment)
  
aTV2’s setDrawsBackground:false
  
aTV2’s setEditable:false
  
aTV2’s setFont:(current application’s NSFont’s fontWithName:“HiraMinPro-W3″ |size|:72)
  
aTV2’s setSelectable:false
  
aTV2’s setTextColor:(current application’s NSColor’s blackColor())
  
aCustView’s addSubview:aTV2
  
  
–aWin’s setBackgroundColor:(current application’s NSColor’s clearColor())
  
  
return aWin
  
end makeWinWithMessage

–ウィンドウを閉じる
on closeWin:aWindow
  delay 3
  
repeat with n from 10 to 1 by -1
    (aWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
aWindow’s |close|()
end closeWin:

★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 

2014/12/14 AppleScriptのカラーフォーマットを読み込む

Script Editorで設定したAppleScriptの構文色分けのフォーマットを読み込むAppleScriptです。

as_editor.png
▲Piyomaru Softwareが使用しており、本Blogにも反映させている構文色分け設定。似た色でも個別に識別できるよう、わざわざRGB値を微妙に変えてある

このように、Script Editor上で指定したカラー値(R、G、B)、フォント名、フォントサイズ(point)をまとめて返します。

オリジナルはShaneがAppleScript Users MLに投稿したScript(AppleScript Libraries用)だったのですが、普通のAppleScriptで使いやすいように(若干)書き換えました。

同様の機能を持つルーチンをCocoaの機能を使わずに(数年前に)実現していたのですが、このようにまっとうな方法で調査ができるのであれば、安心感がアップします。

# 実際に既存のAppleScript(構文カラーリングを検出して、構文要素区分にもとづいた処理を行うもの)に入れ替えてみたら・・・設定値と実際のカラー値が合わないらしくて、そのままでは使えませんでした。もう少し調べてみる必要があるようで、、、

AppleScript名:AppleScriptのカラーフォーマットを読み込む
– Created 2013-11-11 by Shane Stanley
– Changed 2014-12-14 by Takaaki Naganoya
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

set cList to getAppleScriptSourceColors()
–> {{redValue:145, greenValue:40, blueValue:144, fontName:”Osaka”, fontSize:12.0}, {redValue:95, greenValue:94, blueValue:94, fontName:”Osaka”, fontSize:12.0}, {redValue:14, greenValue:62, blueValue:251, fontName:”Osaka”, fontSize:12.0}, {redValue:120, greenValue:52, blueValue:203, fontName:”Osaka”, fontSize:12.0}, {redValue:252, greenValue:42, blueValue:28, fontName:”Osaka”, fontSize:12.0}, {redValue:0, greenValue:0, blueValue:0, fontName:”Osaka”, fontSize:12.0}, {redValue:145, greenValue:82, blueValue:17, fontName:”Osaka”, fontSize:12.0}, {redValue:0, greenValue:0, blueValue:0, fontName:”Osaka”, fontSize:12.0}, {redValue:39, greenValue:201, blueValue:201, fontName:”Osaka”, fontSize:12.0}, {redValue:15, greenValue:62, blueValue:251, fontName:”Osaka”, fontSize:12.0}, {redValue:31, greenValue:182, blueValue:252, fontName:”Osaka”, fontSize:12.0}, {redValue:129, greenValue:58, blueValue:217, fontName:”Osaka”, fontSize:12.0}, {redValue:93, greenValue:54, blueValue:146, fontName:”Osaka”, fontSize:12.0}, {redValue:9, greenValue:55, blueValue:187, fontName:”Osaka”, fontSize:12.0}, {redValue:8, greenValue:55, blueValue:187, fontName:”Osaka”, fontSize:12.0}, {redValue:9, greenValue:55, blueValue:186, fontName:”Osaka”, fontSize:12.0}, {redValue:86, greenValue:55, blueValue:189, fontName:”Osaka”, fontSize:12.0}, {redValue:52, greenValue:32, blueValue:99, fontName:”Osaka”, fontSize:12.0}}

–AppleScriptの構文色分けのカラー値をRGBで取得する
on getAppleScriptSourceColors()
  
  
– get the info as a dictionary
  
set thePath to current application’s NSString’s stringWithString:“~/Library/Preferences/com.apple.applescript.plist”
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theInfo to current application’s NSDictionary’s dictionaryWithContentsOfFile:thePath
  
  
– extract relevant part and loop through
  
set theArray to (theInfo’s valueForKey:“AppleScriptSourceAttributes”) as list
  
  
set colList to {}
  
  
repeat with i from 1 to count of theArray
    set anEntry to item i of theArray
    
    
set colorData to NSColor of anEntry
    
set theColor to (current application’s NSUnarchiver’s unarchiveObjectWithData:colorData)
    
    
set rVal to round ((theColor’s redComponent()) * 255) rounding down
    
set gVal to round ((theColor’s greenComponent()) * 255) rounding down
    
set bVal to round ((theColor’s blueComponent()) * 255) rounding down
    
    
    
set fontData to NSFont of anEntry
    
set theFont to (current application’s NSUnarchiver’s unarchiveObjectWithData:fontData)
    
    
set aFontName to theFont’s displayName() as text
    
set aFontSize to theFont’s pointSize()
    
    
set aColRec to {redValue:rVal, greenValue:gVal, blueValue:bVal, fontName:aFontName, fontSize:aFontSize}
    
    
set the end of colList to aColRec
  end repeat
  
  
return colList
end getAppleScriptSourceColors

★Click Here to Open This Script