Archive for 3月, 2017

2017/03/31 簡単ツイート収集_search

Apitoreの「簡単ツイート収集」REST APIを呼び出して、指定キーワードによるTweet内容の検索を行うAppleScriptです。

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

また、Twitterのサービスとの連携をオンにするために、Apitoreのマイページから「Twitterと連携する」をクリックし、ApitoreをTwitterとアプリ連携してください。

AppleScript名:簡単ツイート収集_search
– Created 2017-03-29 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4572

set aQuery to “#07Itakura”
set aResList to twitterSearchByQuery(aQuery) of me
–> {tweets:{{sentiment:missing value, favoritedCount:409, source:”Echofon“, retweetCount:392, userId:371790917, userName:”機動戦士ガンダム第07板倉小隊”, userScreenName:”07itakura”, text:”【お知らせ】本日放送した板倉小隊特番のアーカイブを明日26日の昼12時から板倉小隊のHPにて1ヵ月限定で配信決定!見逃してしまった方、もう一度見たいという方、ぜひお楽しみに! https://t.co/Q9q6VhiNGU #07itakura”, statusId:8.45606316664021E+17, sentimentScore:missing value, retweeted:false, favorited:false, createdAt:1.490443231E+12, userProfileImageURL:”http://pbs.twimg.com/profile_images/2578804231/hmzlhl1aaxaen8nf8i5b_normal.png”},….

on twitterSearchByQuery(aQuery)
  set reqURLStr to “https://api.apitore.com/api/23/twitter/search”
  
set accessToken to retAccessToken() —Access Token
  
set aRec to {access_token:accessToken, q:aQuery, sinceId:“-1″, maxId:“-1″, iter:“1″}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL) of me
  
set aRESCode to (responseCode of aRes) as integer
  
set aRESTres to (json of aRes) as record
  
  
return aRESTres
end twitterSearchByQuery

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

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

on retAccessToken()
  return “XXXXxxxX-xxxx-XXXx-xxxX-XxxxXxXxxXXx” –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

2017/03/29 URLの文字列から(主に後ろに)スペースでつながった不要部分が存在する場合には除去

URL文字列の後ろから、スペース文字(%20)でつながった不要部分が存在する場合には除去するAppleScriptです。

Wikipedia上で自分が書いた記事内のリンク先URLを自動でチェックしたくて、REST API経由でWikipediaの記事のソース文字列を取得し、NSDataDetectorを呼び出してURLのみを抽出。抽出したURLが実際に存在するか、存在する場合でもForwardされていないかどうかといった情報をチェックするAppleScriptを書いてみました(このぐらいは余裕)。

ところが、書いたAppleScriptを実行すると大量にエラーのURLが見つかりました。エラーになったURLを実際に確認してみても、ページは存在するし削除されたわけでもなさそうでした。

さらに調査してみると、NSDataDetectorがWikipediaのソース文字列からURLを抽出するときに、URLのあとに半角スペースに続いて英数字が存在すると「URLの一部」としてURLエンコーディングしてURLの一部として取り込んでしまっているようでした。

そこで、いったん存在確認でNGが出たURLについては、本ルーチンでクリーニングを行って再度存在確認を実施するようにしてみました。このように対策してみると、きちんとURLの存在を確認できました。

AppleScript名:URLの文字列から(主に後ろに)スペースでつながった不要部分が存在する場合には除去
– Created 2017-03-29 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4571

set aStr to “https://developer.apple.com/library/mac/documentation/” & “AppleScript/Conceptual/AppleScriptX/AppleScriptX.html%20AppleScript%20Overview”
set aRes to cleaningURLStr(aStr) of me
–>
(*
“https://developer.apple.com/library/mac/documentation/
AppleScript/Conceptual/AppleScriptX/AppleScriptX.html”
*)

on cleaningURLStr(aStr)
  set anOffset to offset of “%20″ in aStr
  
if anOffset = 0 then return false
  
set bStr to text 1 thru (anOffset - 1) of aStr
  
return bStr
end cleaningURLStr

★Click Here to Open This Script 

2017/03/28 Keynote/Pages/Numbersがアップデート

Keynote/Pages/Numbersがアップデートし、それぞれKeynote 7.1、Pages 6.1、Numbers 4.1になりました(要macOS 10.12)。

■Keynote 7.1.0
–AppleScript用語辞書の変更点
・current slideがread only属性ではなくなった
・image formatで指定できる値が変更された
small / medium / large –> 60p / 540p / 720p / 1080p / 2160p / native size
・movie formatで指定できる値が変更された
small / medium / large –> 360p / 540p / 720p / 1080p / 2160p / native size
–機能上の変更点
・PDF書き出しをmacOS 10.12.4上で行えるようになった(権限エラーが出なくなった)

■Pages 6.1.0
–AppleScript用語辞書の変更点
・exportコマンドで指定できるフォーマットとして「formatted text」が追加された(RTF?)
–機能上の変更点
・PDF書き出しをmacOS 10.12.4上で行えるようになった(権限エラーが出なくなった)

2017/03/28 macOS 10.12のsayコマンドのバグはNSSpeechSynthesizerのレベルで発生

macOS 10.12.4アップデートがリリースされましたが、不可解なバグや理解しにくい仕様の多くはいまだ解消されていません。

# FAX modemのサポート機能を削ったのはやりすぎだろう(ーー;

そのうちの1つである、sayコマンドで日本語の特定のテキスト読み上げに失敗するというバグ。これを回避するために、NSSpeechSynthesizerを直接呼び出すテストを行ってみたところ、sayコマンドと同様のおかしな音声出力が得られました。

一応、Voice側に問題がある可能性を考慮して、OtoyaとKyokoの両方のVoiceでチェックしてみましたが、両方で同じ現象が発生します。このため、NSSpeechSynthesizerにバグがあるか、OtoyaとKyokoの両方のVoiceに問題があるかといったところなんでしょう。

このレベルで問題があるということは、iOS側でも同じ問題があるのではないかと考え、iOS 10.3上でも読み上げを確認してみたところ、「もげる」→「もげ」、「捥げる」→(読み上げすらしない) と、同様に問題があることがわかりました。

AppleScript名:NSSpeechSynthesizerのバグ
– Created 2017-03-28 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/4569

set vList to {“com.apple.speech.synthesis.voice.otoya.premium”, “com.apple.speech.synthesis.voice.kyoko.premium”}

repeat with i in vList
  set aSynth to (current application’s NSSpeechSynthesizer’s alloc()’s initWithVoice:i)
  
if aSynth is not equal to missing value then
    (aSynth’s startSpeakingString:げる”) –> “げる”(Bug)
    
delay 1
    (
aSynth’s startSpeakingString:“もげる”) –> “もげ”(Bug)
    
delay 1
  end if
end repeat

★Click Here to Open This Script 

2017/03/27 実体参照している文字列をデコードする(ASOC)

HTMLの中などで実体参照(Character reference)しているエンコードされた文字列をデコードするAppleScriptのCocoa呼び出し版です(Pure AppleScript版はこちら)。

AppleScript名:実体参照している文字列をデコードする(ASOC)
– Created 2017-01-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4568

set aStr to "龍馬伝"
set aRes to decodeCharacterReference(aStr) of me
–>  "龍馬伝"

set aStr to "\"第2エア\""
set aRes to decodeCharacterReference(aStr) of me
–>  "\"第2エア\""

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/03/26 WebKit Utilitiesで指定URLをウィンドウ表示

AppleScript Libraries「WebKit Utilities」で指定のURLのWebの内容をウィンドウで表示するAppleScriptです。

AppleScriptでCocoaを直接コントロールできるようになって、WebKitを操作してWebサイトの内容を表示させることはいろいろやってみました。ただ、表示するだけならSafariのほうが機能がリッチなので、表示させるだけではあまりメリットがありません。

個人的な用途であれば、Safariをコントロールする方が、WebKitを呼び出すよりも安心感があって有用性が高いと思われます(ユーザー認証が必要なサイトとか、ダウンロードするような用途とか。YouTubeから指定URLのムービーをダウンロードするぐらいならWebブラウザも何もいりませんけれども)。

画面非表示でWebサイトのレンダリング、および操作を行う「オフラインヘッドレスWebブラウザ」でよいのがないか探したいところです。また、Webサイトからデータを取り出す「データマイニング」を行うのにさまざまなフレームワークを使ったり、クラウド系のデータマイニングサービスをREST API経由で呼び出すなど、使える手段はいろいろ使っていきたいところです(並列処理と相性もいいですし)。

AppleScript名:WebKit Utilitiesで指定URLをウィンドウ表示
– Created 2017-03-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use webLib : script “WebKit Utilities”
–http://piyocast.com/as/archives/4566

set targetURL to “http://www.apple.co.jp”
display URL targetURL window size {1024, 1024}

★Click Here to Open This Script 

2017/03/25 Alert Utilitiesでオーバーレイ文字表示を行う

AppleScript Libraries「Alert Utilities」で画面の中央にオーバーレイ表示で半透明のメッセージ表示を行うAppleScriptです。

スクリーンショットでの見た目はいいんですが、普通こういうのを表示するならアルファ値をループで増減させてふわっと表示して、消すときにもふわっと消すような「演出」を行うと思うところですが、そこはそこ。気に入らないところは自分で書き換えるとよいでしょう。

overlay1.png

overlay_resized.png

AppleScript名:Alert Utilitiesでオーバーレイ文字表示を行う
– Created 2017-03-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use textLib : script “Alert Utilities”

set advancedSettings to {background color:{0, 0, 0}, background dimensions:{512, 512}, font color:{65535, 65535, 65535}, opacity:50}

display overlay text “日本語でも” & return & “表示できるね” duration 3 advanced settings advancedSettings without goose honk

★Click Here to Open This Script 

2017/03/24 はじめてresultが役に立った

これまで、「result」が役に立ったことはなく、AppleのサンプルScript中で多用されているのを苦々しく思っておりました。

ところが、クラウド経由で遠隔地のMacにAppleScriptを実行させる仕組みを作っていたとき、たまたま処理結果を返してこないScriptを「run script」コマンドで実行したところ・・・・結果を(なんでもテキスト化して)返す処理部分でエラー。

つまり、run scriptコマンドの結果を代入している変数には何も入っていないので(beepコマンドだし)その変数自体が定義されていないというエラーに。

そこで、直接run scriptコマンドの結果を変数に代入せずに、実行結果をresultから取得。resultから取得する部分にエラートラップを仕掛けて「コマンドの実行結果が、何も値を返さない」パターンに対処するようにしてみました。

これで、無事対応でき、遠隔地の複数のMacにクラウド経由でコマンドを送って結果を取得できるようになりました。実に、はじめてresultが役に立ちました。

Siriみたいな自然言語処理コマンドインタフェースや、音声認識インタフェース、果ては全国規模の分散プリントを実現するGUIアプリケーションまでAppleScriptで作りましたが、resultが役に立ったのはこれがはじめてです。

AppleScript名:はじめてresultが役に立った
run script “beep 1″
try
  set aTmp to result
  
set a to aTmp
on error
  set a to “”
end try

return a

★Click Here to Open This Script 

2017/03/24 Text Utilitiesで文字操作

「Text Utilities」AppleScript Librariesを用いて文字操作を行うAppleScriptです。

同Script Libraryは文字操作を行う機能を提供するもので、AppleScript用語辞書も含んでいるため、英語っぽい記法で記述できます。

同ライブラリをダウンロードして~/Library/Script Librariesフォルダに入れると同ライブラリの命令を使えるようになります。

同ライブラリには基礎的なテキスト操作(大文字/小文字変換、文字置換、文字列の前後の空白削除)の機能を提供するものです。日本語環境でも問題なく利用できるものかどうか、実際に使って試してみました。

どうでもいい話ですが、日本語には複数形の名詞の語尾変化はないので「AppleScript Libraries」という単語はなかなか言いづらいものがあります。「ライブラリ」だけでいいのかも。

本ライブラリは、あまりScriptに親しみのない人が、文字置換とか文字列の前後のスペースを削除したいとかいう「かわいらしい用途」に使うには向いているのではないでしょうか。

ソースを読んでみると、割とCocoaの基礎的な機能を使っているため「Unicodeの特殊文字が置換できない!」とかいう話に対しては応えられないレベルです。

AppleScript名:Text Utilitiesで文字の置換を行う
– Created 2017-03-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use textLib : script “Text Utilities”
–http://piyocast.com/as/archives/4561

set aStr to “日本語のテキストだよ”
set bStr to replace text “日本語” with “にほんご” in aStr
–>  ”にほんごのテキストだよ”

★Click Here to Open This Script 

AppleScript名:Text Utilitiesで文字の置換を行う(複数一括置換)
– Created 2017-03-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use textLib : script “Text Utilities”
–http://piyocast.com/as/archives/4561

set aStr to “日本語のテキストだよ日本語かも日本語だったら日本語なのに”
set bStr to replace text “日本語” with “にほんご” in aStr
–>  ”にほんごのテキストだよにほんごかもにほんごだったらにほんごなのに”

★Click Here to Open This Script 

AppleScript名:Text Utilitiesで文字列の大文字,小文字の変換を行う
– Created 2017-03-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use textLib : script “Text Utilities”
–http://piyocast.com/as/archives/4561

set aStr to “piyomaru software”
set bStr to transform text aStr to upper case
–>  ”PIYOMARU SOFTWARE”

set cStr to transform text bStr to lower case
–>  ”piyomaru software”

set dStr to transform text aStr to word case
–>  ”Piyomaru Software”

★Click Here to Open This Script 

AppleScript名:Text Utilitiesで前後の空白を削除する(1行のテキスト)
– Created 2017-03-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use textLib : script “Text Utilities”
–http://piyocast.com/as/archives/4561

set aStr to ” This string starts with some space characters.この文字列はいくつかの空白文字ではじまっています。”
set bStr to remove white space around aStr
–>  ”This string starts with some space characters.この文字列はいくつかの空白文字ではじまっています。”

set cStr to ” This string starts with some space characters.この文字列は前後にいくつかの空白文字があります。 “
set dStr to remove white space around cStr
–>  ”This string starts with some space characters.この文字列は前後にいくつかの空白文字があります。”

★Click Here to Open This Script 

AppleScript名:Text Utilitiesで前後の空白を削除する(複数行のテキスト)
– Created 2017-03-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use textLib : script "Text Utilities"
–http://piyocast.com/as/archives/4561

set aStr to " This string starts with some space characters.この文字列は前後にいくつかの空白文字があります。
This string starts with some space characters.この文字列は前後にいくつかの空白文字があります。
This string starts with some space characters.この文字列は前後にいくつかの空白文字があります。
This string starts with some space characters.この文字列は前後にいくつかの空白文字があります。
"
set bStr to remove white space around aStr
(*
"This string starts with some space characters.この文字列は前後にいくつかの空白文字があります。
This string starts with some space characters.この文字列は前後にいくつかの空白文字があります。
This string starts with some space characters.この文字列は前後にいくつかの空白文字があります。
This string starts with some space characters.この文字列は前後にいくつかの空白文字があります。
"
*)

★Click Here to Open This Script 

2017/03/23 Sharing UtilitiesでTwitterにメッセージ投稿

「Sharing Utilities Library」を使ってTwitterで指定のメッセージを投稿するAppleScriptです。

Blindでそのまま送信するわけではなく、いったんダイアログが表示されます。

tweet1_resized.png

Twitter投稿ダイアログが表示されるので、

tweet2.png

「Post」をクリックすると、

tweet3.png

Twitterに指定メッセージが投稿されます。以前に掲載した「ASOCでTwitter投稿」と処理内容は一緒です。

blindで投稿したい場合には、コマンドラインから使うTwitterクライアント「tw」を呼び出す方法がおすすめです。

AppleScript名:Sharing UtilitiesでTwitterにメッセージ投稿
– Created 2017-03-23 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use shareLib : script “Sharing Utilities”
–http://piyocast.com/as/archives/4556

tweet text “ぴよー”

★Click Here to Open This Script 

2017/03/23 Sharing UtilitiesでAirDrop経由のファイル送信を行う

AirDrop経由でファイルを他のMacに送信するAppleScriptです。

ファイル共有やTwitterでメッセージ共有を行う「Sharing Utilities library」の存在は今日の今日まで知りませんでした(なにそれ?!)。

この「Sharing Utilities library」を用いて、AirDropで他のMacにファイルを送信します。

実行する前提条件は、2台のMacが無線LANで通信可能なこと、あらかじめ双方でAirDropによるファイル送信を行なった実績があること。受信側のMacではFinderの「AirDrop」を選択して受信状態にしてあること(↓ 受信側)。

airdrop0_resized.png

その状態で、送信側のMacで本Scriptを実行すると、

airdrop1.png

相手のMac(MBA11)が見つからないので、「Don’t see who you’re looking for?」をクリック。

airdrop2.png

「Search for an Older Mac」 をクリック。

airdrop3.png

送信先(MBA11)をクリックすると、ファイル送信が開始されます。

airdrop4.png

送信完了。

連続で複数のファイルを送信する場合には、指定フォルダ内のファイルへの参照を取得しておくなどしてください。

airdrop5.png

iPhoneやiPadにも送信できます。ただ、送信したファイルをオープンできるアプリがインストールされていないとどうにもならない感じですけれども(汗)

「Sharing Utilities library」はソースコードも見られるようになっているので、見ておくととても参考になります。

AppleScript名:AirDropでファイルを送信する
– Created 2017-03-23 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use shareLib : script “Sharing Utilities”
–http://piyocast.com/as/archives/4554

set anItem to choose file with prompt “Select File to send via AirDrop”
set aaList to {anItem}
begin AirDrop with aaList

★Click Here to Open This Script 

2017/03/22 NSImageのリサイズ(アンチエイリアス解除)

アンチエイリアスをかけずにNSImageを拡大するAppleScriptです。

何も考えずにNSImageをリサイズするとアンチエイリアスがかかります。これはこれで、写真やスクリーンショットを拡大する場合には助かるわけですが、そういう場合ばかりとはかぎりません。

QRコードやバーコードなど、AppleScriptで作成する機会の増えたこれらの認識用画像データは、そのままではサイズが小さいため、適宜リサイズする必要があります。その際にアンチエイリアスがかかるのは避けたいところ。

ML上で質問してShane Stanleyといろいろやりとりして、「こうしたらいいんじゃないの?」というコードがなかなか動かない。エラーで止まる。自分で調べてみても、どうやらこの方法で間違っていないはず。これで動かないということは、OSのバグ? なんだこりゃ、どうしたら動くんだろう??

bab79125-9bdb-46aa-9849-5793d41a0453_resized.png

Shaneの出した結論が「”Antlialias”と書くべきところを”AntiAlias”と大文字小文字を間違えて書いていた」というもの。これは、エディタ側でもチェック対象外だし、なかなか気づきません(T_T)

c75cc957-5c4c-4f4b-b79c-e0f02a8de207.png
▲普通にQRコード画像を拡大したもの。アンチエイリアスが効いている。iPhoneのカメラで読み取って認識できないわけではないが、気になる

a9cf82f4-7f1c-4aa0-93d0-d034e164d7e0.png
▲本ScriptでQRコード画像を拡大したもの。アンチエイリアスを無効化できている

AppleScript名:NSImageをリサイズ(アンチエイリアス解除)pattern 4
– Created 2017-02-03 by Takaaki Naganoya
– Modified 2017-03-22 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
–http://piyocast.com/as/archives/4544

set aPath to POSIX path of (choose file of type {“public.image”} with prompt “Select Image file to scale up (x10)”)
set aNSImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aPath

set resizedImg to my resizeNSImageWithoutAntlialias:aNSImage toScale:10

set aDesktopPath to (current application’s NSProcessInfo’s processInfo()’s environment()’s objectForKey:(“HOME”))’s stringByAppendingString:“/Desktop/”
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.png”)
set fRes to saveNSImageAtPathAsPNG(resizedImg, savePath) of me

–NSImageを指定倍率で拡大(アンチエイリアス解除状態で)
on resizeNSImageWithoutAntlialias:aSourceImg toScale:imgScale
  set aSize to aSourceImg’s |size|()
  
set aWidth to (aSize’s width) * imgScale
  
set aHeight to (aSize’s height) * imgScale
  
  
set aRep to current application’s NSBitmapImageRep’s alloc()’s initWithBitmapDataPlanes:(missing value) pixelsWide:aWidth pixelsHigh:aHeight bitsPerSample:8 samplesPerPixel:4 hasAlpha:true isPlanar:false colorSpaceName:(current application’s NSCalibratedRGBColorSpace) bytesPerRow:0 bitsPerPixel:0
  
  
set newSize to {width:aWidth, height:aHeight}
  
aRep’s setSize:newSize
  
  
current application’s NSGraphicsContext’s saveGraphicsState()
  
  
set theContext to current application’s NSGraphicsContext’s graphicsContextWithBitmapImageRep:aRep
  
current application’s NSGraphicsContext’s setCurrentContext:theContext
  
theContext’s setShouldAntialias:false
  
theContext’s setImageInterpolation:(current application’s NSImageInterpolationNone)
  
  
aSourceImg’s drawInRect:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) fromRect:(current application’s NSZeroRect) operation:(current application’s NSCompositeCopy) fraction:(1.0)
  
  
current application’s NSGraphicsContext’s restoreGraphicsState()
  
  
set newImg to current application’s NSImage’s alloc()’s initWithSize:newSize
  
newImg’s addRepresentation:aRep
  
  
return newImg
end resizeNSImageWithoutAntlialias:toScale:

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

★Click Here to Open This Script 

2017/03/21 CoreImage(CIFilter)で指定画像を2階調ポスタライズ v2

CoreImageのCIFilterを用いて、指定の画像を2階調でポスタライズするAppleScriptです。

CPUImageにも同様のポスタライズ用のフィルタが存在しているのですが、パラメータを指定してもうまく効かなかったので、CIFilterを使ってみました。

6ba2129c-12c5-42bf-b1a6-48dc883a97ec.png
▲実行前

81421d35-72aa-4d9d-9e6b-e2c59f9c9109.png
▲実行後

AppleScript名:CoreImageで指定画像を2階調ポスタライズ v2
– Created 2017-03-21 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “QuartzCore”
–http://piyocast.com/as/archives/4541

–画像を選択
set aPath to POSIX path of (choose file of type {“public.image”})
set aNSImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aPath

set imgRes to execCIFilterWithNSImage(aNSImage, “CIColorPosterize”) of me

set aDesktopPath to (current application’s NSProcessInfo’s processInfo()’s environment()’s objectForKey:(“HOME”))’s stringByAppendingString:“/Desktop/”
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.png”)

set fRes to saveNSImageAtPathAsPNG(imgRes, savePath) of me

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

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

–NSImageをCIImageに変換してCIfilterを実行
on execCIFilterWithNSImage(aNSImage, aFilterName)
  set aCIImage to convNSImageToCIimage(aNSImage) of me
  
  
set aFilter to current application’s CIFilter’s filterWithName:aFilterName
  
aFilter’s setDefaults()
  
aFilter’s setValue:aCIImage forKey:“inputImage”
  
aFilter’s setValue:2 forKey:“inputLevels”
  
set aOutImage to aFilter’s valueForKey:“outputImage”
  
  
set newNSImage to convCIimageToNSImage(aOutImage) of me
  
return newNSImage
end execCIFilterWithNSImage

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

★Click Here to Open This Script 

2017/03/21 CIImageとNSImageの相互変換

CIImageとNSImageの相互変換を行うAppleScriptです。

ファイル入出力をはじめ、さまざまな処理を行う場合にはNSImageで指定するように各種ライブラリの入出力を統一するようにしています。そのため、CIFilterを利用するような場合でもNSImageで画像データを渡すようにしています。

CIFilterを実行するサブルーチン内では、CoreImageで画像データを扱うのでCIImageで画像を渡す必要があるためCIImageに変換してFilter処理を行い、その後にNSImageに変換して結果を返すようにしています。

似たような名前のオブジェクトとして「CGImage」(CoreGraphicsの)がありますが、これはAppleScript側からは手が出ないオブジェクトに見えます。少なくとも、自分はCGImageと他フォーマットとの変換についてはやり方はわかりません。

AppleScript名:CIImageとNSImageの相互変換
– Created 2017-03-21 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "QuartzCore"
–http://piyocast.com/as/archives/4540

–Get Computer Icon (NSImage)
set anImage to current application’s NSImage’s imageNamed:(current application’s NSImageNameComputer)

set aCIImage to convNSImageToCIimage(anImage) of me
–> (CIImage)

set bNSImage to convCIimageToNSImage(aCIImage) of me
–> (NSImage)

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

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

★Click Here to Open This Script 

2017/03/19 QuickTime Player+macOS Sierraでのファイル保存

macOS 10.12上でQuickTime PlayerをAppleScriptからコントロールして、デスクトップ上にムービーを保存しようとすると、エラーが出て実行できません。

mov1.png

mov2.png

AppleScriptを実行すると、まずQuickTime Player側で「権限がない」云々というエラーが表示され、QuickTime Player側のエラーダイアログをクリックすると、スクリプトエディタ側でエラーが表示されます。

Appleにバグレポートしておきましたが、Apple的にはバグではなく「仕様」だと見なされている可能性があります。

デスクトップにムービーを保存することはできませんでしたが、ためしてみたら「ムービー」フォルダに保存することはできました

こういう「仕様」を説明もなしに決定されるのは迷惑ですし、きちんとリリースノートなどで説明してほしいものです。

AppleScript名:QTPlayerのバグ再現
set a to (choose file name) as string

tell application “QuickTime Player”
  tell document 1
    save in file a
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:QTPlayerのバグ再現2
set a to (choose file name)

tell application “QuickTime Player”
  tell document 1
    save in a
  end tell
end tell

★Click Here to Open This Script 

2017/03/18 文字を集合(CountedSet)に変換して文字列同士の近似度を計算する v3

複数の文字列同士の近似度を擬似的に計算できないかと考えて、文字列をCountedSetに変換して、CountedSet同士で演算(intersectSet, minusSet)を実行。その計算結果を加味して「文字列中に含まれている文字列の傾向が似ている」と判断するテストのAppleScriptです。

結局、いちばん差分が小さくて(minusSet)、重複部分が大きい(intersectSet)ものを「一番似ている」ものとして扱うようにソートして求めてみました。

実際には、こんな小さい文字列同士のデータの傾向ではなく、もっと大きな文字列同士の傾向を比較することを念頭に置いています。

今回は文字を分解して「文字」同士で比較していますが、「単語」で比較したほうがいいんだろうか、文字のままでいいんだろうかなど、結論は出ていないので実際のデータでいろいろ試してみたいところです。

AppleScript名:文字を集合(CountedSet)に変換して文字列同士の近似度を計算する v3
– Created 2017-03-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4534

set aStr to "This is a pinnapple."
set bStr to "This is an apple."
set cStr to "Piyomaru San Dayo."

set aRes to stringDifferenceWithAppearance(aStr, bStr, "A & B") of me
–>  {intersect:11, minus:3}

set bRes to stringDifferenceWithAppearance(bStr, cStr, "B & C") of me
–>  {intersect:5, minus:8}

set cRes to stringDifferenceWithAppearance(cStr, aStr, "C & A") of me
–>  {intersect:5, minus:9}

–結果をソートする
set allRes to current application’s NSArray’s arrayWithArray:{aRes, bRes, cRes}
set aSortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:"intersect" ascending:false
set bSortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:"minus" ascending:true
set aSortedArray to allRes’s sortedArrayUsingDescriptors:{aSortDesc, bSortDesc}

–もっとも似ている傾向を持つデータの組み合わせ
set aMostApproximative to aSortedArray’s firstObject() as record
–>  {minus:3, dataLabel:"A & B", intersect:11}

–文字列同士の近似傾向を、相違点と重複箇所の2つの方向から計算する
on stringDifferenceWithAppearance(aStr, bStr, aLabel)
  set aMinus to getApproximationBetweenStrings(aStr, bStr) of me
  
set aIntersect to getApproximationBetweenStringsIntersect(aStr, bStr) of me
  
return {intersect:aIntersect, minus:aMinus, dataLabel:aLabel}
end stringDifferenceWithAppearance

–与えられた文字列同士の相違点を計算する(結果がより小さい値のデータ同士が似ている)
on getApproximationBetweenStrings(aStr, bStr)
  set aList to current application’s NSMutableArray’s arrayWithArray:(characters of aStr)
  
set bList to current application’s NSMutableArray’s arrayWithArray:(characters of bStr)
  
  
set aIndex to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bIndex to current application’s NSCountedSet’s alloc()’s initWithArray:bList
  
  
aIndex’s minusSet:bIndex
  
set aRes to aIndex’s allObjects()’s |count|()
  
  
bIndex’s minusSet:aIndex
  
set bRes to bIndex’s allObjects()’s |count|()
  
  
if aRes bRes then
    return bRes
  else
    return aRes
  end if
end getApproximationBetweenStrings

–与えられた文字列同士の重複箇所を計算する(結果がより大きい値のデータ同士が似ている)
on getApproximationBetweenStringsIntersect(aStr, bStr)
  set aList to current application’s NSMutableArray’s arrayWithArray:(characters of aStr)
  
set bList to current application’s NSMutableArray’s arrayWithArray:(characters of bStr)
  
  
set aIndex to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bIndex to current application’s NSCountedSet’s alloc()’s initWithArray:bList
  
  
aIndex’s intersectSet:bIndex
  
set aRes to aIndex’s allObjects()’s |count|()
  
return aRes
end getApproximationBetweenStringsIntersect

★Click Here to Open This Script 

2017/03/18 文字を集合(CountedSet)に変換して文字列同士の近似度を計算する v2

複数の文字列同士の近似度を擬似的に計算できないかと考えて、文字列をCountedSetに変換して、CountedSet同士でand演算(intersectSet)を実行。その計算結果が大きいほど「文字列中に含まれている文字列の傾向が似ている」と判断するテストのAppleScriptです。

countedset_intersect_resized.png

とりあえずはintersectSetで積集合を計算しています。重複している部分を求めているわけです。

 「This is an apple.」と「This is a pinapple.」–> 11
 「This is a pinapple.」と「Piyomaru San Dayo.」–> 5
 「Piyomaru San Dayo.」と「This is an apple.」–> 5

v1とv2の計算結果を合わせて、両方の傾向を反映させるようにするとよいのかもしれません。

AppleScript名:文字を集合(CountedSet)に変換して文字列同士の近似度を計算する v2
– Created 2017-03-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4532

set aStr to "This is a pinnapple."
set bStr to "This is an apple."
set cStr to "Piyomaru San Dayo."

set a1Res to getApproximationBetweenStringsIntersect(aStr, bStr) of me
–>  11

set bRes to getApproximationBetweenStringsIntersect(bStr, cStr) of me
–>  5

set cRes to getApproximationBetweenStringsIntersect(cStr, aStr) of me
–>  5

on getApproximationBetweenStringsIntersect(aStr, bStr)
  set aList to current application’s NSMutableArray’s arrayWithArray:(characters of aStr)
  
set bList to current application’s NSMutableArray’s arrayWithArray:(characters of bStr)
  
  
set aIndex to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bIndex to current application’s NSCountedSet’s alloc()’s initWithArray:bList
  
  
aIndex’s intersectSet:bIndex
  
set aRes to aIndex’s allObjects()’s |count|()
  
return aRes
end getApproximationBetweenStringsIntersect

★Click Here to Open This Script 

2017/03/18 文字を集合(CountedSet)に変換して文字列同士の近似度を計算する v1

複数の文字列同士の近似度を擬似的に計算できないかと考えて、文字列をCountedSetに変換して、CountedSet同士で減算を実行。その計算結果が少ないほど「文字列中に含まれている文字列の傾向が似ている」と判断するテストのAppleScriptです。

countedset.png

とりあえずはminusSetで減算を行なっていますが、ほかの方法も試してみたいところです。

本Scriptでは、得られた結果の数値が小さければ重複している文字が多いということで、計算結果そのものにはあまり意味はありませんが、複数の結果を大小比較して、数値が小さいもののペアが「似たような傾向を持つもの」として期待できます。

 「This is an apple.」と「This is a pinapple.」–> 3
 「This is a pinapple.」と「Piyomaru San Dayo.」–> 8
 「Piyomaru San Dayo.」と「This is an apple.」–> 9

ということで、これらの間では「This is an apple.」と「This is a pinapple.」の近似度が一番高いといえることになります。

AppleScript名:文字を集合(CountedSet)に変換して文字列同士の近似度を計算する v1
– Created 2017-03-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4530

set aStr to “This is a pinnapple.”
set bStr to “This is an apple.”
set cStr to “Piyomaru San Dayo.”

set a1Res to getApproximationBetweenStrings(aStr, bStr) of me
–>  3

set bRes to getApproximationBetweenStrings(bStr, cStr) of me
–>  8

set cRes to getApproximationBetweenStrings(cStr, aStr) of me
–>  9

on getApproximationBetweenStrings(aStr, bStr)
  set aList to current application’s NSMutableArray’s arrayWithArray:(characters of aStr)
  
set bList to current application’s NSMutableArray’s arrayWithArray:(characters of bStr)
  
  
set aIndex to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bIndex to current application’s NSCountedSet’s alloc()’s initWithArray:bList
  
  
aIndex’s minusSet:bIndex
  
set aRes to aIndex’s allObjects()’s |count|()
  
  
bIndex’s minusSet:aIndex
  
set bRes to bIndex’s allObjects()’s |count|()
  
  
if aRes bRes then
    return bRes
  else
    return aRes
  end if
end getApproximationBetweenStrings

★Click Here to Open This Script 

2017/03/16 Dockとメニューバーを隠す→戻す

メニューバーとDockを隠して10秒たったら元に戻すAppleScriptです。

隠すことが目的で、元に戻すのは単なる後片付けです。

Objective-Cの「|」記号がORであることを忘れてしばらく考えてしまいましたが、ORだとわかればEnumを加算して数値で指定すればいいだけなので、パラメータを直接数値で指定しました。

AppleScript名:Dockとメニューバーを隠す→戻す
– Created 2017-03-15 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/4529

–Main MenuとDockを隠す
current application’s NSApplication’s sharedApplication()’s setPresentationOptions:10 –NSApplicationPresentationHideMenuBar | NSApplicationPresentationHideDock

delay 10

–MenuとDockを通常に戻す
current application’s NSApplication’s sharedApplication()’s setPresentationOptions:(current application’s NSApplicationPresentationDefault)

★Click Here to Open This Script 

2017/03/15 Spotlightで指定フォルダ以下の指定文字を含むファイル一覧を取得

Cocoaの機能を呼び出すAppleScriptObjCでは、さまざまなCocoaのAPIを呼び出す手法が模索されてきました。その中でもSpotlight検索は「割とまだ決定版の手法が確立していない」ものでありました。

spotlightでタグを指定して検索
http://piyocast.com/as/archives/3731

ASOCでmdfindするじっけん v4(フルパスを返す)
http://piyocast.com/as/archives/4122

などなど、徐々に進化してきて、Shane StanleyのAppleScript Libraries「BridgePlus」にSpotlightの呼び出し命令が実装されたりと、手段が洗練されてきたという経緯があります。

書籍「AppleScript 10大最新技術」にも掲載していますが、その時点のバージョンよりもはるかにこなれた書き方がML上でShane Stanleyから提示されました。いままでよりもはるかに短いので、ちょっと腰を抜かしてしまったほど。しかも、とてもさりげなく、、、

「ああ、こういう書き方でもいいんだ、、、」

と、かなりすごいことになっています。

AppleScript名:Spotlightで指定フォルダ以下の指定文字を含むファイル一覧を取得
– Created 2017-03-15 By Shane Stanley
use AppleScript version “2.4″ – Yosemite (10.10) or later
use framework “Foundation”
use scripting additions
–http://piyocast.com/as/archives/4528

set thePath to POSIX path of (path to desktop) – whatever

–ファイル名で検索
set theKeyword to “スクリーンショット”
set fResList to my searchPath:thePath searchPredicate:“(kMDItemFSName CONTAINS [c]%@)” predicateArgs:{theKeyword}
–>  {”/Users/me/Desktop/2013/03/スクリーンショット 2016-12-15 8.44.28.png”, “/Users/me/Desktop/FromDesktop/samples/list splitted or broken/スクリーンショット 2015-08-31 10.49.30.png”, …… }

–UTI(File Kind)で検索
set theKeyword to “public.png”
set fResList to my searchPath:thePath searchPredicate:“(kMDItemContentType == [c]%@)” predicateArgs:{theKeyword}
–> {”/Users/me/Desktop/2013/03/スクリーンショット 2016-12-15 8.44.28.png”, “/Users/me/Desktop/FromDesktop/IMG_3143_resized.png”, “/Users/me/Desktop/FromDesktop/asoctable.png”….}

–ファイルの内容で検索
set fResList to my searchPath:thePath searchPredicate:“(kMDItemTextContent == [c]%@)” predicateArgs:{“戦場の絆”}
–>  {”/Users/me/Desktop/2013/01/gundam_games_history.txt”, “/Users/me/Desktop/book1_2.0.pdf”}

on searchPath:thePath searchPredicate:predString predicateArgs:argList
  set thePred to current application’s NSPredicate’s predicateWithFormat:predString argumentArray:argList
  
set targetURL to current application’s |NSURL|’s fileURLWithPath:thePath
  
set theQuery to current application’s NSMetadataQuery’s new()
  
  
theQuery’s setPredicate:thePred
  
theQuery’s setSearchScopes:{targetURL}
  
theQuery’s startQuery()
  
  
repeat while theQuery’s isGathering() as boolean
    delay “0.001″ as real
  end repeat
  
theQuery’s stopQuery()
  
  
set theCount to theQuery’s resultCount()
  
set theResults to current application’s NSMutableArray’s array()
  
  
repeat with i from 1 to theCount
    set aResult to (theQuery’s resultAtIndex:(i - 1))
    
set thePath to (aResult’s valueForAttribute:(current application’s NSMetadataItemPathKey))
    (
theResults’s addObject:thePath)
  end repeat
  
  
return (theResults’s sortedArrayUsingSelector:“compare:”) as list
end searchPath:searchPredicate:predicateArgs:

★Click Here to Open This Script 

2017/03/13 Finderの最前面のウィンドウで選択中のアイテムと非選択アイテムを切り替える

Finderの最前面のウィンドウ中で選択中のアイテムと選択対象外のアイテムを切り替えるAppleScriptです。

finder_anime2.gif

どういう場面において便利なのかは不明ですが、、、、

AppleScript名:Finderの最前面のウィンドウで選択中のアイテムと非選択アイテムを切り替える
– Created 2017-03-12 by Takaaki Naganoya
– 2017 Piyomaru Software
–http://piyocast.com/as/archives/4526
tell application "Finder"
  if (count every window) = 0 then return
  
set aSel to selection as alias list
  
  
tell window 1
    set aList to (every file) as alias list
  end tell
  
  
set newSel to {}
  
repeat with i in aList
    set j to contents of i
    
if j is not in aSel then
      set the end of newSel to j
    end if
  end repeat
  
  
set selection to newSel
end tell

★Click Here to Open This Script 

2017/03/11 256×3のグラフ画像を縦方向に拡大する v2

GPUImage.frameworkの明度ヒストグラムの出力画像を加工するために作成したAppleScriptの改良版です。

256×3ドットの画像から、

6ed48d0a-5718-4562-9ad3-b7a63269678f.png

明度ヒストグラムのデータ部分である中央の256×1ドットのパターンを切り抜いて取得。そのパターンで256×90の空白の画像を塗りつぶして保存します。

53da8086-f585-4d45-9d4b-e5b9ceee7f03.png

最初のバージョンでは、バカていねいに元の画像の色情報を読み取って、その通りに新規画像に点で描画していました。そのため、処理に数秒(4秒ぐらい?)かかっていました。

本バージョンは、MacBook Pro Retina 2012(Core i7 2.66GHz)で0.008秒ぐらいでファイル書き込みも含めて終了します。

AppleScript名:256×3のグラフ画像を縦方向に拡大する v2
– Created 2017-03-11 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/4522

set aHeight to 90
set aWidth to 256

set aPath to POSIX path of (choose file of type {“public.image”})
set anImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aPath

–256×1で切り抜き
set bImage to my cropNSImageBy:{0, 1, 256, 1} fromImage:anImage
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:(anImage’s TIFFRepresentation())

–256×90の画像を作成
set cImage to current application’s NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))

–256×1のパターンでぬりつぶし
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
cImage’s lockFocus()
(
current application’s NSColor’s colorWithPatternImage:bImage)’s |set|()
current application’s NSBezierPath’s fillRect:theRect
cImage’s unlockFocus()

–PNG形式で保存
set aPath to (POSIX path of (path to desktop) & (current application’s NSUUID’s UUID())’s UUIDString() as string) & “.png”
saveNSImageAtPathAsPNG(cImage, aPath)

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

–NSImageを指定の大きさでトリミング
on cropNSImageBy:{x1, y1, newWidth, newHeight} fromImage:theImage
  set theSize to (theImage’s |size|()) as record
  
set oldHeight to height of theSize
  
  
– transpose y value for Cocoa coordintates
  
set y1 to oldHeight - newHeight - y1
  
set newRect to {{x:x1, y:y1}, {width:newWidth, height:newHeight}}
  
theImage’s lockFocus()
  
set theRep to current application’s NSBitmapImageRep’s alloc()’s initWithFocusedViewRect:newRect
  
theImage’s unlockFocus()
  
  
set outImage to current application’s NSImage’s alloc()’s initWithSize:(theRep’s |size|())
  
outImage’s addRepresentation:theRep
  
  
return outImage
end cropNSImageBy:fromImage:

★Click Here to Open This Script 

2017/03/11 macOS 10.12のsayコマンドにバグ

Appleのディスカッションフォーラムで報告された内容によると、macOS 10.12上のsayコマンドで「特定の文字の組み合わせで文字を無視する」とのこと。

これは、気づいたユーザーをほめるべきなのか、こんな状態でOSをリリースするAppleを非難すべきなのか、その両方なのか。macOS 10.12ではAppleScript処理系のバージョンは(macOS 10.11から引き続き)2.5のまま変更はないので、OS側のテキスト解析系のサービスのバグなんでしょう。

日本語の文字列の範囲でも他に何かありそうな雰囲気がしますし、他の言語でも何か問題がありそうです。

AppleScript名:音声読み上げバグ(10.12)
say げる” using “Otoya” –> “げる”–* Bug *
say “もげる” using “Otoya” –> “もげ”–* Bug *
say “もゲル” using “Otoya” –> “もげる”
say “モゲル” using “Otoya” –> “もげる”

★Click Here to Open This Script 

AppleScript名:音声読み上げバグ確認(10.12)
set aStr to “あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやいゆえよわをんがぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽ”
set aList to characters of aStr

repeat with i in aList
  set sayText to i & “げる”
  
say sayText using “Otoya”
end repeat

★Click Here to Open This Script 

2017/03/09 ASCIImageでPNG画像をデスクトップに作成する

オープンソースのプログラム「ASCIImage」(By Charles Parnot)を用いて、ASCII ARTからPNG画像を作成するAppleScriptです。AppleScriptからの呼び出しは、同プログラムをフレームワーク化した「asciiImageKit」を経由しています。

本AppleScriptのテストのためには、asciiImageKit.frameworkを~/Library/Frameworksフォルダに入れておく必要があります。バイナリを用意しておきましたので、自己責任でおためしください。

Download Binary (30KB)

ASCIImageは(どうして作者がこれを作ったのかが)とても不思議なプログラムで、画像描画を文字で(ASCII ARTっぽく)指定するとNSImageが得られます。NSImageが得られれば、あとはPNGなりJPEGなり好みの画像フォーマットで書き出しできます。

ascii1.png
▲shouldAntialias=falseでレンダリングした画像

ascii2.png
▲shouldAntialias=trueでレンダリングした画像

inv.png
▲自分でデータ作成をこころみてみたものの、思い通りに描画されなかったデータ。コツが必要なのか意外と難しい、、、、

AppleScript名:ASCIImageでPNG画像をデスクトップに作成する
– Created 2017-03-09 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “asciiImageKit” –https://github.com/cparnot/ASCIImage
use framework “AppKit”
–http://piyocast.com/as/archives/4517

set aColor to current application’s NSColor’s blackColor()

set aRep to {· · · 1 2 · · · · ·, ¬
  · · · A # # · · · ·, ¬
  
· · · · # # # · · ·, ¬
  
· · · · · # # # · ·, ¬
  
· · · · · · 9 # 3 ·, ¬
  
· · · · · · 8 # 4 ·, ¬
  
· · · · · # # # · ·, ¬
  
· · · · # # # · · ·, ¬
  
· · · 7 # # · · · ·, ¬
  
· · · 6 5 · · · · ·}

set anImage to current application’s NSImage’s imageWithASCIIRepresentation:aRep |color|:aColor shouldAntialias:false

set aPath to (POSIX path of (path to desktop) & (current application’s NSUUID’s UUID())’s UUIDString() as string) & “.png”
set fRes to saveNSImageAtPathAsPNG(anImage, aPath) of me

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

★Click Here to Open This Script 

2017/03/07 矩形座標同士の合計

NSUnionRectによる矩形座標(NSRect)の合計をためしてみました。

unionrect.png

実際に方眼紙を塗りつぶしてみると、計算結果が不思議な感じもするのですが(空いているセルもあるので)、、、そういうものなんでしょう、、、か(^ー^;;;;;

AppleScript名:矩形座標同士の合計
– Created 2017-03-06 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4515

set a1Rect to {origin:{x:10, y:10}, |size|:{width:40, height:40}}
set b1Rect to {origin:{x:30, y:30}, |size|:{width:40, height:40}}
set a1Res to current application’s NSUnionRect(a1Rect, b1Rect)
–>  {origin:{x:10.0, y:10.0}, size:{width:60.0, height:60.0}}

★Click Here to Open This Script 

2017/03/06 矩形座標同士の衝突判定 v3

なんとなくあるとは予想していた矩形座標(NSRect)同士の衝突検出。Cocoa勉強会池袋で聞いてみたら、やっぱりありました(汗)

面倒な処理も必要なく、NSIntersectionRect(aRect, bRect) で重なり合う(and)箇所を検出できてしまいました。1対の矩形座標の衝突検出で所要時間0.001秒以下。たいへん簡単かつお手軽に検出できました。

NSIntersectionRectとNSUnionRectのことは、しばらく忘れられないことでしょう。

AppleScript名:矩形座標同士の衝突判定 v3
– Created 2017-03-06 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4514

set a1Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set b1Rect to {origin:{x:30, y:30}, |size|:{width:100, height:100}}
set a1Res to detectRectanglesCollision(a1Rect, b1Rect) of me
–>  true

set a4Rect to {origin:{x:0, y:20}, |size|:{width:100, height:10}}
set b4Rect to {origin:{x:1000, y:10000}, |size|:{width:50, height:100}}
set a2Res to detectRectanglesCollision(a4Rect, b4Rect) of me
–>  false

set a3Rect to {origin:{x:30, y:30}, |size|:{width:50, height:50}}
set b3Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set a3Res to detectRectanglesCollision(a3Rect, b3Rect) of me
–> true

set a4Rect to {origin:{x:0, y:20}, |size|:{width:100, height:10}}
set b4Rect to {origin:{x:10, y:10}, |size|:{width:50, height:100}}
set a4Res to detectRectanglesCollision(a4Rect, b4Rect) of me
–> true

–NSRect同士の衝突判定
on detectRectanglesCollision(aRect, bRect)
  set a1Res to current application’s NSIntersectionRect(aRect, bRect)
  
return not (a1Res = {origin:{x:0.0, y:0.0}, |size|:{width:0.0, height:0.0}})
end detectRectanglesCollision

★Click Here to Open This Script 

2017/03/05 矩形座標同士の衝突判定 v2

2つのNSRect同士の衝突判定を行うAppleScriptです。v1ではNSRectの内含の順序が異なると衝突を検出できないので修正しました。

→ 矩形座標同士の衝突判定 v3

rect2_resized.png

Rect AがRect Bを含むかどうかチェックを行うというのがV1の処理内容で、これはRect AがRect Bよりも大きいことを前提としたもの。Rect Bのほうが大きい場合には成立しません。

そこで、Rect A>Rect Bを前提とした処理を行なったあとで、衝突していない(false)と判定した場合には、Rect AとRect Bを入れ替えて再度処理してみました。最悪の場合、かなりの回数のループを行なってしまうわけですが、他にいろいろ解決策はありそうです。

救いがあるのは、数百回程度のループ処理ならさほど時間がかからないというところでしょうか。1対の矩形の衝突判定で0.01秒程度。座標のステップ値を10に設定したときには0.002秒程度でした。

AppleScript名:矩形座標同士の衝突判定 v2
– Created 2017-03-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4510

set a1Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set b1Rect to {origin:{x:30, y:30}, |size|:{width:100, height:100}}
set a1Res to detectCollision(a1Rect, b1Rect, 1) of me
–> true

set a2Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set b2Rect to {origin:{x:200, y:30}, |size|:{width:100, height:100}}
set a2Res to detectCollision(a2Rect, b2Rect, 1) of me
–> false

set a3Rect to {origin:{x:30, y:30}, |size|:{width:50, height:50}}
set b3Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set a3Res to detectCollision(a3Rect, b3Rect, 1) of me
–> true

set a4Rect to {origin:{x:0, y:20}, |size|:{width:100, height:10}}
set b4Rect to {origin:{x:10, y:10}, |size|:{width:50, height:100}}
set a4Res to detectCollision(a4Rect, b4Rect, 1) of me
–> true

–NSRect同士の衝突判定
on detectCollision(aRect, bRect, stepNum)
  set a1Res to detectCollisionSub(aRect, bRect, stepNum) of me
  
if a1Res = true then
    return true
  else
    set a2Res to detectCollisionSub(bRect, aRect, stepNum) of me
    
return a2Res
  end if
end detectCollision

on detectCollisionSub(aRect, bRect, stepNum)
  
  
set origX1 to aRect’s origin’s x
  
set origY1 to aRect’s origin’s y
  
set origX2 to origX1 + (aRect’s |size|’s width)
  
set origY2 to origY1 + (aRect’s |size|’s height)
  
  
repeat with i from origX1 to origX2 by stepNum
    set aPoint to {x:i, y:origY1}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origY1 to origY2 by stepNum
    set aPoint to {x:origX2, y:i}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origX1 to origX2 by stepNum
    set aPoint to {x:i, y:origY2}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origY1 to origY2 by stepNum
    set aPoint to {x:origX1, y:i}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
return false
end detectCollisionSub

★Click Here to Open This Script 

2017/03/05 矩形座標同士の衝突判定

2つのNSRect同士の衝突判定を行うAppleScriptです。

→ 矩形座標同士の衝突判定 v3

NSRect(矩形)とNSPoint(点)の間で矩形に座標が含まれるかどうか確認を行うのには、NSPointInRectを利用することになりますが、Referenceを見てもNSRect(矩形)同士が重なっているかどうかを確認するメソッドが存在しないようです。

矩形同士の衝突判定を行う仕組みといえばSpriteが存在しているため、SpriteKitの機能を使えば簡単にできそうですが、そこまで手をかけなくても、ただ単にNSRect(矩形)の外周部を1刻みでNSPoint(点)に分解し、すべてのNSPoint(点)が相手側のNSPoint(矩形)に含まれるかをループでチェックすればわかります(知性のカケラもない処理です)。

rect1_resized.png

大きな矩形同士であれば、ステップ数を大きくするなどのチューニングも必要かもしれませんが、ほかにもっといい手段がありそうな気もします。

AppleScript名:矩形座標同士の衝突判定
– Created 2017-03-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4508

set a1Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set b1Rect to {origin:{x:30, y:30}, |size|:{width:100, height:100}}
set a1Res to detectCollisionDetect(a1Rect, b1Rect, 1) of me
–> true

set a2Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set b2Rect to {origin:{x:200, y:30}, |size|:{width:100, height:100}}
set a2Res to detectCollisionDetect(a2Rect, b2Rect, 1) of me
–> false

–NSRect同士の衝突判定
on detectCollisionDetect(aRect, bRect, stepNum)
  
  
set origX1 to aRect’s origin’s x
  
set origY1 to aRect’s origin’s y
  
set origX2 to origX1 + (aRect’s |size|’s width)
  
set origY2 to origY1 + (aRect’s |size|’s height)
  
  
repeat with i from origX1 to origX2 by stepNum
    set aPoint to {x:i, y:origY1}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origY1 to origY2 by stepNum
    set aPoint to {x:origX2, y:i}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origX1 to origX2 by stepNum
    set aPoint to {x:i, y:origY2}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origY1 to origY2 by stepNum
    set aPoint to {x:origX1, y:i}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
return false
end detectCollisionDetect

★Click Here to Open This Script 

2017/03/04 256×3のグラフ画像を縦方向に拡大する

先日掲載した「GPUImage.frameworkを利用して指定画像が真っ白かを判定する」AppleScriptで、GPUImage.frameworkの明度ヒストグラムの出力画像を加工するために作成したAppleScriptです。

→ 改良版を掲載しています「256×3のグラフ画像を縦方向に拡大する v2」

256×3ドットという、

2906be82-598a-4dbf-86ec-efe081461ade.png

掲載に難のあるグラフィック。これをそのまま掲載するだけでもよかったのですが、HTMLタグで無理やりサイズを変更。

2906be82-598a-4dbf-86ec-efe081461ade.png

これでだいぶ見やすくはなったものの、Webブラウザ側で不要なスムージング処理をしてしまうようで、意図したようには表示されません。

1つだけPhotoshopで加工してみた(盛大にコピペ)のですが、あまりの作業の不毛さに、2つ以上作るのは勘弁してほしいという内容でした。

そこで作成したのが本Scriptです(ザ・作り捨てScript)。本当に256×90の黒い画像を作成し、指定のヒストグラム画像からデータ表示部分の内容を縦方向に拡大します。

実際にためして驚いたのが、指定サイズのNSImageを作成してそのままNSBitmapImageRepに変換すれば指定サイズのビットマップ画像が得られると思っていたのに、missing valueが返ってきたこと。仕方なく本当に(黒く)塗りつぶしています。

atest3.png

GPUImage.frameworkを使っているわけでもないし、普通に漫然とループ処理でドット単位の塗りつぶしを行なっているだけなので、処理には数秒待たされます。もう少しうまいやりかたもありそうですが、数秒程度なら許容範囲でしょう。掲載資料作成用の作り捨てScriptだし。

AppleScript名:256×3のグラフ画像を縦方向に拡大する
– Created 2017-03-03 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/4504

set aHeight to 90
set aWidth to 256

set aPath to POSIX path of (choose file of type {“public.image”})
set anImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aPath
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:(anImage’s TIFFRepresentation())

set bImage to current application’s NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))

–描画実行(黒くぬりつぶし)
set fillColor to current application’s NSColor’s blackColor()
bImage’s lockFocus()
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
set theNSBezierPath to current application’s NSBezierPath’s bezierPath
theNSBezierPath’s appendBezierPathWithRect:theRect
fillColor’s |set|()
theNSBezierPath’s fill()
bImage’s unlockFocus() –描画ここまで

set bRawImg to current application’s NSBitmapImageRep’s imageRepWithData:(bImage’s TIFFRepresentation())

–元画像から色情報読み取り
set origData to {}
repeat with i from 0 to 255
  set origColor to (aRawimg’s colorAtX:i y:1)
  
set the end of origData to origColor
end repeat

–新規作成画像をぬりつぶし
repeat with yNum from 1 to 88
  repeat with xNum from 0 to 255
    set anItem to item (xNum + 1) of origData
    (
bRawImg’s setColor:anItem atX:xNum y:yNum)
  end repeat
end repeat

set newImg to current application’s NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
newImg’s addRepresentation:bRawImg

set newFilePath to POSIX path of (choose file name)
saveNSImageAtPathAsPNG(newImg, newFilePath)

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

★Click Here to Open This Script 

2017/03/03 ステータスバーのじっけん2

macOSのメニューバー上にステータスバー・アイテムを作成するAppleScriptです。

AppleScriptからステータスバーを作成し、メニューを作成・登録できることを確認しましたが、アプレットで実行するのは面倒なのでScript Editor上でそのまま実行できるようにしてみました。

stat10.png

実行・呼び出しに問題があるのではなく、どちらかといえばステータスバー自体を消去する手段を通常のAppleScriptでは用意できなかったことに問題がありました。

そこで、自分で作ったステータスバーのメニューに「Quit」項目を用意し、ステータスバーアイテムの抹消を行えるようにしてみました。

メニュー自体にはCommand Keyなどの指定も行えるのですが、ステータスバー・アイテムだとキーボード・ショートカットを取得できないようで(他のツール類もそんな感じ)、そういうもののようです。

AppleScript名:ステータスバーのじっけん2
– Created 2017-03-03 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/4502

property aStatusItem : missing value

on run
  init() of me
end run

on init()
  set aList to {“Piyomaru”, “Software”, “”, “Takaaki”, “Naganoya”, “”, “Quit”}
  
  
set aStatusItem to current application’s NSStatusBar’s systemStatusBar()’s statusItemWithLength:(current application’s NSVariableStatusItemLength)
  
  
aStatusItem’s setTitle:🚗
  
aStatusItem’s setHighlightMode:true
  
aStatusItem’s setMenu:(createMenu(aList) of me)
end init

on createMenu(aList)
  set aMenu to current application’s NSMenu’s alloc()’s init()
  
set aCount to 1
  
  
repeat with i in aList
    set j to contents of i
    
if j is not equal to “” then
      set aMenuItem to (current application’s NSMenuItem’s alloc()’s initWithTitle:j action:“actionHandler:” keyEquivalent:“”)
    else
      set aMenuItem to (current application’s NSMenuItem’s separatorItem())
    end if
    (
aMenuItem’s setTarget:me)
    (
aMenuItem’s setTag:aCount)
    (
aMenu’s addItem:aMenuItem)
    
    
if j is not equal to “” then
      set aCount to aCount + 1
    end if
  end repeat
  
  
return aMenu
end createMenu

on actionHandler:sender
  set aTag to tag of sender as integer
  
set aTitle to title of sender as string
  
  
if aTitle is not equal to “Quit” then
    display dialog aTag as string
  else
    current application’s NSStatusBar’s systemStatusBar()’s removeStatusItem:aStatusItem
  end if
end actionHandler:

★Click Here to Open This Script