Archive for 12月, 2017

2017/12/30 日本語の慣用句を検索する

オープンソースの「DictionaryKit」(By Mattt)を用いて、「スーパー大辞林」から日本語の慣用句を検索するAppleScriptです。

興味のある方は、DictionaryKitをフレームワーク化したdictKit.frameworkのバイナリをOS X 10.10以降用にビルドしたものをダウンロードして~/Library/Frameworksフォルダに入れておためしください。

–> Download Framework Binary

「血」 → {”血が通う”, “血が騒ぐ”, “血が繫がる”, “血が上る”, “血が引く”, “血で血を洗う”, “血と汗”, “血となり肉となる”, “血に飢える”, “血の出るよう”, “血の滲むよう”, “血は争えない”, “血は水よりも濃い”, “血も涙もない”, “血湧き肉躍る”, “血を受ける”, “血を歃る”, “血を吐く思い”, “血を引く”, “血を見る”, “血を分ける”}

AppleScript名:日本語の慣用句を検索する
– Created 2017-12-30 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “dictKit” –https://github.com/mattt/DictionaryKit
–http://piyocast.com/as/archives/5077

set aRes to retJapaneseIdionFromKanjiChar(“血”) of me
–>  {”血が通う”, “血が騒ぐ”, “血ががる”, “血が上る”, “血が引く”, “血で血を洗う”, “血と汗”, “血となり肉となる”, “血に飢える”, “血の出るよう”, “血の滲むよう”, “血は争えない”, “血は水よりも濃い”, “血も涙もない”, “血湧き肉躍る”, “血を受ける”, “血を歃る”, “血を吐く思い”, “血を引く”, “血を見る”, “血を分ける”}

set aRes to retJapaneseIdionFromKanjiChar(“家”) of me
–>  {”家給し人足る”, “家高し”, “家に杖つく”, “家貧しくして孝子顕わる”, “家をあける”, “家を出ず”, “家を外にする”}

set aRes to retJapaneseIdionFromKanjiChar(“水”) of me
–>  {”水到りて渠成る”, “水が合わない”, “水が漬く”, “水が入る”, “水が引く”, “水涸る”, “水清ければ魚棲まず”, “水澄む”, “水で割る”, “水と油”, “水にする”, “水に流す”, “水になる”, “水に馴れる”, “水温む”, “水の滴るよう”, “水の流れと身のゆくえ”, “水の低きに就く如し”, “水は方円の器に随う”, “水も漏らさぬ”, “水をあける”, “水を打ったよう”, “水を得た魚のよう”, “水を掛ける”, “水をさす”, “水を向ける”}

set aRes to retJapaneseIdionFromKanjiChar(“木”) of me
–>  {”木から落ちた猿”, “樹静かならんと欲すれども風止まず”, “木で鼻を括る”, “木に竹を接ぐ”, “木にも草にも心を置く”, “木に餅がなる”, “木に縁りて魚を求む”, “木の股から生まれる”, “木六竹八塀十郎”, “木を見て森を見ず”}

on retJapaneseIdionFromKanjiChar(aKanji)
  set aDictionary to (current application’s TTTDictionary’s dictionaryNamed:“スーパー大辞林”)
  
set hitEntryList to (aDictionary’s entriesForSearchTerm:aKanji) as list
  
if hitEntryList is not equal to {missing value} then
    
    
repeat with ii in hitEntryList
      set j to contents of ii
      
      
set headW to (j’s headword)
      
set headW to headW as text
      
      
try
        set aText to (j’s |text|)
        
set aText to aText as text
      on error
        set aText to (j’s HTML)
        
set aText to decodeCharacterReference(aText) of me
      end try
      
      
if aText contains “〈句項目〉” then
        set aCount to 1
        
set tmpList to paragraphs of aText
        
set aLen to length of tmpList
        
        
repeat with i in tmpList
          set j to contents of i
          
if j contains “〈句項目〉” then
            set outList to items (aCount + 1) thru -1 of tmpList
            
exit repeat
          end if
          
set aCount to aCount + 1
        end repeat
        
        
repeat with ii from (aCount + 1) to aLen
          set jj to contents of ii
          
if jj = “” then exit repeat
        end repeat
        
        
set outList to contents of items (aCount + 1) thru (ii - 1) of tmpList
        
return outList
      end if
    end repeat
    
    
return {}
  end if
end retJapaneseIdionFromKanjiChar

on decodeCharacterReference(aStr)
  set anNSString to current application’s NSString’s stringWithString:aStr
  
set theData to anNSString’s dataUsingEncoding:(current application’s NSUTF16StringEncoding)
  
set styledString to current application’s NSAttributedString’s alloc()’s initWithHTML:theData documentAttributes:(missing value)
  
set plainText to (styledString’s |string|()) as string
  
return plainText
end decodeCharacterReference

★Click Here to Open This Script 

2017/12/29 任意の2色の色差ΔEを求める

オープンソースの「Colours」(By Ben Gordon)をフレームワーク化したcolorsKitを呼び出して、指定の2色の色差(ΔE)を計算するAppleScriptです。

色差を求めるためには、RGB→XYZ→L*a*b*と変換する必要があるわけですが、Colours内で計算してくれます。本ScriptではAppleScriptのchoose colorコマンドの実行結果をCocoaの色データに変換してColours内のメソッドを呼び出しています。

実行には、colorsKit.frameworkのインストールを必要とします。アーカイブをダウンロードして、~/Library/Frameworksフォルダに入れてください(あくまで自己責任で)。

–> Download Framework Binary

AppleScript名:任意の2色の色差ΔEを求める
– Created 2017-12-29 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “colorsKit” –https://github.com/bennyguitar/Colours
use framework “AppKit”
–http://piyocast.com/as/archives/5075

property NSColor : a reference to current application’s NSColor

set aASCol to choose color
set bASCol to choose color

set aCocoaList to retCocoaColorList(aASCol, 65535) of me
set bCocoaList to retCocoaColorList(bASCol, 65535) of me

set aCol to NSColor’s colorFromRGBAArray:aCocoaList
set bCol to NSColor’s colorFromRGBAArray:bCocoaList

set aDist to aCol’s distanceFromColor:bCol type:2 –ColorDistanceCIE2000

return aDist

–Convert “choose color” RGB list (0-65535) to Cocoa color RGBA Array (0.0-1.0)
on retCocoaColorList(aColorList, aMax)
  set cocoaColorList to {}
  
repeat with i in aColorList
    set the end of cocoaColorList to i / aMax
  end repeat
  
set the end of cocoaColorList to 1.0
  
return cocoaColorList
end retCocoaColorList

★Click Here to Open This Script 

2017/12/28 iBooksライブラリ中のepubファイルからメタ情報を取得 v3

iBooksライブラリ中のbook(ePub)ファイルからメタ情報(属性情報)を取得するAppleScriptです。

iBooks.app自体はまったくScriptableでもなんでもないですが、ライブラリ内の各ファイルから直接情報を取得できます。各book書類はread onlyなうえに本文の内容は暗号化されているので、この程度で問題ないでしょう。

実行にはShane StanleyのAppleScriptライブラリ「Metadata Lib」のインストールが必要です。

AppleScript名:iBooksライブラリ中のepubファイルから情報を取得 v3
– Created 2017/02/26 by Christopher Stone
– Modified 2017/11/01 by Takaaki Naganoya
use framework “Foundation”
use scripting additions
use mdLib : script “Metadata Lib” version “1.0.0″
–http://piyocast.com/as/archives/5074

property NSString : a reference to current application’s NSString
property NSMutableArray : a reference to current application’s NSMutableArray
property NSPropertyListFormat : a reference to current application’s NSPropertyListFormat
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSPropertyListImmutable : a reference to current application’s NSPropertyListImmutable
property NSPropertyListSerialization : a reference to current application’s NSPropertyListSerialization

set aPath to POSIX path of (path to library folder from user domain)
set sourceFolder to aPath & “Containers/com.apple.BKAgentService/Data/Documents/iBooks/Books/”

set textFiles to mdLib’s searchFolders:{sourceFolder} searchString:“kMDItemContentType contains %@ || kMDItemContentType contains %@ “ searchArgs:{“com.apple.ibooks-folder”, “org.idpf.epub-container”}

set outDicList to NSMutableArray’s new()
repeat with i in textFiles
  set aFile to (i as string)
  
  
if aFile ends with “/” then
    set aFullPath to aFile & “iTunesMetadata.plist”
  else
    set aFullPath to aFile & “/iTunesMetadata.plist”
  end if
  
  
try
    set xmlData to read ((POSIX file aFullPath) as alias) as «class utf8»
    
set xRes to readPlistFromStr(xmlData) of me
    
log xRes as list of string or string –as anything (maybe record or missing value)
    
    
(*cover-writing-mode:vertical, genre:教育, scroll-axis:default, sort-artist:あっぷる, BKITunesMigratedMetadata:PersistentID:6.68315366592803E+18, seriesTitle:Everyone Can Code, sort-name:Swiftによるあぷりけーしょん開発:入門編, itemId:1209648719, apple-id:xxxxxxxxxxxx@xxx.xxx, fileExtension:ibooks, year:2017, releaseDate:2017-03-19T07:00:00Z, BKInsertionDate:512115887, asset-info:flavor:pluspub, file-size:60642970, book-info:publication-version:162901775, PageProgression:default, asset-info:flavor:pluspub, file-size:60642970, package-file-hash:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX, BKAllocatedSize:82993152, longDescription:このコースでは、Swiftという言語を使って基本的なプログラミングの土台をしっかりと作り上げていきます。基本的なiOSアプリケーションを一から開発するために必要なツール、手法、概念を活用して、実践的な練習に取り組みます。さらに、プログラミングと優れたアプリケーション開発の土台となる、ユーザーインターフェイス設計の基本原則についても学習します。このコースを受講するにあたってプログラミングの経験は必要ありません。プログラミングの経験がある場合、レッスンの最初の方は簡単に読み進めていただくとよいでしょう。このブックではプログラミングの基礎にとどまらず、ソフトウェア開発ツールや概念、ベストプラクティスについても学習できます。, artistId:9.39801385E+8, artistName:Apple Education, isPreview:false, BKDisplayName:mzbf.eqmpijqw..d2.dlv.d2.dlv.ibooks, human-friendly-publication-version:1.1, shouldDisableTouchEmulation:true, vendorId:379015, drmVersionNumber:0, kind:ebook, s:143462, genreId:10037, explicit:2, seriesAdamId:1.118575554E+9, publisher:Apple Inc. - Education, versionRestrictions:16843008, BKGenerationCount:2, desktopSupportLevel:supported, primaryLanguage:ja, itemName:Swiftによるアプリケーション開発:入門編, purchaseDate:2017-03-25T06:21:26Z, shouldDisableOptimizeSpeed:true, obeyPageBreaks:1, pageCount:244*)
    
if xRes is not equal to missing value then
      (outDicList’s addObject:xRes)
    end if
  end try
end repeat

return outDicList as list of string or string –as anything

–stringのplistを読み込んでNSDictionaryに
on readPlistFromStr(theString)
  set aSource to NSString’s stringWithString:theString
  
set pListData to aSource’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aPlist to NSPropertyListSerialization’s propertyListFromData:pListData mutabilityOption:(NSPropertyListImmutable) |format|:(NSPropertyListFormat) errorDescription:(missing value)
  
return aPlist
end readPlistFromStr

★Click Here to Open This Script 

2017/12/26 TextEditで最前面のドキュメント内で使用されている色情報を抽出して処理対象色を選択

テキストエディット上で色をつけた箇所を抽出して、ポップアップメニューから対象色を選択し、指定の色の箇所のテキストを取り出すAppleScriptです。

textedit1_resized.png

Mac標準搭載のテキストエディタ「テキストエディット」はAppleScriptからコントロールできるため、行数や文字数を数えるという原始的な処理はもちろんのこと、赤く色をつけた箇所のみを抽出するとかフォントを変更した箇所だけを抽出するといった高度な「AppleScriptらしい」処理が可能です。

黒以外の色が指定された文字の箇所を抽出するAppleScriptにポップアップメニューを動的に生成する機能を付加して、抽出対象色を自由に指定できるようにしてみました。

テキストエディタ上でリッチテキストモードの書類をオープンして一部に色をつけた状態で、AppleScriptをスクリプトエディタ上でControl-Command-Rにより実行します。

Scriptの大部分は動的にWindowとボタンとポップアップメニューを生成、およびクリック時のイベントを処理するためのもので、テキストエディットと通信を行なって書式情報や文字列を取得する部分はごく一部です。

textedit2.png

textedit3.png

textedit4.png

AppleScript名:TextEditで最前面のドキュメント内で使用されている色情報を抽出して処理対象色を選択
– Created 2017-12-26 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “Carbon” – AEInteractWithUser() is in Carbon
–http://piyocast.com/as/archives/5071

property NSView : a reference to current application’s NSView
property NSColor : a reference to current application’s NSColor
property NSArray : a reference to current application’s NSArray
property NSMenu : a reference to current application’s NSMenu
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property NSTextField : a reference to current application’s NSTextField
property NSMenuItem : a reference to current application’s NSMenuItem
property NSBezierPath : a reference to current application’s NSBezierPath
property NSPopUpButton : a reference to current application’s NSPopUpButton
property NSWindowController : a reference to current application’s NSWindowController
property NSTitledWindowMask : a reference to current application’s NSTitledWindowMask
property NSRoundedBezelStyle : a reference to current application’s NSRoundedBezelStyle
property NSNormalWindowLevel : a reference to current application’s NSNormalWindowLevel
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton

property windisp : false

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

tell application “TextEdit”
  set dCount to count every document
  
if dCount = 0 then return
  
tell text of front document
    set aList to color of every character
  end tell
end tell

–1D/2D Listのユニーク化
set ap1List to uniquify1DList(aList, true) of me

–色選択ダイアログを表示してポップアップメニューから色選択
set aButtonMSG to “OK”
set aWindowTitle to “Choose Color”

set aVal to getPopupValues(ap1List, 65535, aButtonMSG, aWindowTitle, 180) of me

if (aVal = false) or (aVal = missing value) then
  display dialog “No Selection” buttons {“OK”} default button 1 with icon 2
  
return
end if

set targColor to item aVal of ap1List
set aRes to pickupColoredText(targColor) of me
set the clipboard to aRes –抽出結果をクリップボードへ
return aRes

on getPopupValues(ap1List, aColMax, aButtonMSG, aWindowMSG, timeOutSecs)
  
  
set (my windisp) to true
  
  
set aView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 360, 100))
  
  
–Labelをつくる
  
set a1TF to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(30, 60, 80, 20))
  
a1TF’s setEditable:false
  
a1TF’s setStringValue:“Color:”
  
a1TF’s setDrawsBackground:false
  
a1TF’s setBordered:false
  
  
–Ppopup Buttonをつくる
  
set a1Button to NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 60, 200, 20)) pullsDown:false
  
a1Button’s removeAllItems()
  
  
set a1Menu to NSMenu’s alloc()’s init()
  
  
set iCount to 1
  
repeat with i in ap1List
    copy i to {r1, g1, b1}
    
    
set nsCol to makeNSColorFromRGBAval(r1, g1, b1, aColMax, aColMax) of me
    
set anImage to makeNSImageWithFilledWithColor(64, 64, nsCol) of me
    
    
set aTitle to “Color_” & (iCount as string)
    
set aMenuItem to (NSMenuItem’s alloc()’s initWithTitle:aTitle action:“actionHandler:” keyEquivalent:“”)
    (
aMenuItem’s setImage:anImage)
    (
aMenuItem’s setEnabled:true)
    (
a1Menu’s addItem:aMenuItem)
    
    
set iCount to iCount + 1
  end repeat
  
  
a1Button’s setMenu:a1Menu
  
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 10, 140, 40)))
  
bButton’s setButtonType:(current application’s NSMomentaryLightButton)
  
bButton’s setBezelStyle:(current application’s NSRoundedBezelStyle)
  
bButton’s setTitle:aButtonMSG
  
bButton’s setTarget:me
  
bButton’s setAction:(“clicked:”)
  
bButton’s setKeyEquivalent:(return)
  
  
aView’s addSubview:a1TF
  
  
aView’s addSubview:a1Button
  
aView’s addSubview:bButton
  
aView’s setNeedsDisplay:true
  
  
–NSWindowControllerを作ってみた
  
set aWin to (my makeWinWithView(aView, 300, 100, aWindowMSG))
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
  
wController’s showWindow:me
  
  
set aCount to timeOutSecs * 100
  
  
set hitF to false
  
repeat aCount times
    if (my windisp) = false then
      set hitF to true
      
exit repeat
    end if
    
delay 0.01
    
set aCount to aCount - 1
  end repeat
  
  
my closeWin:aWin
  
  
if hitF = true then
    set s1Val to (a1Button’s indexOfSelectedItem() as integer) + 1
  else
    set s1Val to false
  end if
  
  
return s1Val
  
end getPopupValues

on clicked:aSender
  set (my windisp) to false
end clicked:

–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 current application’s NSTitledWindowMask
  
  
set aDefer to current application’s NSBackingStoreBuffered
  
  
– Window
  
set aWin to 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 setReleasedWhenClosed:true
  
aWin’s |center|()
  
–aWin’s makeKeyAndOrderFront:(me)
  
  
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:

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

on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

–1D Listをユニーク化
on uniquify1DList(theList as list, aBool as boolean)
  set aArray to NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:“@distinctUnionOfObjects.self”
  
set bList to bArray as list
  
return bList
end uniquify1DList

–指定サイズのNSImageを作成し、指定色で塗って返す
on makeNSImageWithFilledWithColor(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 makeNSImageWithFilledWithColor

on pickupColoredText(aColList)
  set outStrList to “”
  
  
tell application “TextEdit”
    tell text of front document
      set colorList to color of every attribute run
      
set textList to characters of every attribute run
      
      
set aCount to length of colorList
      
      
repeat with i from 1 to aCount
        set aColCon to item i of colorList
        
if aColCon is equal to aColList then –指定色の箇所
          set outStrList to outStrList & ((contents of item i of textList) as string) & return
        end if
      end repeat
      
    end tell
  end tell
  
  
return outStrList
end pickupColoredText

★Click Here to Open This Script 

2017/12/26 Numbersから緯度経度情報を取得して地図にプロット v3

Numbersでオープン中の書類の現在選択中のシートにある表の内容を読み取って、MKMapViewの地図にピンで位置をプロットして表示するAppleScriptです。

実行にはShane StanleyのAppleScriptライブラリ「BridgePlus」のインストールを必要とします。

実行時にはNumbersで「ピン名称」「緯度」「経度」のデータをオープンしておく必要があります。

→ sample data (Numbers)

実行にはスクリプトエディタ上でControlーCommandーRを実行してください。

前バージョンからは、

  Pinデータ作成時にプログレスバーを表示
  地図種別切り替え

を追加してみました。680箇所の位置データをプロットさせてみたら10秒程度かかったので、プログレスバーを表示させたらいい感じでした。

map40_resized.png

map41_resized.png

map42_resized.png

map43_resized.png

AppleScript名:Numbersから緯度経度情報を取得して地図にプロット v3(プログレスバー+セグメント)
– Created 2017-12-20 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “MapKit”
use framework “CoreLocation”
use bPlus : script “BridgePlus”
–http://piyocast.com/as/archives/5065

property NSView : a reference to current application’s NSView
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property SMSForder : a reference to current application’s SMSForder
property NSWindow : a reference to current application’s NSWindow
property MKMapView : a reference to current application’s MKMapView
property MKMapTypeHybrid : a reference to current application’s MKMapTypeHybrid
property MKPointAnnotation : a reference to current application’s MKPointAnnotation
property MKMapTypeSatellite : a reference to current application’s MKMapTypeSatellite
property NSWindowController : a reference to current application’s NSWindowController
property NSTitledWindowMask : a reference to current application’s NSTitledWindowMask
property MKMapTypeStandard : a reference to current application’s MKMapTypeStandard
property NSSegmentedControl : a reference to current application’s NSSegmentedControl
property NSNormalWindowLevel : a reference to current application’s NSNormalWindowLevel
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSSegmentStyleTexturedRounded : a reference to current application’s NSSegmentStyleTexturedRounded

property windisp : false
property selSeg : 0
property aMapView : missing value

–データを取得する
set locList to getDataFromNumbersDoc() of me

set aWidth to 800
set aHeight to 600

set segTitleList to {“Map”, “Satellite”, “Satellite + Map”}
set tableTitle to retCurNumbersDocsTableName() of me
dispMapView(aWidth, aHeight, tableTitle, “OK”, 180, locList, segTitleList) of me

on dispMapView(aWidth as integer, aHeight as integer, aTitle as text, aButtonMSG as text, timeOutSecs as number, locList, segTitleList)
  –Check If this script runs in foreground
  
if not (current application’s NSThread’s isMainThread()) as boolean then
    error “This script must be run from the main thread (Command-Control-R in Script Editor).”
  end if
  
  
set selSeg to 0
  
set (my windisp) to true
  
  
  
  
–NSViewをつくる
  
set aNSView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aHeight, aWidth))
  
  
aNSView’s setNeedsDisplay:true
  
  
set aWin to makeWinWithView(aNSView, aWidth, aHeight, aTitle, 1.0)
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
wController’s showWindow:me
  
aWin’s makeKeyAndOrderFront:me –Windowを表示状態に
  
  
  
–Progress Barをつくる
  
set aPBar to current application’s NSProgressIndicator’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 40, aWidth, 40))
  
aPBar’s setMaxValue:(length of locList)
  
aPBar’s setMinValue:1
  
aPBar’s setIndeterminate:false
  
aPBar’s setControlSize:(current application’s NSProgressIndicatorPreferredLargeThickness)
  
aPBar’s setDoubleValue:(1.0 as real)
  
aNSView’s addSubview:aPBar
  
  
  
–MKMapViewをつくる
  
set aMapView to MKMapView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 40, aWidth, aHeight - 40))
  
aMapView’s setMapType:(current application’s MKMapTypeStandard)
  
  
aMapView’s setZoomEnabled:true
  
aMapView’s setScrollEnabled:true
  
aMapView’s setPitchEnabled:true
  
aMapView’s setRotateEnabled:false
  
aMapView’s setShowsCompass:true
  
aMapView’s setShowsZoomControls:true
  
aMapView’s setShowsScale:true
  
aMapView’s setShowsUserLocation:true
  
aMapView’s setDelegate:me
  
  
  
–MapにPinを追加
  
set aCount to 1
  
repeat with i in locList
    (aPBar’s setDoubleValue:(aCount as real)) –Update Progress Bar
    
    
copy i to {tmpAdr, tmpLat, tmpLong}
    
    
set aLocation to current application’s CLLocationCoordinate2DMake(tmpLat, tmpLong)
    
set anAnnotation to MKPointAnnotation’s alloc()’s init()
    (
anAnnotation’s setCoordinate:aLocation)
    (
anAnnotation’s setTitle:tmpAdr)
    (
aMapView’s addAnnotation:anAnnotation)
    
    
set aCount to aCount + 1
  end repeat
  
aPBar’s removeFromSuperview() –Remove Progress Bar
  
  
–Segmented Controlをつくる
  
set aSeg to makeSegmentedControl(segTitleList, aWidth, aHeight) of me
  
aNSView’s addSubview:aSeg
  
  
–MapViewをWindow上に表示  
  
copy middle item of locList to {tmpAdr, tmpLat, tmpLong}
  
set aLocation to current application’s CLLocationCoordinate2DMake(tmpLat, tmpLong)
  
aMapView’s setCenterCoordinate:aLocation zoomLevel:7 animated:false
  
aNSView’s addSubview:aMapView
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(aWidth - 100, 0, 100, 40)))
  
bButton’s setTitle:aButtonMSG
  
bButton’s setButtonType:(current application’s NSMomentaryLightButton)
  
bButton’s setBezelStyle:(current application’s NSRoundedBezelStyle)
  
bButton’s setKeyEquivalent:(return)
  
bButton’s setTarget:me
  
bButton’s setAction:(“clicked:”)
  
aNSView’s addSubview:bButton
  
  
aWin’s makeFirstResponder:aMapView
  
  
set aCount to timeOutSecs * 10 –timeout seconds * 10
  
repeat aCount times
    if (my windisp) = false then
      exit repeat
    end if
    
delay 0.1
  end repeat
  
  
my closeWin:aWin
  
end dispMapView

–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 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 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 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:

on makeSegmentedControl(titleList, aWidth, aHeight)
  set aLen to length of titleList
  
  
set aSeg to NSSegmentedControl’s alloc()’s init()
  
aSeg’s setSegmentCount:aLen
  
  
set aCount to 0
  
repeat with i in titleList
    set j to contents of i
    (
aSeg’s setLabel:j forSegment:aCount)
    
set aCount to aCount + 1
  end repeat
  
  
aSeg’s setTranslatesAutoresizingMaskIntoConstraints:false
  
aSeg’s setSegmentStyle:(NSSegmentStyleTexturedRounded)
  
aSeg’s setFrame:(current application’s NSMakeRect(10, 5, 260, 30))
  
aSeg’s setTrackingMode:0
  
aSeg’s setTarget:me
  
aSeg’s setAction:“clickedSeg:”
  
aSeg’s setSelectedSegment:0
  
  
return aSeg
end makeSegmentedControl

–Numbersでオープン中の書類の選択中のシートの表1からデータを取得して2D Listに
on getDataFromNumbersDoc()
  
  
load framework
  
  
tell application “Numbers”
    if (count every document) = 0 then return false
    
    
tell front document
      if (count every sheet) = 0 then return false
      
      
tell active sheet
        tell table 1
          set colCount to column count
          
set rowCount to row count
          
set headerCount to header row count
          
set footerCount to footer row count
          
          
set dList to value of every cell of cell range
        end tell
      end tell
      
    end tell
  end tell
  
  
–Convert 1D List to 2D List
  
set bList to (SMSForder’s subarraysFrom:dList groupedBy:colCount |error|:(missing value)) as list
  
set sItem to 1 + headerCount
  
set eItem to rowCount - footerCount
  
set cList to items sItem thru eItem of bList
  
  
return cList
  
end getDataFromNumbersDoc

on retCurNumbersDocsTableName()
  tell application “Numbers”
    tell front document
      tell active sheet
        tell table 1
          return name
        end tell
      end tell
    end tell
  end tell
end retCurNumbersDocsTableName

on clickedSeg:aSender
  set aSel to aSender’s selectedSegment()
  
set selSeg to (aSel + 1)
  
set mapList to {MKMapTypeStandard, MKMapTypeSatellite, MKMapTypeHybrid}
  
set curMap to contents of item selSeg of mapList
  
aMapView’s setMapType:(curMap)
end clickedSeg:

★Click Here to Open This Script 

2017/12/25 Segmented Controlを表示する

NSSegmentedControlを表示して選択されたSegmentのID(+1)を返すAppleScriptです。

segcontrol_resized.png

スクリプトエディタ上でControl-Command-Rと操作すると実行できます。

Xcode上でAppleScriptのアプリケーションを作っていると、とても使用頻度の高いNSSegmentedControlですが、スクリプトエディタ上で使うかどうかは不明です。

AppleScript名:Segmented Controlを表示する
– Created 2017-12-20 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “AppKit”
–http://piyocast.com/as/archives/5059

property NSView : a reference to current application’s NSView
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property NSWindowController : a reference to current application’s NSWindowController
property NSSegmentedControl : a reference to current application’s NSSegmentedControl

property windisp : false
property selSeg : 0

set aWidth to 500
set aHeight to 100

set segTitleList to {“First Segment”, “Second Segment”, “Third Segment”, “Forth Segment”}

set aRes to dispSegControl(aWidth, aHeight, “Segemented Control”, “OK”, 180, segTitleList) of me

on dispSegControl(aWidth as integer, aHeight as integer, aTitle as text, aButtonMSG as text, timeOutSecs as number, segTitleList)
  
  
–Check If this script runs in foreground
  
if not (current application’s NSThread’s isMainThread()) as boolean then
    error “This script must be run from the main thread (Command-Control-R in Script Editor).”
  end if
  
  
set selSeg to 0
  
set (my windisp) to true
  
  
–Segmented Controlをつくる
  
set aSeg to makeSegmentedControl(segTitleList, aWidth, aHeight) of me
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(aWidth / 4, 0, aWidth / 2, 40)))
  
bButton’s setTitle:aButtonMSG
  
bButton’s setButtonType:(current application’s NSMomentaryLightButton)
  
bButton’s setBezelStyle:(current application’s NSRoundedBezelStyle)
  
bButton’s setKeyEquivalent:(return)
  
bButton’s setTarget:me
  
bButton’s setAction:(“clicked:”)
  
  
–NSViewをつくる
  
set aNSV to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aHeight, aWidth))
  
aNSV’s addSubview:aSeg
  
aNSV’s addSubview:bButton
  
aNSV’s setNeedsDisplay:true
  
  
set aWin to makeWinWithView(aNSV, aWidth, aHeight, aTitle, 1.0)
  
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
wController’s showWindow:me
  
  
aWin’s makeKeyAndOrderFront:me
  
  
set aCount to timeOutSecs * 10 –timeout seconds * 10
  
repeat aCount times
    if (my windisp) = false then
      exit repeat
    end if
    
delay 0.1
  end repeat
  
  
my closeWin:aWin
  
  
return (selSeg + 1)
end dispSegControl

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

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

–make Window for Input
on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle, alphaV)
  set aScreen to NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
set aBacking to current application’s NSTitledWindowMask
  
set aDefer to current application’s NSBackingStoreBuffered
  
  
– Window
  
set aWin to NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
  
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:

on makeSegmentedControl(titleList, aWidth, aHeight)
  set aLen to length of titleList
  
  
set aSeg to NSSegmentedControl’s alloc()’s init()
  
aSeg’s setSegmentCount:aLen
  
  
set aCount to 0
  
repeat with i in titleList
    set j to contents of i
    (
aSeg’s setLabel:j forSegment:aCount)
    
set aCount to aCount + 1
  end repeat
  
  
aSeg’s setTranslatesAutoresizingMaskIntoConstraints:false
  
aSeg’s setSegmentStyle:(current application’s NSSegmentStyleTexturedRounded)
  
aSeg’s setFrame:(current application’s NSMakeRect(20, aHeight - 60, aWidth, aHeight - 40))
  
aSeg’s setTrackingMode:0
  
aSeg’s setTarget:me
  
aSeg’s setAction:“clickedSeg:”
  
aSeg’s setSelectedSegment:0
  
  
return aSeg
end makeSegmentedControl

★Click Here to Open This Script 

2017/12/25 Bitcoin Exchange Rates APIを呼び出す

Bitcoin Exchange Rates APIを呼び出すAppleScriptです。

処理結果をNSDictionaryのままにして(recordに変換せずに)おいてありますが、これは”15m:”というラベルの値がrecordだと取り出せない(数字ではじまるラベルを許容していない)ためで、valueForKeyなどのメソッドでNSDictionaryから取り出す必要があります。

AppleScript名:Bitcoin Exchange Rates APIを呼び出す
– Created 2017-12-11 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/5058

property |NSURL| : a reference to current application’s |NSURL|
property NSData : a reference to current application’s NSData
property NSJSONSerialization : a reference to current application’s NSJSONSerialization

set aInfo to getBitcoinExchangeRating() of me
set aVal to (aInfo’s valueForKeyPath:"JPY")
–>  (NSDictionary) {15m:1483814.35, sell:1483366.93, symbol:"\", last:1483814.35, buy:1484261.76}

on getBitcoinExchangeRating()
  try
    with timeout of 10 seconds
      set link to "https://blockchain.info/ja/ticker" –Exchange Rates API
      
set theURL to |NSURL|’s URLWithString:link
      
set jsonData to NSData’s dataWithContentsOfURL:theURL
      
set aJsonDict to (NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value))
      
return aJsonDict
    end timeout
  on error
    return missing value
  end try
end getBitcoinExchangeRating

★Click Here to Open This Script 

2017/12/23 Numbersから緯度経度情報を取得して地図にプロット

Numbersでオープン中の書類の現在選択中のシートにある表の内容を読み取って、MKMapViewの地図にピンで位置をプロットして表示するAppleScriptです。

map23_resized.png

スクリーンショット例は「戦場の絆」の導入されているゲームセンターの住所から緯度・経度情報を求めて本Scriptで地図表示させたものです。

Numbersの表示中のシート中の表からデータを読み取るわけですが、「ピンのタイトル」「緯度(Latitude)」「経度(Longitude)」でデータが構成されている必要があります。読み取り時にはとくにNumbers上でセルを選択しておく必要はありません。

→ sample data (Numbers)

map20_resized.png

実行にはShane StanleyのAppleScriptライブラリ「BridgePlus」のインストールを必要とします。

map21_resized.png

Numbersで「ピンのタイトル」「緯度(Latitude)」「経度(Longitude)」がセットになったデータをオープンした状態で、スクリプトエディタ上でControl-Command-Rと操作すると実行できます。

map30_resized.png

Script Menuに入れて実行することも可能ですが、その場合にはボタンをクリックさせてウィンドウをクローズすることができません。

map22_resized.png

AppleScript名:Numbersから緯度経度情報を取得して地図にプロット
– Created 2017-12-20 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “MapKit”
use framework “CoreLocation”
use bPlus : script “BridgePlus”
–http://piyocast.com/as/archives/5051

property |NSURL| : a reference to current application’s |NSURL|
property NSData : a reference to current application’s NSData
property NSView : a reference to current application’s NSView
property NSString : a reference to current application’s NSString
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property MKMapView : a reference to current application’s MKMapView
property NSURLRequest : a reference to current application’s NSURLRequest
property NSURLConnection : a reference to current application’s NSURLConnection
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSWindowController : a reference to current application’s NSWindowController
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

property windisp : false

–データを取得する
set locList to getDataFromNumbersDoc() of me

set aWidth to 800
set aHeight to 500

dispMapView(aWidth, aHeight, “Result”, “OK”, 180, locList) of me

on dispMapView(aWidth as integer, aHeight as integer, aTitle as text, aButtonMSG as text, timeOutSecs as number, locList)
  
  
–Check If this script runs in foreground
  
if not (current application’s NSThread’s isMainThread()) as boolean then
    error “This script must be run from the main thread (Command-Control-R in Script Editor).”
  end if
  
  
set (my windisp) to true
  
  
–MKMapViewをつくる
  
set aMapView to MKMapView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 40, aWidth, aHeight - 40))
  
aMapView’s setMapType:(current application’s MKMapTypeStandard)
  
  
aMapView’s setZoomEnabled:true
  
aMapView’s setScrollEnabled:true
  
aMapView’s setPitchEnabled:true
  
aMapView’s setRotateEnabled:false
  
aMapView’s setShowsCompass:true
  
aMapView’s setShowsZoomControls:true
  
aMapView’s setShowsScale:true
  
aMapView’s setShowsUserLocation:true
  
aMapView’s setDelegate:me
  
  
  
–MapにPinを追加
  
repeat with i in locList
    copy i to {tmpAdr, tmpLat, tmpLong}
    
    
set aLocation to current application’s CLLocationCoordinate2DMake(tmpLat, tmpLong)
    
set anAnnotation to current application’s MKPointAnnotation’s alloc()’s init()
    (
anAnnotation’s setCoordinate:aLocation)
    (
anAnnotation’s setTitle:tmpAdr)
    (
aMapView’s addAnnotation:anAnnotation)
  end repeat
  
  
copy middle item of locList to {tmpAdr, tmpLat, tmpLong}
  
set aLocation to current application’s CLLocationCoordinate2DMake(tmpLat, tmpLong)
  
aMapView’s setCenterCoordinate:aLocation zoomLevel:7 animated:false
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(aWidth / 4, 0, aWidth / 2, 40)))
  
bButton’s setTitle:aButtonMSG
  
bButton’s setButtonType:(current application’s NSMomentaryLightButton)
  
bButton’s setBezelStyle:(current application’s NSRoundedBezelStyle)
  
bButton’s setKeyEquivalent:(return)
  
bButton’s setTarget:me
  
bButton’s setAction:(“clicked:”)
  
  
–SplitViewをつくる
  
set aSplitV to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aHeight, aWidth))
  
aSplitV’s addSubview:aMapView
  
aSplitV’s addSubview:bButton
  
aSplitV’s setNeedsDisplay:true
  
  
set aWin to makeWinWithView(aSplitV, aWidth, aHeight, aTitle, 1.0)
  
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
aWin’s makeFirstResponder:aMapView
  
wController’s showWindow:me
  
  
aWin’s makeKeyAndOrderFront:me
  
  
set aCount to timeOutSecs * 10 –timeout seconds * 10
  
repeat aCount times
    if (my windisp) = false then
      exit repeat
    end if
    
delay 0.1
  end repeat
  
  
my closeWin:aWin
  
end dispMapView

–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 NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
set aBacking to current application’s NSTitledWindowMask
  
set aDefer to current application’s NSBackingStoreBuffered
  
  
– Window
  
set aWin to NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
  
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:

–Numbersでオープン中の書類の選択中のシートの表1からデータを取得して2D Listに
on getDataFromNumbersDoc()
  
  
load framework
  
  
tell application “Numbers”
    if (count every document) = 0 then return false
    
    
tell front document
      if (count every sheet) = 0 then return false
      
      
tell active sheet
        tell table 1
          set colCount to column count
          
set rowCount to row count
          
set headerCount to header row count
          
set footerCount to footer row count
          
          
set dList to value of every cell of cell range
        end tell
      end tell
      
    end tell
  end tell
  
  
–Convert 1D List to 2D List
  
set bList to (current application’s SMSForder’s subarraysFrom:dList groupedBy:colCount |error|:(missing value)) as list
  
set sItem to 1 + headerCount
  
set eItem to rowCount - footerCount
  
set cList to items sItem thru eItem of bList
  
  
return cList
  
end getDataFromNumbersDoc

★Click Here to Open This Script 

2017/12/21 指定IPアドレスの情報を取得してMKMapViewで表示 v3

指定のIPアドレスの情報をfreegeoip.netのREST APIを呼び出して取得し、緯度、経度情報からMKMapViewで地図を表示するAppleScriptの改良版です。

map10.png

map11.png

map12.png

フロントエンドプロセスで実行する必要があるため、スクリプトエディタ上でControl+Command-Rで実行します。

指定位置をピンで表示していますが、とくにピンを落とすアニメーションは不要と考えて省略しています。ほかにも、不要なアニメーションを省略しています。

AppleScriptのワークフローで地図を表示させる必然性は高くありません。指定場所から半径500m以内に存在する施設を検索するなどの計算を行なって、結果を表示させるぐらいでしょうか。ただ、スマートフォンではないので大量に位置座標の計算や表示を行なってもネットワークやCPUがへこたれないため、いくらでも計算できます。

インタラクティブに地図を表示するMLMapViewよりも、地図画像を取得するMKMapSnapshotterの方が合っているかもしれません。ただ、MKMapSnapshotterの呼び出しはBlocks構文が必要なようなので(=AppleScriptから呼べないので)、ちょっと手をつけていません。

AppleScript名:指定IPアドレスの情報を取得してMKMapViewで表示 v3
– Created 2015-12-11 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “MapKit”
use framework “CoreLocation”
–http://piyocast.com/as/archives/5050

property |NSURL| : a reference to current application’s |NSURL|
property NSData : a reference to current application’s NSData
property NSView : a reference to current application’s NSView
property NSString : a reference to current application’s NSString
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property MKMapView : a reference to current application’s MKMapView
property NSURLRequest : a reference to current application’s NSURLRequest
property NSURLConnection : a reference to current application’s NSURLConnection
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSWindowController : a reference to current application’s NSWindowController
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

property windisp : false

set nRes to hasInternetConnection() of me
if nRes = false then
  display dialog “No Internet Connection….” buttons {“OK”} default button 1 with icon 0
  
return
end if

set aClip to the clipboard
set anIP to text returned of (display dialog “Input IP address to find its location” default answer aClip)

–Check If this script runs in foreground
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 windisp to false
set aInfo to getIPAddressInfoFreeGeoIP(anIP) of me

if aInfo = missing value then
  display dialog “Network Error”
  
return
end if

set aLong to (longitude of (aInfo as record)) as real
set aLat to (latitude of (aInfo as record)) as real
set aZip to zip_code of (aInfo as record)

set aWidth to 450
set aHeight to 500

set aButtonMSG to “OK”

dispMapView(aWidth, aHeight, “MKMapView TEST v3″, aButtonMSG, 180, aLat, aLong) of me

on dispMapView(aWidth as integer, aHeight as integer, aTitle as text, aButtonMSG as text, timeOutSecs as number, aLat, aLong)
  
  
set (my windisp) to true
  
  
–MKMapViewをつくる
  
set aMapView to MKMapView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 40, aWidth, aHeight - 40))
  
aMapView’s setMapType:(current application’s MKMapTypeStandard)
  
  
aMapView’s setZoomEnabled:true
  
aMapView’s setScrollEnabled:true
  
aMapView’s setPitchEnabled:true
  
aMapView’s setRotateEnabled:true
  
aMapView’s setShowsCompass:true
  
aMapView’s setShowsZoomControls:true
  
aMapView’s setShowsScale:true
  
aMapView’s setShowsUserLocation:true
  
  
set aLocation to current application’s CLLocationCoordinate2DMake(aLat, aLong)
  
aMapView’s setCenterCoordinate:aLocation zoomLevel:10 animated:false
  
aMapView’s setDelegate:me
  
  
–MapにPinを追加
  
set anAnnotation to current application’s MKPointAnnotation’s alloc()’s init()
  
anAnnotation’s setCoordinate:aLocation
  
anAnnotation’s setTitle:aTitle
  
aMapView’s addAnnotation:anAnnotation
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, 40)))
  
bButton’s setTitle:aButtonMSG
  
bButton’s setButtonType:(current application’s NSMomentaryLightButton)
  
bButton’s setBezelStyle:(current application’s NSRoundedBezelStyle)
  
bButton’s setKeyEquivalent:(return)
  
bButton’s setTarget:me
  
bButton’s setAction:(“clicked:”)
  
  
–SplitViewをつくる
  
set aSplitV to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aHeight, aWidth))
  
aSplitV’s addSubview:aMapView
  
aSplitV’s addSubview:bButton
  
aSplitV’s setNeedsDisplay:true
  
  
set aWin to makeWinWithView(aSplitV, aWidth, aHeight, aTitle, 1.0)
  
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
aWin’s makeFirstResponder:aMapView
  
wController’s showWindow:me
  
  
aWin’s makeKeyAndOrderFront:me
  
  
set aCount to timeOutSecs * 10 –timeout seconds * 10
  
repeat aCount times
    if (my windisp) = false then
      exit repeat
    end if
    
delay 0.1
  end repeat
  
  
my closeWin:aWin
  
end dispMapView

–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 NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
set aBacking to current application’s NSTitledWindowMask
  
set aDefer to current application’s NSBackingStoreBuffered
  
  
– Window
  
set aWin to NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
  
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:

–http://freegeoip.net
on getIPAddressInfoFreeGeoIP(IPAddress)
  try
    with timeout of 10 seconds
      set link to “http://freegeoip.net/json/” & IPAddress
      
set theURL to |NSURL|’s URLWithString:link
      
set jsonData to NSData’s dataWithContentsOfURL:theURL
      
set aJsonDict to (NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value))
      
return aJsonDict
    end timeout
  on error
    return missing value
  end try
end getIPAddressInfoFreeGeoIP

–Internet Connection Check
on hasInternetConnection()
  set aURL to |NSURL|’s alloc()’s initWithString:“http://www.google.com”
  
set aReq to NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:5.0
  
set urlRes to (NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
  
if urlRes = missing value then
    return false
  else
    return true
  end if
end hasInternetConnection

★Click Here to Open This Script 

2017/12/20 指定IPアドレスの情報を取得してMKMapViewで表示

指定のIPアドレスの情報をIP-APIのREST APIを呼び出して取得し、緯度、経度情報からMKMapViewで地図を表示するAppleScriptです。

map1.png

map2.png

map3.png

map4.png

map5.png

前バージョンではshellのcurlコマンドでREST APIを呼び出していましたが、Shane Stanleyからツッコミが入って書き換えました。

フロントエンドプロセスで実行する必要があるため、スクリプトエディタ上でControl+Command-Rで実行します。ASObjC Explorer 4やScript Debugger上では表示できない可能性があります(あと、アプレットに書き出して実行するとエラーに、、、、)。

ずいぶん昔に作りかけて放置していたScriptに機能追加と修正を加えたものだったので、不思議な処理を行なっている部分がありました。初回掲載時からこれを修正しました。

AppleScript名:指定IPアドレスの情報を取得してMKMapViewで表示
– Created 2015-12-11 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “MapKit”
use framework “CoreLocation”
use framework “Carbon”
–http://piyocast.com/as/archives/5041

property |NSURL| : a reference to current application’s |NSURL|
property NSData : a reference to current application’s NSData
property NSString : a reference to current application’s NSString
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property NSSplitView : a reference to current application’s NSSplitView
property MKMapView : a reference to current application’s MKMapView
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSWindowController : a reference to current application’s NSWindowController
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

property windisp : false

set anIP to “175.139.227.170″

set aInfo to getIPAddressInfo(anIP) of me

if aInfo = missing value then
  display dialog “Network Error”
  
return
end if

set aLong to (lon of (aInfo as record)) as real
set aLat to (lat of (aInfo as record)) as real

set aWidth to 450
set aHeight to 300

set aTitle to “MKMapTypeStandard”
set aButtonMSG to “OK”

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

dispMapView(aWidth, aHeight, aTitle, aButtonMSG, 180, aLat, aLong) of me

on dispMapView(aWidth as integer, aHeight as integer, aTitle as text, aButtonMSG as text, timeOutSecs as number, aLat, aLong)
  
  
set (my windisp) to true
  
  
–MKMapViewをつくる
  
set aMapView to MKMapView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
aMapView’s setMapType:(current application’s MKMapTypeStandard)
  
  
–MKMapTypeStandard –Works, First run may not display map texts
  
–MKMapTypeHybrid –Works
  
–MKMapTypeSatellite–Works
  
–MKMapTypeSatelliteFlyover–Works
  
–MKMapTypeHybridFlyover–Works
  
–MKMapTypeMutedStandard–Not Works (Error)
  
  
aMapView’s setZoomEnabled:true
  
aMapView’s setScrollEnabled:true
  
aMapView’s setPitchEnabled:true
  
aMapView’s setRotateEnabled:false
  
aMapView’s setShowsCompass:true
  
aMapView’s setShowsZoomControls:true
  
aMapView’s setShowsScale:true
  
aMapView’s setShowsUserLocation:false
  
  
set aLocation to current application’s CLLocationCoordinate2DMake(aLat, aLong)
  
aMapView’s setCenterCoordinate:aLocation zoomLevel:17 animated:false
  
aMapView’s setDelegate:me
  
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, 40)))
  
bButton’s setTitle:aButtonMSG
  
bButton’s setKeyEquivalent:(return)
  
bButton’s setTarget:me
  
bButton’s setAction:(“clicked:”)
  
  
–SplitViewをつくる
  
set aSplitV to NSSplitView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aHeight, aWidth))
  
aSplitV’s setVertical:false
  
  
aSplitV’s addSubview:aMapView
  
aSplitV’s addSubview:bButton
  
aSplitV’s setNeedsDisplay:true
  
  
set aWin to makeWinWithView(aSplitV, aWidth, aHeight, aTitle, 1.0)
  
  
set wController to NSWindowController’s alloc()
  
wController’s initWithWindow:aWin
  
aWin’s makeFirstResponder:aMapView
  
wController’s showWindow:me
  
  
aWin’s makeKeyAndOrderFront:me
  
  
set aCount to timeOutSecs * 10 –timeout seconds * 10
  
repeat aCount times
    if (my windisp) = false then
      exit repeat
    end if
    
delay 0.1
  end repeat
  
  
my closeWin:aWin
  
end dispMapView

–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 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 NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
  
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 NSModalPanelWindowLevel) – original : 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:

–http://ip-api.com/docs/
on getIPAddressInfo(IPAddress)
  set link to “http://ip-api.com/json/” & IPAddress & “?fields=country,city,isp,org,as,mobile,proxy,message,lat,lon”
  
set theURL to |NSURL|’s URLWithString:link
  
set jsonData to NSData’s dataWithContentsOfURL:theURL
  
set aJsonDict to (NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value))
  
return aJsonDict
end getIPAddressInfo

★Click Here to Open This Script 

2017/12/19 指定IPアドレスの情報を取得してマップ.appで表示

指定のIPアドレスの情報をIP-APIのREST APIを呼び出して取得し、緯度、経度情報からマップ.appを検索するAppleScriptです。

maps_resized.png

マップ.appでの指定住所や指定緯度&経度の表示はURLイベント経由でしか行えないので、地図のローディング終了検出などは無理です(長めにdelayして時間待ちするしか)。

地図表示して地図をPDFに指定ファイル名で保存、というあたりまで処理できるとAppleScriptらしい感じがしますが、まだそこまでは行っていません。

GUI Scriptingを併用するとマップ.appからのPDF書き出しも行えそうですが、動的にMKMapViewを作成してビューの内容をPDF書き出ししたほうがよさそうです。

→ Xcode上でMKMapViewからの画像取得をAppleScriptでやってみたら、どうも著作権的にできない模様。もしくは取得対象のレイヤーが違うとか、、、

mappdf1_resized.png
▲マップ.appのメニューから書き出しを行なったPDF

c8ba8f71-2c21-4282-9e85-37af35b818cd_resized.png
▲Xcode上のAppleScriptObjCアプリケーションでMKMapViewから画像を取得して書き出しを行なったPNG

AppleScript名:指定IPアドレスの情報を取得して地図.appで表示
– Created 2017-12-10 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/5037

property NSString : a reference to current application’s NSString
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

set aInfo to getIPAddressInfo(“133.6.129.212″) of me
set aLon to (lon of (aInfo as record)) as string
set aLat to (lat of (aInfo as record)) as string

set aURL to “http://maps.apple.com/?ll=” & aLat & “,” & aLon & “&t=m”
open location aURL

–http://ip-api.com/docs/
on getIPAddressInfo(IPAddress)
  set link to “http://ip-api.com/json/” & IPAddress & “?fields=country,city,isp,org,as,mobile,proxy,message,lat,lon”
  
set curl_command to “curl “ & link
  
set jRes to do shell script curl_command
  
set jsonString to NSString’s stringWithString:jRes
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to (NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value))
  
return aJsonDict
end getIPAddressInfo

★Click Here to Open This Script 

2017/12/17 アドウェア「OSX.Pirrit」のAppleScriptコードを読んでみた

2016年4月にその存在が公表された、macOSをターゲットにしたアドウェア「OSX.Pirrit」。

一部で「AppleScriptが使われている」との話が注目を集めていますが、実物を見てみないと判断のつかないところです。

「Mac」を狙うアドウェア「OSX.Pirrit」が巧妙化–研究者が指摘
Macを狙うアドウェア「OSX.Pirrit」、マルウェアの手口を借りて拡散

実物を探しても見つかりません。OSX.Pirritについて構造やコードレベルで説明しているBlogの記事を見つけたため、そこに掲載されているコードのスクリーンショットから判断してみます。

・OSX.Pirrit Mac Adware Part III: The DaVinci Code
https://www.cybereason.com/blog/targetingedge-mac-os-x-pirrit-malware-adware-still-active

OSX.Pirritの感染経路はMac用アプリケーションのインストーラーパッケージおよびそこに仕込まれたshell scriptです。このshell scriptが管理者権限で実行されることを利用しています。「怪しいインストーラーを実行すると危険」というのが本アドウェアについてのポイントです。感染(ルート権限でやり放題にプログラムを実行)状態になってしまえば、あとは何を使って何をされても「後の祭り」です。

# プロセスのBundle IDを偽装する、という「手口」はなかなか参考になりました

まずは、shell scriptでupdaterプログラムをルート権限で定期実行できるようにしたり、Objective-Cで書かれた「updater」プログラムをダウンロード。

しばらく他のプログラムの解説が続いたあと、「どこにAppleScriptの話があるの?」という気分になった頃にようやくAppleScriptの話が出てきます。

macverという実行ファイルの中にbase64でエンコードされたAppleScriptの文字列が含まれており、これをデコードして実行するようです。

AppleScriptのコードというので、どれだけ凝った処理をやっているのかと思いきや、それほど行数はないのと、半分以上はSafariにdo javascriptコマンドで実行するJavaScriptです。

OSのバージョンや環境情報を調べての対策もやっていません。割と雑なコードです。Cocoaの機能も呼び出さないし、アプリケーションプロセスの特定にBundle IDも使いません。

JavaScript部分の処理のていねいさに比べて、ものすごく雑な感じがします。

そして、ここが大事なところなのですが……現行のSafari v10.x上ではデフォルトでAppleEvent経由でのJavaScriptの実行は禁止状態になっています。

つまり、広告情報をWebブラウザのコンテンツに突っ込む部分を(デフォルトでは)実行できない状態になっています。

もう少し何か楽しませてくれるかと思っていたのですが、実に残念です。

2017/12/16 表示中のCotEditor書類の「次」のファイルを縦書きでオープン

CotEditorで表示中のテキストファイルを、ファイルの入っているフォルダの中でファイル名の並び順で「次」にあたるファイルを縦書きでオープンするAppleScriptです。

「小説家になろう」サイトからダウンロードした小説のテキストファイル(連番入りテキストファイル)をCotEditorで縦書き表示して、順次ファイルを切り替えて読み進めるために作ったものです。

CotEditorはプレーンテキストのエディタでありながら、縦書き表示が可能で、画面表示がキレイなので「縦書きテキストビューワー」としてもよく利用しています。そして、AppleScriptからのコントロールが可能なので、さまざまな「存在しない機能」を勝手に追加できます。

cot3.png

1つのフォルダ中に連番つきのファイルのうちどれかをCotEditorでオープンしている状態で、

cot1.png

本Scriptを実行すると、書類が入っているフォルダ中のテキストファイルのファイル名を抽出してソートし、現在のファイルの「次」に該当するファイルをCotEditorでオープンします。

オープンしたら、元Windowのサイズを取得して、元Windowと同じサイズに設定して、元の書類をクローズ。「次」の書類の表示状態を縦書きに設定します。

OS側のScript Menuから実行することを前提としていますが、CotEditor内蔵のScript Menuからは実行できません(内蔵MenuだとGUI Scriptingなどが実行できないもよう)。

CotEditor自体の縦書き表示/横書き表示の切り替え機能がAppleScript側に解放されていれば、AppleScript用語辞書経由でアクセスできますが、現状では表示方向の属性の取得・変更はできないので野蛮なGUI Scripting経由で行っています。

cot2.png

AppleScript名:表示中のCotEditor書類の「次」のファイルを縦書きでオープン
– Created 2017-12-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use bPlus : script “BridgePlus”
–http://piyocast.com/as/archives/5034

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property SMSForder : a reference to current application’s SMSForder
property NSPredicate : a reference to current application’s NSPredicate
property NSFileManager : a reference to current application’s NSFileManager
property NSMutableArray : a reference to current application’s NSMutableArray
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSURLIsPackageKey : a reference to current application’s NSURLIsPackageKey
property NSURLIsDirectoryKey : a reference to current application’s NSURLIsDirectoryKey
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles
property NSDirectoryEnumerationSkipsPackageDescendants : a reference to current application’s NSDirectoryEnumerationSkipsPackageDescendants
property NSDirectoryEnumerationSkipsSubdirectoryDescendants : a reference to current application’s NSDirectoryEnumerationSkipsSubdirectoryDescendants

load framework

tell application “CotEditor”
  set dCount to count every document
  
if dCount = 0 then return
  
  
tell front document
    set curPath to path
  end tell
  
  
tell window 1
    set aBounds to bounds
  end tell
end tell

set aPath to NSString’s stringWithString:curPath
set fileName to (aPath’s lastPathComponent()) –ファイル名
set pathExtension to aPath’s pathExtension() as string
set parentFol to (aPath’s stringByDeletingLastPathComponent()) as string —親フォルダ

–同じフォルダから同じ拡張子のファイルのファイル名を取得
set fList to my getFilesByIncludedStringInName:(pathExtension) fromDirectory:(parentFol) exceptPackages:(true)

–昇順ソート
set aArray to NSArray’s arrayWithArray:fList
set desc1 to NSSortDescriptor’s sortDescriptorWithKey:“self” ascending:true selector:“localizedCaseInsensitiveCompare:”
set bArray to aArray’s sortedArrayUsingDescriptors:{desc1}

–ファイル名検索
set aIndex to (SMSForder’s indexesOfItem:fileName inArray:bArray inverting:false) as list
if aIndex = {} then
  display notification “Error: File Not Found”
  
return
end if

set bIndex to (contents of first item of aIndex) + 1 + 1 –0 based to 1 based conversion & next one
set aLen to length of (bArray as list)
if bIndex > aLen then
  display notification “Error: Out of bounds”
  
return
end if

set newFile to contents of item bIndex of (bArray as list)
set newPath to parentFol & “/” & newFile

tell application “CotEditor”
  set oldDoc to front document
  
  
open (POSIX file newPath) as alias
  
tell window 1
    set bounds to aBounds
  end tell
  
  
close oldDoc without saving
end tell

makeWinVertical() of me –縦書き表示

–指定フォルダ内の指定文字列を含むファイル名のlistを抽出する
on getFilesByIncludedStringInName:(fileNameStr as string) fromDirectory:(sourceFolder) exceptPackages:(packageF as boolean)
  set fileManager to NSFileManager’s defaultManager()
  
set aURL to |NSURL|’s fileURLWithPath:sourceFolder
  
set theOptions to (NSDirectoryEnumerationSkipsPackageDescendants as integer) + (NSDirectoryEnumerationSkipsHiddenFiles as integer) + (NSDirectoryEnumerationSkipsSubdirectoryDescendants as integer)
  
set directoryContents to fileManager’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:theOptions |error|:(missing value)
  
set findPredicates to NSPredicate’s predicateWithFormat_(“lastPathComponent CONTAINS %@”, fileNameStr)
  
set foundItemList to directoryContents’s filteredArrayUsingPredicate:findPredicates
  
  
–Remove Folders From found URL Array
  
set anArray to NSMutableArray’s alloc()’s init()
  
repeat with i in foundItemList
    set j to contents of i
    
set {theResult, isDirectory} to (j’s getResourceValue:(reference) forKey:(NSURLIsDirectoryKey) |error|:(missing value))
    
    
–Collect files
    
if (isDirectory as boolean = false) then
      (anArray’s addObject:j)
    else if (packageF = false) then
      –Allow Package files?
      
set {theResult, isPackage} to (j’s getResourceValue:(reference) forKey:(NSURLIsPackageKey) |error|:(missing value))
      
if (isPackage as boolean) = true then
        (anArray’s addObject:j)
      end if
    end if
    
  end repeat
  
  
return (anArray’s valueForKey:“lastPathComponent”) as list
end getFilesByIncludedStringInName:fromDirectory:exceptPackages:

–Make CotEditor’s front window to Vertical display mode (Tategaki)
on makeWinVertical()
  activate application “CotEditor”
  
tell application “System Events”
    tell process “CotEditor”
      try
        click menu item “縦書きで表示” of menu 1 of menu bar item “フォーマット” of menu bar 1
      end try
    end tell
  end tell
end makeWinVertical

★Click Here to Open This Script 

2017/12/15 ハンドラ間接呼び出し

ハンドラを間接的に呼び出すAppleScriptです。ハンドラへの参照を変数に入れて、変数経由でハンドラを呼び出します。

さんざん実験していた内容ですが、「失敗していた」と思っていたところ成功していました。

ただし、呼び出される側のハンドラは、Pure AppleScriptでよく見られる、

 on aHandler(aParam, bParam)

のような記法では間接呼び出しは無理で、

 on aHandler given aParam:XXXX bParam:YYYY

のようにgivenでラベル付きパラメータを記述するタイプでしか呼び出せていません。

 on aHandlerWithAParam:XXXX bParam:YYYY

のようなObjective-Cスタイルのハンドラもダメです。

ただし、無意味句を用いた英文タイプのものは大丈夫だと思います。

AppleScript名:ハンドラ間接呼び出し
– Created 2017-12-14 by Takaaki Naganoya
– 2017 Piyomaru Software
–http://piyocast.com/as/archives/5031

set a to class of b
–> handler
set d to class of c
–> handler

set bHandle to (a reference to b) as handler
set cHandle to (a reference to c) as handler

copy bHandle to indirectHandler
set e to indirectHandler given parameter:“ABC”
–> “ABC_B”

copy cHandle to indirectHandler
set e to indirectHandler given parameter:“ABC”
–> “ABC_C”

on b given parameter:thisParam as string
  return thisParam & “_B”
end b

on c given parameter:thisParam as string
  return thisParam & “_C”
end c

★Click Here to Open This Script 

2017/12/14 MPSoundEngineでサウンド発生

オープンソースの「MPSoundEngine」(By Matthias Plappert)をFramework化した「mpSoundKit」を呼び出してサウンドを発生させるAppleScriptです。

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

–> Download Framework Binary

MPSoundEngineはモノラル/ステレオで指定周波数のサインウェーブを発生させるだけのものです。

機能が単純で素朴なので、いろいろやってみたくなる危険な香りがします。64ビットの8コアのコンピュータを使っているのに、なぜか1980年代にタイムスリップして8ビットのコンピュータを使っているかのような錯覚に陥ります。

MMLの解釈・再生プログラムを作り出したら「負け」のような気が、、、

AppleScript名:mpSoundEngineでA=440Hzのモノラルの音を出す
– Created 2017-12-14 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “mpSoundKit” –https://github.com/matthiasplappert/MPSoundEngine
–http://piyocast.com/as/archives/5030

set engine to current application’s MPMonoSoundEngine’s alloc()’s init()
engine’s channel()’s setFrequency:440.0
engine’s start()
delay 3
engine’s |stop|()

★Click Here to Open This Script 

AppleScript名:mpSoundEngineで440Hzと261Hzの音を出す
– Created 2017-12-14 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “mpSoundKit” –https://github.com/matthiasplappert/MPSoundEngine
–http://piyocast.com/as/archives/5030

set engine to current application’s MPStereoSoundEngine’s alloc()’s init()
engine’s leftChannel()’s setFrequency:440.0
engine’s rightChannel()’s setFrequency:261.0
engine’s start()
delay 0.5
engine’s |stop|()

★Click Here to Open This Script 

AppleScript名:mpSoundEngineで音階を出す
– Created 2017-12-14 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “mpSoundKit” –https://github.com/matthiasplappert/MPSoundEngine
–http://piyocast.com/as/archives/5030

property engine : missing value

set engine to current application’s MPMonoSoundEngine’s alloc()’s init()
–https://pages.mtu.edu/~suits/notefreqs.html
set soundList to {261.63, 293.66, 329.63, 349.23, 392.0, 440.0, 493.88, 523.25}

repeat with i in soundList
  makeSound(i) of me
end repeat

engine’s |stop|()

on makeSound(aHz)
  engine’s channel()’s setFrequency:aHz
  
engine’s start()
  
delay 0.1
  
–engine’s |stop|()
end makeSound

★Click Here to Open This Script 

AppleScript名:電話の呼び出し音のような音
– Created 2017-12-14 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “mpSoundKit” –https://github.com/matthiasplappert/MPSoundEngine
–http://piyocast.com/as/archives/5030

property engine : missing value

set engine to current application’s MPMonoSoundEngine’s alloc()’s init()
–https://pages.mtu.edu/~suits/notefreqs.html
set soundList to {440.0, 466.16}

repeat 10 times
  repeat with i in soundList
    makeSound(i) of me
  end repeat
end repeat

engine’s |stop|()

on makeSound(aHz)
  engine’s channel()’s setFrequency:aHz
  
engine’s start()
  
delay 0.05
  
–engine’s |stop|()
end makeSound

★Click Here to Open This Script 

AppleScript名:音階発生(Stereo)
– Created 2017-12-14 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “mpSoundKit” –https://github.com/matthiasplappert/MPSoundEngine
–http://piyocast.com/as/archives/5030

property engine : missing value

set engine to current application’s MPStereoSoundEngine’s alloc()’s init()
–https://pages.mtu.edu/~suits/notefreqs.html
set soundList to {261.63, 293.66, 329.63, 349.23, 392.0, 440.0, 493.88, 523.25}
set aLen to length of soundList

repeat with i from 1 to aLen
  makeStereoSound(item i of soundList, item (aLen - i + 1) of soundList) of me
end repeat

engine’s |stop|()

on makeStereoSound(aHz, bHz)
  engine’s leftChannel()’s setFrequency:aHz
  
engine’s rightChannel()’s setFrequency:bHz
  
engine’s start()
  
delay 0.5
end makeStereoSound

★Click Here to Open This Script 

AppleScript名:mpSoundEngineでループ音声発生(サイレン1)
– Created 2017-12-14 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “mpSoundKit” –https://github.com/matthiasplappert/MPSoundEngine
–http://piyocast.com/as/archives/5030

set engine to current application’s MPMonoSoundEngine’s alloc()’s init()
engine’s start()
repeat with i from 100 to 1000 by 20
  repeat with ii from i to 1000 by 20
    (engine’s channel()’s setFrequency:ii)
    
delay 0.005
  end repeat
end repeat

engine’s |stop|()

★Click Here to Open This Script 

AppleScript名:mpSoundEngineでループ音声発生(サイレン2)
– Created 2017-12-14 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “mpSoundKit” –https://github.com/matthiasplappert/MPSoundEngine
–http://piyocast.com/as/archives/5030

set engine to current application’s MPMonoSoundEngine’s alloc()’s init()
engine’s start()
repeat with i from 1000 to 100 by -20
  (engine’s channel()’s setFrequency:i)
  
delay 0.01
end repeat

engine’s |stop|()

★Click Here to Open This Script 

AppleScript名:ランダム音発生(昔のSFでコンピュータが演算している風の音)
– Created 2017-12-14 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “mpSoundKit” –https://github.com/matthiasplappert/MPSoundEngine
–http://piyocast.com/as/archives/5030

set engine to current application’s MPMonoSoundEngine’s alloc()’s init()

engine’s start()

repeat 1000 times
  set aNum to random number from 50 to 4000
  (
engine’s channel()’s setFrequency:aNum)
  
delay 0.02
end repeat

engine’s |stop|()

★Click Here to Open This Script 

2017/12/14 指定文字の花文字テキストを取得する(Retina対応)

指定文字を指定フォントの花文字を作成してCotEditor上に花文字で新規ドキュメントを作成するAppleScriptのRetina Display対応版です。

テキストエディタへの出力部分はTextEdit.app、BBEdit、TextWrangler、mi、Jedit Omega、CotEditor用のルーチンを差し替えればすぐに対応可能です。

以前に掲載したルーチンがRetina Display(144×144dpi)の環境を考慮していなかったので、対応させてみました(Retina Display搭載機をLid Closed Modeで運用して外部ディスプレイつないでいるので)。

Retina Display対応というのは、倍の解像度で文字が出力されるという話ではなく、Retina Displayの環境でも問題なく文字全体が出力されるということです。

flowtext.png

AppleScript名:指定文字の花文字テキストを取得する(Retina対応)
– Created 2017-12-12 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/5028

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

set aString to “あ”
set hanaSize to 36
set thisFont to selectAFont(aString) of me
if thisFont = false then return –Cancel

–花文字文字列を作成
set fRes to getHanamojiStr(hanaSize, thisFont, aString, 0.7, true) of me
makeNewDocument given parameter:fRes

–花文字文字列を計算して返す
on getHanamojiStr(aFontSize as real, aFontName as string, aString as string, aThread as real, incFontName as boolean)
  if length of aString is not equal to 1 then return false
  
  
–指定文字コードが指定フォント中に存在するかチェック
  
set fRes to retGlyphsInFont(aFontName, id of aString) of me
  
if fRes = false then return false
  
  
set aThreadShould to 768 * aThread
  
if (chkMultiByteChar(aString) of me) = false then
    set spaceChar to string id 12288 –全角スペース(UTF-16)
  else
    set spaceChar to string id 32 –半角スペース
  end if
  
  
set fillColor to NSColor’s whiteColor –塗り色
  
set bString to aString & ” “ –処理内容の帳尻合わせ(そのままだと右端が欠けるのでスペースを入れた)
  
set anAssrStr to makeRTFfromParameters(bString, aFontName, aFontSize, -2, (aFontSize * 1.2)) of me
  
set aSize to anAssrStr’s |size|()
  
  
if class of aSize = record then
    set attrStrWidth to width of aSize
    
set attrStrHeight to height of aSize
  else if class of aSize = list then –macOS 10.13.xのバグ回避
    copy aSize to {attrStrWidth, attrStrHeight}
  end if
  
  
set {xPos, yPos} to {0, 0}
  
  
set tmpImg1 to makeImageWithFilledColor(attrStrWidth, attrStrHeight, fillColor) of me
  
set tmpImg2 to drawAttributedStringsOnImage(tmpImg1, anAssrStr, xPos, yPos) of me
  
set aRawimg to NSBitmapImageRep’s imageRepWithData:(tmpImg2’s TIFFRepresentation())
  
  
–画像から順次指定座標の色データを拾って花文字listに反映
  
set strList to {}
  
repeat with y from 1 to attrStrHeight - 1
    
    
set strListX to {}
    
repeat with x from 0 to attrStrWidth - 1
      set tmpCol to getColorFromRawImage(aRawimg, x, y) of me
      
      
if tmpCol is not equal to false then
        if tmpCol is not equal to {255, 255, 255} then
          copy tmpCol to {tmpR, tmpG, tmpB}
          
if (tmpR + tmpG + tmpB) < aThreadShould then
            set the end of strListX to aString
          else
            set the end of strListX to spaceChar
          end if
        else
          set the end of strListX to spaceChar
        end if
      end if
      
    end repeat
    
set the end of strList to strListX
  end repeat
  
  
–2D List→Text
  
set aRes to list2dToStringByUsingDelimiters(strList, “”, return) of me
  
  
if incFontName = true then
    set fName to getDisplayedNameOfFont(aFontName) of me
    
set aRes to “■” & fName & return & return & aRes
  end if
  
  
return aRes
end getHanamojiStr

–指定Raw画像中の指定座標のピクセルの色をRGBで取り出す
on getColorFromRawImage(aRawimg, x as real, y as real)
  set aRatio to getImageRatio() of me –Retina Display対応
  
set origColor to (aRawimg’s colorAtX:(x * aRatio) y:(y * aRatio))
  
  
set srgbColSpace to NSColorSpace’s deviceRGBColorSpace
  
if srgbColSpace = missing value then return false
  
  
set aColor to (origColor’s colorUsingColorSpace:srgbColSpace)
  
  
set aRed to (aColor’s redComponent()) * 255
  
set aGreen to (aColor’s greenComponent()) * 255
  
set aBlue to (aColor’s blueComponent()) * 255
  
  
return {aRed as integer, aGreen as integer, aBlue as integer}
end getColorFromRawImage

–画像のうえに指定のスタイル付きテキストを描画して画像を返す
on drawAttributedStringsOnImage(anImage, anAssrStr, xPos as real, yPos as real)
  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)
  set aVal1 to NSFont’s fontWithName:fontName |size|:aFontSize
  
set aKey1 to (NSFontAttributeName)
  
  
set aVal2 to NSColor’s blackColor()
  
set aKey2 to (NSForegroundColorAttributeName)
  
  
set aVal3 to aKerning
  
set akey3 to (NSKernAttributeName)
  
  
set aVal4 to 0
  
set akey4 to (NSUnderlineStyleAttributeName)
  
  
set aVal5 to 2 –all ligature ON
  
set akey5 to (NSLigatureAttributeName)
  
  
set aParagraphStyle to NSMutableParagraphStyle’s alloc()’s init()
  
aParagraphStyle’s setMinimumLineHeight:(aLineSpacing)
  
aParagraphStyle’s setMaximumLineHeight:(aLineSpacing)
  
set akey7 to (NSParagraphStyleAttributeName)
  
  
set keyList to {aKey1, aKey2, akey3, akey4, akey5, akey7}
  
set valList to {aVal1, aVal2, aVal3, aVal4, aVal5, aParagraphStyle}
  
set attrsDictionary to NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
  
  
set attrStr to NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary
  
return attrStr
end makeRTFfromParameters

–指定サイズの画像を作成し、背景を指定色で塗る
on makeImageWithFilledColor(aWidth as real, aHeight as real, fillColor)
  set anImage to NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
set aRatio to getImageRatio() of me –Retina Display対応
  
  
anImage’s lockFocus()
  
set theRect to {{x:0, y:0}, {width:aWidth * aRatio, height:aHeight * aRatio}}
  
set theNSBezierPath to NSBezierPath’s bezierPath
  
theNSBezierPath’s appendBezierPathWithRect:theRect
  
fillColor’s |set|()
  
theNSBezierPath’s fill()
  
anImage’s unlockFocus()
  
  
return anImage
end makeImageWithFilledColor

–2D Listをアイテム間および行間のデリミタを個別に指定してテキスト変換
on list2dToStringByUsingDelimiters(aList as list, itemDelimiter, lineDelimiter)
  set outList to {}
  
repeat with i in aList
    set aStr to listToStringUsingTextItemDelimiter(i, itemDelimiter) of me
    
set the end of outList to aStr
  end repeat
  
  
set bStr to listToStringUsingTextItemDelimiter(outList, lineDelimiter) of me
  
return bStr
end list2dToStringByUsingDelimiters

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

–ユーザー環境にインストールされているすべてのフォントのPostScript名とグリフ数を返す
on getEveryFontPSNameANdGlyphsNum(aStr)
  set aFontList to NSFontManager’s sharedFontManager()’s availableFonts()
  
set thePred to NSPredicate’s predicateWithFormat:“NOT SELF BEGINSWITH ’.’”
  
set aFontList to (aFontList’s filteredArrayUsingPredicate:thePred) as list
  
  
set aList to {}
  
repeat with i in aFontList
    set aName to contents of i
    
set aNum to countNumberOfGlyphsInFont(aName) of me
    
set dName to getDisplayedNameOfFont(aName) of me
    
    
set fRes to retGlyphsInFont(aName, id of aStr) of me
    
if fRes = true then
      set the end of aList to {fontName:aName, fontNum:aNum, dispName:dName}
    end if
  end repeat
  
  
return aList
end getEveryFontPSNameANdGlyphsNum

–指定Postscript名称のフォントに定義されている文字数を数えて返す
on countNumberOfGlyphsInFont(fontName as string)
  set aFont to NSFont’s fontWithName:fontName |size|:9.0
  
if aFont = missing value then return false
  
set aProp to aFont’s numberOfGlyphs()
  
return aProp as number
end countNumberOfGlyphsInFont

–フォントのPostScript NameからDisplayed Nameを取得
on getDisplayedNameOfFont(aName as string)
  set aFont to NSFont’s fontWithName:aName |size|:9.0
  
set aDispName to (aFont’s displayName()) as string
  
return aDispName
end getDisplayedNameOfFont

–全角文字が存在するか
on chkMultiByteChar(checkString as string)
  set aStr to NSString’s stringWithString:checkString
  
set aRes to aStr’s canBeConvertedToEncoding:(current application’s NSASCIIStringEncoding)
  
return (aRes as boolean)
end chkMultiByteChar

–指定名称のフォントに指定の文字コードが含まれているかチェック
on retGlyphsInFont(fontName as string, strCode as integer)
  set aFont to NSFont’s fontWithName:fontName |size|:24.0
  
if aFont = missing value then return false
  
set aSet to aFont’s coveredCharacterSet()
  
set aRes to (aSet’s characterIsMember:strCode) as boolean
  
return aRes as list of string or string –as anything
end retGlyphsInFont

on selectAFont(aString)
  set fRes to getEveryFontPSNameANdGlyphsNum(aString) of me
  
set theArray to NSArray’s arrayWithArray:fRes
  
set thePred to NSPredicate’s predicateWithFormat:“fontNum > 10000″
  
set bArray to ((theArray’s filteredArrayUsingPredicate:thePred)’s valueForKeyPath:“dispName”) as list
  
set thisFont to choose from list bArray
  
return thisFont
end selectAFont

–Retina Display対応ルーチン
on getImageRatio()
  set retinaF to detectRetinaDisplay() of me
  
if retinaF = true then
    return 2.0 as real
  else
    return 1.0 as real
  end if
end getImageRatio

on detectRetinaDisplay()
  set dispList to current application’s NSScreen’s screens()
  
set retinaF to false
  
  
repeat with i in dispList
    set j to contents of i
    
set aDepth to j’s backingScaleFactor()
    
if aDepth > 1.0 then
      set retinaF to true
    end if
  end repeat
  
  
return retinaF
end detectRetinaDisplay

on makeNewDocument given parameter:aStr
  tell application id “com.coteditor.CotEditor”
    activate
    
set newDoc to make new document
    
tell newDoc
      set contents to aStr
    end tell
  end tell
end makeNewDocument

★Click Here to Open This Script 

2017/12/13 ハンドラの間接呼び出しのじっけん

ハンドラの間接呼び出しの実験を行うAppleScriptです。

variableeditor.gif

ハンドラの間接呼び出しは、Scripter誰もが一度は考えてみる課題ですが、自分にはどう考えてもできませんでした。もしかして、世界にひとりぐらいは実現している人間がいるかもしれませんが、とりあえず自分の結論は「無理」というものでした。

# recordを文字列に変換するのも、当初は「言語仕様的に不可能」と言われた空前絶後の超絶テクニックでしたが、いまでは割と手垢のついた「手口」に

ハンドラの存在確認が行える以上、間接的にハンドラを呼び出すことも不可能ではなさそうな雰囲気もしていますが、とりあえず行えていません。

結局、異なるAppleScript Librariesに同じ名前のハンドラを作っておき、呼び出し先のAppleScript Librariesを「代入」で切り替えることで、間接呼び出しっぽい処理を実現してみました。

scriptlibs.png

別にif文で条件分岐してもかまわなさそうな内容ですが、「やってできないことはない」という落とし所が見えました。

本Scriptでは、TextEdit.app、BBEdit、TextWranglermiJedit OmegaCotEditorという6本のテキストエディタをダイアログで選択し、当該エディタで花文字テキストの新規ドキュメントを作成しています。

–> Download This Script Bundle

AppleScript名:variableHandlerTest
– Created 2017-12-12 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use ed001 : script “textedit”
use ed002 : script “bbedit”
use ed003 : script “textwrangler”
use ed004 : script “mi”
use ed005 : script “jeditomega”
use ed006 : script “coteditor”
–http://piyocast.com/as/archives/5023

set aString to retFlowerText() of me

set appIDlist to {“com.apple.textedit”, “com.barebones.bbedit”, “com.barebones.textwrangler”, “net.mimikaki.mi”, “jp.co.artman21.JeditOmega”, “com.coteditor.CotEditor”}
set scriptObjList to {ed001, ed002, ed003, ed004, ed005, ed006}

set appNameList to {}
set appBundleIDList to {}

repeat with i in appIDlist
  set anAppID to contents of i
  
set aRes to checkAppInstallation(anAppID) of me
  
if aRes is not equal to false then
    set the end of appBundleIDList to anAppID
  end if
end repeat

set cRes to choose from list appBundleIDList
if cRes = false then return –Cancel

set appIDnum to retIndexNumInArray(appIDlist, contents of first item of cRes)
set objRef to contents of item appIDnum of scriptObjList

copy objRef to theTargetEditor –Very Important!!

tell theTargetEditor
  makeNewDocument given parameter:aString
end tell

on retFlowerText()
  return “                                            
           あああああ                            
           あああああ                            
           あああああ                            
           あああああ                            
    ああああああああああああああああああああああああああああ            
    ああああああああああああああああああああああああああああ            
    ああああああああああああああああああああああああああああ            
    ああああああああああああああああああああああああああああ            
           あああああ                            
           あああああ                            
           あああああ  ああああああ                    
           あああああああああああああああああ                
           あああああああああああああああああああ              
         あああああああああ   ああああああああああ             
        ああああああああ    ああああ  ああああああ            
       あああああああああ    ああああ   あああああ            
      あああああ ああああ   あああああ    あああああ           
     あああああ  あああああ  ああああ     あああああ           
     ああああ   あああああ あああああ     あああああ           
    あああああ   ああああああああああ      あああああ           
    ああああ     あああああああああ      あああああ           
   あああああ     ああああああああ       あああああ           
   あああああ     あああああああ        あああああ           
   あああああ     ああああああ        ああああああ           
   あああああ    ああああああ         ああああああ           
   ああああああああああああああ        あああああああ            
    ああああああああああああ       ああああああああ             
    あああああああああああ   あああああああああああああ             
     ああああああああ     あああああああああああ               
        あ         あああああああああ                 
                                            
                                            

end retFlowerText

–指定IDのアプリケーションがHDD上に存在するかを確認
on checkAppInstallation(appID)
  tell application “Finder”
    try
      set aRes to exists of application file id appID
    on error
      return false
    end try
  end tell
  
  
return true
end checkAppInstallation

–1D List中のシーケンシャルサーチ
on retIndexNumInArray(aList, aTarget)
  script obj
    property list : aList
  end script
  
  
set aCount to 1
  
set hitF to false
  
  
repeat with i in obj’s list
    set j to contents of i
    
if aTarget = j then
      return aCount
    end if
    
    
set aCount to aCount + 1
  end repeat
  
  
if hitF = false then return 0
end retIndexNumInArray

★Click Here to Open This Script 

AppleScript名:textedit
on makeNewDocument given parameter:aStr
  tell application id “com.apple.textedit”
    set aDoc to make new document
    
tell aDoc
      set text of it to aStr
    end tell
    
activate
  end tell
end makeNewDocument

★Click Here to Open This Script 

AppleScript名:bbedit
on makeNewDocument given parameter:aStr
  tell application id “com.barebones.bbedit”
    set aDoc to make new text document with properties {text:aStr}
    
activate
  end tell
end makeNewDocument

★Click Here to Open This Script 

AppleScript名:textwrangler
on makeNewDocument given parameter:aStr
  tell application id “com.barebones.textwrangler”
    set aDoc to make new text document with properties {text:aStr}
    
activate
  end tell
end makeNewDocument

★Click Here to Open This Script 

AppleScript名:mi
on makeNewDocument given parameter:aStr
  tell application id “net.mimikaki.mi”
    make new document with properties {content:aStr}
    
activate
  end tell
end makeNewDocument

★Click Here to Open This Script 

AppleScript名:jeditomega
on makeNewDocument given parameter:aStr
  tell application id “jp.co.artman21.JeditOmega”
    set aDoc to make new document with properties {text:aStr}
    
activate
  end tell
end makeNewDocument

★Click Here to Open This Script 

AppleScript名:coteditor
on makeNewDocument given parameter:aStr
  tell application id “com.coteditor.CotEditor”
    activate
    
set newDoc to make new document
    
tell newDoc
      set contents to aStr
    end tell
  end tell
end makeNewDocument

★Click Here to Open This Script 

2017/12/12 クリップボードに入ったproperty宣言部分を見た目の描画サイズ(幅)と文字コードでソート

クリップボードに入ったAppleScriptのproperty宣言部分を画面上の見た目と文字コードでソートしてクリップボードに入れるAppleScriptです。

以前に、同様の文字列長でソートするAppleScriptを作成したことがありましたが、

after2.png

文字列長できちんとソートしたものの、プロポーショナルフォントで表示されるため、

 「文字列長どおりにソートしても見た目がよくなるわけではない」

というたいへんに残念な結果に。

そこで、NSAttributedStringの描画サイズを取得するメソッドを利用して、画面上の見た目(画面上の描画サイズ)を取得し、描画サイズ(幅)と文字コード順でソートするようにしてみました。

sortbylooks.png

スクリプトエディタでCocoaオブジェクトへのproperty参照宣言部分をコピーし、本Scriptを呼び出し、ふたたびエディタ中に内容をペースとすると、画面上の描画サイズにもとづいて並べ替えたproperty宣言文が展開されます。

画面上の描画サイズを計算する際には、NSAttributedStringを組み立てる必要があるわけですが、この際の指定フォントについては最初にクリップボードに入っていた内容をNSAttributedStringとして取得し、その中で使われていた中で最も登場頻度の高いものを取得して自動で指定しています(やりすぎ)。

AppleScript名:クリップボードに入ったproperty宣言部分を見た目の描画サイズ(幅)と文字コードでソート
– Created 2017-12-08 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “AppKit”
–http://piyocast.com/as/archives/5021

property NSFont : a reference to current application’s NSFont
property NSData : a reference to current application’s NSData
property NSColor : a reference to current application’s NSColor
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSDictionary : a reference to current application’s NSDictionary
property NSPasteboard : a reference to current application’s NSPasteboard
property NSCountedSet : a reference to current application’s NSCountedSet
property NSMutableArray : a reference to current application’s NSMutableArray
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSAttributedString : a reference to current application’s NSAttributedString
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSKernAttributeName : a reference to current application’s NSKernAttributeName
property NSMutableParagraphStyle : a reference to current application’s NSMutableParagraphStyle
property NSLigatureAttributeName : a reference to current application’s NSLigatureAttributeName
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSUnderlineStyleAttributeName : a reference to current application’s NSUnderlineStyleAttributeName
property NSParagraphStyleAttributeName : a reference to current application’s NSParagraphStyleAttributeName
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName

–クリップボードの内容を文字列として取得
set aStr to (the clipboard) as string
if aStr = “” then
  display dialog “No Data in Clipboard” buttons {“OK”} default button 1
  
return
end if

–クリップボードの内容をStyled Stringで取得して最頻出フォントを取得
set clipboardAttrStr to getClipboardASStyledText() of me
if clipboardAttrStr = missing value then
  display dialog “Can not get clipboard as Styled String” buttons {“OK”} default button 1
  
return
end if
set attrList to getAttributeRunsFromAttrString(clipboardAttrStr) of me
set anArray to (NSArray’s arrayWithArray:attrList)’s valueForKeyPath:“fontName”
set aFontList to (countItemsByItsAppearance(anArray) of me)
set aFontName to theName of first item of aFontList

–クリップボードから取得した文字データについて処理
set aList to paragraphs of aStr –行ごとにparseしてlist化
set bList to {}
repeat with i in aList
  set j to contents of i
  
if j ≠ {} then
    set jList to words of j
    
if jList ≠ {} then
      if contents of first item of jList = “property” then
        set curLabel to contents of second item of jList
        
        
–行をAttributed Stringとして組み立てて、画面描画時の仕上がりサイズを取得
        
set anAssrStr to makeRTFfromParameters(j, aFontName, 16, -2, 16) of me
        
set aSize to anAssrStr’s |size|() –画面描画時のサイズを取得
        
        
if class of aSize = record then
          set attrStrWidth to width of aSize
          
set attrStrHeight to height of aSize
        else if class of aSize = list then –macOS 10.13.xのバグ回避
          copy aSize to {attrStrWidth, attrStrHeight}
        end if
        
        
set the end of bList to {aLabel:curLabel, aCon:j, aWidth:attrStrWidth}
      end if
    end if
  end if
end repeat

if bList = {} then
  display dialog “Error” buttons {“OK”} default button 1
  
return
end if

–複数キーでソート(書式つきテキストの仕上がりサイズ幅、文字コード順でソート)
set aArray to NSArray’s arrayWithArray:bList
set desc1 to NSSortDescriptor’s sortDescriptorWithKey:“aWidth” ascending:true
set desc2 to NSSortDescriptor’s sortDescriptorWithKey:“aLabel” ascending:true selector:“localizedCaseInsensitiveCompare:”
set bArray to aArray’s sortedArrayUsingDescriptors:{desc1, desc2}

–ソートしたlist of recordからaCon(元のproperty宣言行そのもの)を一括で取り出す
set dArray to (NSMutableArray’s arrayWithArray:bArray)’s valueForKeyPath:“aCon”

–listをデリミタつきのテキストに
set dStr to retStrFromArrayWithDelimiter(dArray, return) of me

set the clipboard to (dStr & return)

–1D Listを文字列長でソート v2
on sort1DListByIndicatedStringLength(aList as list, aSortKey as string, sortOrder as boolean)
  set aArray to NSArray’s arrayWithArray:aList
  
set descLabel1 to NSString’s stringWithString:(aSortKey & “.length”)
  
set descLabel2 to NSString’s stringWithString:aSortKey
  
set desc1 to NSSortDescriptor’s sortDescriptorWithKey:descLabel1 ascending:sortOrder
  
set desc2 to NSSortDescriptor’s sortDescriptorWithKey:descLabel2 ascending:true selector:“localizedCaseInsensitiveCompare:”
  
set bArray to aArray’s sortedArrayUsingDescriptors:{desc1, desc2}
  
return bArray as list
end sort1DListByIndicatedStringLength

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

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

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

–指定のNSAttributedStringから書式情報をlist of recordで取得
on getAttributeRunsFromAttrString(theStyledText)
  script aSpd
    property styleList : {}
  end script
  
  
set (styleList of aSpd) to {} —for output
  
  
set thePureString to theStyledText’s |string|() –pure string from theStyledText
  
  
set theLength to theStyledText’s |length|()
  
set startIndex to 0
  
  
repeat until (startIndex = theLength)
    set {theAtts, theRange} to theStyledText’s attributesAtIndex:startIndex longestEffectiveRange:(reference) inRange:{startIndex, theLength - startIndex}
    
    
set aText to (thePureString’s substringWithRange:theRange) as string
    
    
set aColor to (theAtts’s valueForKeyPath:“NSColor”)
    
if aColor is not equal to missing value then
      set aSpace to aColor’s colorSpace()
      
      
set aRed to (aColor’s redComponent()) * 255
      
set aGreen to (aColor’s greenComponent()) * 255
      
set aBlue to (aColor’s blueComponent()) * 255
      
      
set colList to {aRed as integer, aGreen as integer, aBlue as integer}
      
set colStrForFind to (aRed as integer as string) & ” “ & (aGreen as integer as string) & ” “ & (aBlue as integer as string)
    else
      set colList to {0, 0, 0}
      
set colStrForFind to “0 0 0″
    end if
    
    
set aFont to (theAtts’s valueForKeyPath:“NSFont”)
    
if aFont is not equal to missing value then
      set aDFontName to aFont’s displayName()
      
set aDFontSize to aFont’s pointSize()
    end if
    
    
set the end of (styleList of aSpd) to {stringVal:aText, colorStr:colStrForFind, colorVal:colList, fontName:aDFontName as string, fontSize:aDFontSize}
    
set startIndex to current application’s NSMaxRange(theRange)
  end repeat
  
  
return (styleList of aSpd)
end getAttributeRunsFromAttrString

–1D Listをアイテムの出現頻度順でソートして返す
on countItemsByItsAppearance(aList as list)
  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
  
  
set theDesc to NSSortDescriptor’s sortDescriptorWithKey:“numberOfTimes” ascending:false
  
bArray’s sortUsingDescriptors:{theDesc}
  
  
return bArray as list
end countItemsByItsAppearance

★Click Here to Open This Script 

2017/12/12 RTFの読み込み v2.2

指定のRTF(Ritch Text Format)ファイルを読み込んでNSAttributedStringに変換し、文字色、フォント名、フォントサイズ、文字列でrecordを作成して返すAppleScriptです。

任意のGUIアプリケーションの書式付きテキストから、指定の書式で該当箇所をピックアップするのはAppleScriptでは定番中の定番処理。テキストエディット.appのattribute runs(書式の一括取り出し)が有名です。もちろん、各種ワープロやDTPソフトウェアでも「出来てあたりまえ」の処理といえます(Pages、Numbers、Keynoteあたりはちょっと無理かも)。

Cocoa+Objective-Cの機能で同様の処理をいろいろ探してみましたが、NSAttributedStringからの書式による抽出はなかなか見つけられませんでした(不可能ではないものの、そういう処理にあまり関心がなさそうな雰囲気)。

そこで、MLで相談しつつNSAttributedStringからの文字書式(フォント名、ポイント数、文字色)による抽出が行えるように書いてみました。

ひたすらループ処理なので、処理データ量が増えるとそれなりに時間がかかります。ただし、いったん書式情報を抽出すれば、フィルタリング処理なども高速に行えます。

AppleScript名:RTFの読み込み v2.2
– Created 2017-12-10 by Takaaki Naganoya
– Modified 2017-12-11 by Shane Stanley
– Modified 2017-12-11 by Nigel Garvey
– Modified 2017-12-12 by Takaaki Naganoya
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
–http://piyocast.com/as/archives/5020

property NSData : a reference to current application’s NSData
property NSString : a reference to current application’s NSString
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString

set fRes to choose file of type {“public.rtf”}

set aFilePath to NSString’s stringWithString:(POSIX path of fRes)
set aData to NSData’s dataWithContentsOfFile:aFilePath options:0 |error|:(missing value)
set theStyledText to NSMutableAttributedString’s alloc()’s initWithData:aData options:(missing value) documentAttributes:(missing value) |error|:(missing value)

set attrRes to getAttributeRunsFromAttrString(theStyledText) of me
(*
{{stringVal:”abcdefg”, colorStr:”0 0 0″, colorVal:{0, 0, 0}, fontName:”Helvetica”, fontSize:12.0}, {stringVal:”12234534353534″, colorStr:”255 0 0″, colorVal:{255, 0, 0}, fontName:”Helvetica”, fontSize:12.0}, {stringVal:”dewhuiwheiuweriuwherwe”, colorStr:”0 0 0″, colorVal:{0, 0, 0}, fontName:”Helvetica”, fontSize:12.0}, {stringVal:”asda192837137129831″, colorStr:”255 0 0″, colorVal:{255, 0, 0}, fontName:”Helvetica”, fontSize:12.0}}
*)

on getAttributeRunsFromAttrString(theStyledText)
  script aSpd
    property styleList : {}
  end script
  
  
set (styleList of aSpd) to {} —for output
  
  
set thePureString to theStyledText’s |string|() –pure string from theStyledText
  
  
set theLength to theStyledText’s |length|()
  
set startIndex to 0
  
  
repeat until (startIndex = theLength)
    set {theAtts, theRange} to theStyledText’s attributesAtIndex:startIndex longestEffectiveRange:(reference) inRange:{startIndex, theLength - startIndex}
    
    
–String  
    
set aText to (thePureString’s substringWithRange:theRange) as string
    
    
–Color
    
set aColor to (theAtts’s valueForKeyPath:“NSColor”)
    
if aColor is not equal to missing value then
      set aSpace to aColor’s colorSpace()
      
      
set aRed to (aColor’s redComponent()) * 255
      
set aGreen to (aColor’s greenComponent()) * 255
      
set aBlue to (aColor’s blueComponent()) * 255
      
      
set colList to {aRed as integer, aGreen as integer, aBlue as integer} –for comparison
      
set colStrForFind to (aRed as integer as string) & ” “ & (aGreen as integer as string) & ” “ & (aBlue as integer as string) –for filtering
    else
      set colList to {0, 0, 0}
      
set colStrForFind to “0 0 0″
    end if
    
    
–Font
    
set aFont to (theAtts’s valueForKeyPath:“NSFont”)
    
if aFont is not equal to missing value then
      set aDFontName to aFont’s displayName()
      
set aDFontSize to aFont’s pointSize()
    end if
    
    
set the end of (styleList of aSpd) to {stringVal:aText, colorStr:colStrForFind, colorVal:colList, fontName:aDFontName as string, fontSize:aDFontSize}
    
set startIndex to current application’s NSMaxRange(theRange)
    
  end repeat
  
  
return (styleList of aSpd)
  
end getAttributeRunsFromAttrString

★Click Here to Open This Script 

2017/12/10 クリップボードに入ったproperty宣言部分を文字列長と文字コードでソート

クリップボードに入ったAppleScriptのproperty宣言部分を文字列長と文字コードでソートしてクリップボードに入れるAppleScriptです。

最近、AppleScript中でCocoaの機能を呼び出す処理を書く際に、プログラムリストが(横に)長くなることを避けるため、冒頭部分にpropertyで各Cocoa Objectへの参照を宣言するようにしていますが、、、、

正直、ここの宣言部分が乱雑なので、清書するために書いたものです。スクリプトメニューに入れて利用することを前提としています。

prop_before.png

property宣言部分をコピーして本Scriptを実行。property宣言部分の文字数が少ない順&文字コード順にソートを行います。

prop_after.png

結果をペースト。より、宣言部分が多いと(見た目の)効果が大きいです。

after2.png

対象がスクリプトエディタだけであれば、スクリプトエディタ自体をAppleScriptからコントロールして、冒頭のproperty宣言部分を抽出してproperty宣言文の構文要素をピックアップし、クリップボードを経由しないで書き換えることも可能です。

ただし、スクリプトエディタ以外の記述ソフト(Script Debugger、ASObjC Explorer 4、Xcode)を利用しているケースが多いことを考慮してクリップボード経由でデータのやり取りを行わせてみました。

AppleScript書類に対してのアクセスについては、正直Script Debuggerよりもスクリプトエディタの方が上(リッチテキスト形式でもアクセスできるので、構文色分けを利用して各種構文要素にアクセス可能)。スクリプト内容を解析して書き換えを行うような用途については、「Piyomaru Script Assistant」(電子書籍購入者の方への購入特典)をご利用いただいている方にはそのパワーをご理解いただけると思います。

同ツールはAppleScriptでAppleScriptを解析して、AppleScript自体を書き換えるというコンテクストメニューからのAppleScript呼び出しを超強化したものです。

AppleScript名:クリップボードに入ったproperty宣言部分を文字列長と文字コードでソート
– Created 2017-12-08 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/5014

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

set aStr to (the clipboard)
if aStr = “” then
  display dialog “No Data in Clipboard”
  
return
end if

set aList to paragraphs of aStr
set bList to {}
repeat with i in aList
  set j to contents of i
  
if j ≠ {} then
    set jList to words of j
    
if jList ≠ {} then
      if contents of first item of jList = “property” then
        set curLabel to contents of second item of jList
        
set the end of bList to {aLabel:curLabel, aCon:j}
      end if
    end if
  end if
end repeat

if bList = {} then
  display dialog “Error”
  
return
end if

–昇順ソート
set cList to sort1DListByIndicatedStringLength(bList, “aLabel”, true) of me

–ソートしたlist of recordからaCon(元のproperty宣言行そのもの)を一括で取り出す
set dArray to (NSMutableArray’s arrayWithArray:cList)’s valueForKeyPath:“aCon”

–listをテキストに
set dStr to retStrFromArrayWithDelimiter(dArray, return) of me

set the clipboard to dStr

–1D Listを文字列長でソート v2
on sort1DListByIndicatedStringLength(aList as list, aSortKey as string, sortOrder as boolean)
  set aArray to NSArray’s arrayWithArray:aList
  
set descLabel1 to NSString’s stringWithString:(aSortKey & “.length”)
  
set descLabel2 to NSString’s stringWithString:aSortKey
  
set desc1 to NSSortDescriptor’s sortDescriptorWithKey:descLabel1 ascending:sortOrder
  
set desc2 to NSSortDescriptor’s sortDescriptorWithKey:descLabel2 ascending:true selector:“localizedCaseInsensitiveCompare:”
  
set bArray to aArray’s sortedArrayUsingDescriptors:{desc1, desc2}
  
return bArray as list
end sort1DListByIndicatedStringLength

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

★Click Here to Open This Script 

2017/12/08 指定文字の花文字を取得してRTFで書き出す

指定文字の花文字を取得して、収録グリフ数が10,000以上のフォントから30をデスクトップにRTFで書き出すAppleScriptです。

注意:ただし、本ScriptはRetina Display未対応です

hanamoji1.png

前のバージョンからの改良点は、

 〇慊衒源が指定フォント中にグリフを持っているかどうかチェックしてから処理
 ▲ぅ鵐好函璽襪気譴討い襯侫ント数が少ない場合への対処

といったところです。

花文字作成部分の処理内容は、

 ”漸荵慊衒源を収録しているフォントの一覧を取得
 ↓,納萋世靴織侫ントのうち、グリフ数が10,000以上のものをピックアップ
 スタイル付きテキストを作成。仕上がり(描画)サイズを取得
 せ転紊りサイズでRaw画像を作成
 ズ鄒したRaw画像を塗りつぶす(White)
 ε匹蠅弔屬靴Raw画像にスタイル付きテキストを描画
 Raw画像の各座標から色情報をピックアップ、指定スレッショルド値以上であればドットが存在していると判定
 ┘疋奪箸存在している場合には描画文字列を、存在していない場合にはスペースを配列に追加
 作成した2次元配列をテキストに変換。フォント名をテキストに含める指定を行なっている場合にはフォントのPostScript名を文字列に出力

というところです。

これまでは(macOS 10.10より前)AppleScriptで画像処理を行おうとすると、Photoshopあたりで処理するのが定番でしたが、Cocoaの機能を利用することで、カラープロファイル処理が厳密に求められるような内容でなければPhotoshopなしでけっこうな処理が行えるようになってきました。

テキスト処理において(文字コード自動判別が可能になったため)テキストエディタが要らなくなってきたように、データベース処理で(小規模データであれば)FileMaker Proが要らなくなってきて、同様に画像処理でもPhotoshopなしで処理できるものが増えてきた今日このごろです。

AppleScript名:指定文字の花文字を取得してRTFで書き出す
– Created 2017-11-19 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/5012

property NSArray : a reference to current application’s NSArray
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 NSUUID : a reference to current application’s NSUUID
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
property NSColorSpace : a reference to current application’s NSColorSpace
property NSFontManager : a reference to current application’s NSFontManager
property NSPredicate : a reference to current application’s NSPredicate
property NSDictionary : a reference to current application’s NSDictionary

set aString to “あ”
set hanaMax to 30
set hanaSize to 36
set targFontName to “Osaka-Mono” –”Courier New”–結果を出力するRTFのフォント名(PostScript名)

set fRes to getEveryFontPSNameANdGlyphsNum() of me
set theArray to NSArray’s arrayWithArray:fRes
set thePred to NSPredicate’s predicateWithFormat:“fontNum > 10000″
set bArray to (theArray’s filteredArrayUsingPredicate:thePred) as list

if hanaMax > (length of bArray) then
  set hanaMax to (length of bArray)
end if

set aCount to 1

repeat hanaMax * 2 times
  set aFontName to contents of item aCount of bArray
  
  
–花文字文字列を作成
  
set fRes to getHanamojiStr(hanaSize, fontName of aFontName, aString, 0.7, true) of me
  
if fResfalse then
    –StyledStringで結果出力(RTFとしてファイル保存)
    
set aStyledStr to makeRTFfromParameters(fRes, targFontName, 11, 0.0, 0.0) of me
    
set aRange to current application’s NSMakeRange(0, aStyledStr’s |length|())
    
set aVal1 to NSFont’s fontWithName:targFontName |size|:11
    
    
aStyledStr’s beginEditing()
    (
aStyledStr’s addAttribute:(NSFontAttributeName) value:aVal1 range:aRange)
    
aStyledStr’s endEditing()
    
    
set targFol to POSIX path of (path to desktop)
    
set aUUID to NSUUID’s UUID()’s UUIDString() as text
    
set bRes to my saveStyledTextAsRTF(aUUID, targFol, aStyledStr) –RTFで書き出す
    
    
set aCount to aCount + 1
    
if aCount > hanaMax then exit repeat
  end if
end repeat

–花文字文字列を計算して返す
on getHanamojiStr(aFontSize as real, aFontName as string, aString as string, aThread as real, incFontName as boolean)
  if length of aString is not equal to 1 then return false
  
  
–指定文字コードが指定フォント中に存在するかチェック
  
set fRes to retGlyphsInFont(aFontName, id of aString) of me
  
if fRes = false then return false
  
  
set aThreadShould to 768 * aThread
  
if (chkMultiByteChar(aString) of me) = false then
    set spaceChar to string id 12288 –全角スペース(UTF-16)
  else
    set spaceChar to string id 32 –半角スペース
  end if
  
  
set fillColor to NSColor’s whiteColor –塗り色
  
set bString to aString & ” “ –処理内容の帳尻合わせ(そのままだと右端が欠けるのでスペースを入れた)
  
set anAssrStr to makeRTFfromParameters(bString, aFontName, aFontSize, -2, (aFontSize * 1.2)) of me
  
set aSize to anAssrStr’s |size|()
  
  
if class of aSize = record then
    set attrStrWidth to width of aSize
    
set attrStrHeight to height of aSize
  else if class of aSize = list then –macOS 10.13.xのバグ回避
    copy aSize to {attrStrWidth, attrStrHeight}
  end if
  
  
set {xPos, yPos} to {0, 0}
  
  
set tmpImg1 to makeImageWithFilledColor(attrStrWidth, attrStrHeight, fillColor) of me
  
set tmpImg2 to drawAttributedStringsOnImage(tmpImg1, anAssrStr, xPos, yPos) of me
  
set aRawimg to NSBitmapImageRep’s imageRepWithData:(tmpImg2’s TIFFRepresentation())
  
  
–画像から順次指定座標の色データを拾って花文字listに反映
  
set strList to {}
  
repeat with y from 1 to attrStrHeight - 1
    
    
set strListX to {}
    
repeat with x from 0 to attrStrWidth - 1
      set tmpCol to getColorFromRawImage(aRawimg, x, y) of me
      
      
if tmpCol is not equal to false then
        if tmpCol is not equal to {255, 255, 255} then
          copy tmpCol to {tmpR, tmpG, tmpB}
          
if (tmpR + tmpG + tmpB) < aThreadShould then
            set the end of strListX to aString
          else
            set the end of strListX to spaceChar
          end if
        else
          set the end of strListX to spaceChar
        end if
      end if
      
    end repeat
    
set the end of strList to strListX
  end repeat
  
  
–2D List→Text
  
set aRes to list2dToStringByUsingDelimiters(strList, “”, return) of me
  
  
if incFontName = true then
    set fName to getDisplayedNameOfFont(aFontName) of me
    
set aRes to “■” & fName & return & return & aRes
  end if
  
  
return aRes
end getHanamojiStr

–指定Raw画像中の指定座標のピクセルの色をRGBで取り出す
on getColorFromRawImage(aRawimg, x as real, y as real)
  set origColor to (aRawimg’s colorAtX:x y:y)
  
set srgbColSpace to NSColorSpace’s deviceRGBColorSpace
  
if srgbColSpace = missing value then return false
  
  
set aColor to (origColor’s colorUsingColorSpace:srgbColSpace)
  
  
set aRed to (aColor’s redComponent()) * 255
  
set aGreen to (aColor’s greenComponent()) * 255
  
set aBlue to (aColor’s blueComponent()) * 255
  
  
return {aRed as integer, aGreen as integer, aBlue as integer}
end getColorFromRawImage

–画像のうえに指定のスタイル付きテキストを描画して画像を返す
on drawAttributedStringsOnImage(anImage, anAssrStr, xPos as real, yPos as real)
  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)
  set aVal1 to NSFont’s fontWithName:fontName |size|:aFontSize
  
set aKey1 to (NSFontAttributeName)
  
  
set aVal2 to NSColor’s blackColor()
  
set aKey2 to (NSForegroundColorAttributeName)
  
  
set aVal3 to aKerning
  
set akey3 to (NSKernAttributeName)
  
  
set aVal4 to 0
  
set akey4 to (NSUnderlineStyleAttributeName)
  
  
set aVal5 to 2 –all ligature ON
  
set akey5 to (NSLigatureAttributeName)
  
  
set aParagraphStyle to NSMutableParagraphStyle’s alloc()’s init()
  
aParagraphStyle’s setMinimumLineHeight:(aLineSpacing)
  
aParagraphStyle’s setMaximumLineHeight:(aLineSpacing)
  
set akey7 to (NSParagraphStyleAttributeName)
  
  
set keyList to {aKey1, aKey2, akey3, akey4, akey5, akey7}
  
set valList to {aVal1, aVal2, aVal3, aVal4, aVal5, aParagraphStyle}
  
set attrsDictionary to NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
  
  
set attrStr to NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary
  
return attrStr
end makeRTFfromParameters

–指定サイズの画像を作成し、背景を指定色で塗る
on makeImageWithFilledColor(aWidth as real, aHeight as real, 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}, {width:aWidth, height:aHeight}}
  
set theNSBezierPath to NSBezierPath’s bezierPath
  
theNSBezierPath’s appendBezierPathWithRect:theRect
  
fillColor’s |set|()
  
theNSBezierPath’s fill()
  
anImage’s unlockFocus()
  
  
return anImage
end makeImageWithFilledColor

–2D Listをアイテム間および行間のデリミタを個別に指定してテキスト変換
on list2dToStringByUsingDelimiters(aList as list, itemDelimiter, lineDelimiter)
  set outList to {}
  
repeat with i in aList
    set aStr to listToStringUsingTextItemDelimiter(i, itemDelimiter) of me
    
set the end of outList to aStr
  end repeat
  
  
set bStr to listToStringUsingTextItemDelimiter(outList, lineDelimiter) of me
  
return bStr
end list2dToStringByUsingDelimiters

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

–ユーザー環境にインストールされているすべてのフォントのPostScript名とグリフ数を返す
on getEveryFontPSNameANdGlyphsNum()
  set aFontList to NSFontManager’s sharedFontManager()’s availableFonts()
  
set thePred to NSPredicate’s predicateWithFormat:“NOT SELF BEGINSWITH ’.’”
  
set aFontList to (aFontList’s filteredArrayUsingPredicate:thePred) as list
  
  
set aList to {}
  
repeat with i in aFontList
    set aName to contents of i
    
set aNum to countNumberOfGlyphsInFont(aName) of me
    
set the end of aList to {fontName:aName, fontNum:aNum}
  end repeat
  
  
return aList
end getEveryFontPSNameANdGlyphsNum

–指定Postscript名称のフォントに定義されている文字数を数えて返す
on countNumberOfGlyphsInFont(fontName as string)
  set aFont to NSFont’s fontWithName:fontName |size|:9.0
  
if aFont = missing value then return false
  
set aProp to aFont’s numberOfGlyphs()
  
return aProp as number
end countNumberOfGlyphsInFont

–フォントのPostScript NameからDisplayed Nameを取得
on getDisplayedNameOfFont(aName as string)
  set aFont to NSFont’s fontWithName:aName |size|:9.0
  
set aDispName to (aFont’s displayName()) as string
  
return aDispName
end getDisplayedNameOfFont

–全角文字が存在するか
on chkMultiByteChar(checkString as string)
  set aStr to NSString’s stringWithString:checkString
  
set aRes to aStr’s canBeConvertedToEncoding:(current application’s NSASCIIStringEncoding)
  
return (aRes as boolean)
end chkMultiByteChar

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(aFileName as string, targFol as string, aStyledString)
  set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to 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 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

–指定名称のフォントに指定の文字コードが含まれているかチェック
on retGlyphsInFont(fontName as string, strCode as integer)
  set aFont to NSFont’s fontWithName:fontName |size|:24.0
  
if aFont = missing value then return false
  
set aSet to aFont’s coveredCharacterSet()
  
set aRes to (aSet’s characterIsMember:strCode) as boolean
  
return aRes as list of string or string –as anything
end retGlyphsInFont

★Click Here to Open This Script 

2017/12/06 指定フォルダ以下のテキストファイルのファイル名のうち連番部分を抽出して、欠落や重複を検出する

指定フォルダ以下の指定形式のファイルのファイル名をSpotlightですべて取得し、重複や連番部分の欠落を抽出するAppleScriptです。

しょっちゅう同じようなScriptを作っているような気もしますが、それだけ個人的な必要度が高いものかもしれません。

連番部分を含む命名規則を持つファイル群、

  1AXXXXXX-101.txt
  1AXXXXXX-72.txt
  1AXXXXXX-9.txt

から(ファイル名はサンプル)、ファイル名の共通部分をスキャンして、ファイルごとに変更になる部分を抽出しています。一応、ねんのために拡張子を外したデータを処理しています。

ファイル名の共通部分をデータ同士から抽出する、というのが本Scriptの新機軸です。

データすべてから変更部分を取得するのではなく、データの文字数の最大、最小を取得し、それぞれの文字列に該当するデータを10件ずつピックアップし、その間で変更部分の検出を行なっています。

こうした「固定部分の自動検出」というのは、仕様がきちんと存在していない仕事において必要になってくると思われます。すべてのファイル名データから命名ルールを自動検出したり、例外に該当するものを除外したり、ということも考えられそうです。

なお、実行には、Shane StanleyのAppleScriptライブラリ「Metadata Lib」および「BridgePlus」のインストールを必要とします。

AppleScript名:指定フォルダ以下のテキストファイルのファイル名のうち連番部分を抽出して、欠落や重複を検出する
– Created 2017-12-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use mdLib : script “Metadata Lib” version “1.0.0″
use bPlus : script “BridgePlus”
–http://piyocast.com/as/archives/5011

property NSCountedSet : a reference to current application’s NSCountedSet
property NSMutableArray : a reference to current application’s NSMutableArray
property SMSForder : a reference to current application’s SMSForder
property NSMutableSet : a reference to current application’s NSMutableSet
property NSIndexSet : a reference to current application’s NSIndexSet

set origFol to (POSIX path of (choose folder))
set txtFiles to mdLib’s searchFolders:{origFol} searchString:“kMDItemContentType == %@” searchArgs:{“public.plain-text”}

–ファイル名部分から拡張子を削除して収集
set anArray to ((current application’s NSMutableArray’s arrayWithArray:txtFiles)’s valueForKeyPath:“lastPathComponent.stringByDeletingPathExtension”)

–ファイル名文字列リストから、共通部分(変更のない部分)を抽出
set intStr to retInterSectionStr(anArray) of me

set cList to {}
repeat with i in (anArray as list)
  set aRes to repChar(i as string, intStr, “”) of me
  
set aNumF to chkNumeric(aRes) of me
  
if aNumF = true then
    set the end of cList to aRes as integer
  else
    log i
  end if
end repeat

set aRes to calcGaps(cList) of me
set bRes to returnDuplicatesOnly(cList) of me

return {gaps:aRes, dups:bRes}
–>  {gaps:{195, 284, 285}, dups:{}}

–与えられた文字列リストのうち、文字列共通部分を抽出
on retInterSectionStr(anArray)
  set aMin to (anArray’s valueForKeyPath:“@min.length”) as integer
  
set aMax to (anArray’s valueForKeyPath:“@max.length”) as integer
  
  
set bList to {}
  
repeat with i from aMin to aMax
    set aCount to 0
    
    
repeat with ii in (anArray as list)
      set aLen to length of ii
      
if aLen = i then
        set the end of bList to contents of ii
        
if aCount = 10 then
          exit repeat
        else
          set aCount to aCount + 1
        end if
      end if
    end repeat
    
  end repeat
  
  
set aStr to contents of first item of bList
  
set bList to rest of bList
  
  
repeat with i in bList
    set bStr to contents of i
    
set intStr to calcIntersection(aStr, bStr) of me
    
if intStr = false then
      exit repeat
    else
      copy intStr to aStr
    end if
  end repeat
  
  
return aStr
end retInterSectionStr

–2つの文字列から共通部分を(先頭から)抽出
on calcIntersection(aStr, bStr)
  set aList to characters of aStr
  
set bList to characters of bStr
  
  
set aLen