Menu

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

AppleScriptの穴

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

カテゴリー: Color

指定画像をPNG形式(グレースケール)で保存

Posted on 7月 9, 2019 by Takaaki Naganoya

指定の画像ファイルをグレースケールのPNG画像ファイルに変換するAppleScriptです。

Appleが配布しているMNISTの手書き数字画像の認識CoreMLモデルをCocoa Framework化してみたところ、グレースケールの画像を要求されたため、画像をグレースケール化するルーチンを作ってみました。

結局、MNISTの手書き画像認識はうまく行かなかったのですが(全部「0」が返ってくる、、、)、グレースケール変換ルーチンは実用的だったので載せておくことにしました。

AppleScript名:指定画像をPNG形式(グレースケール)で保存
— Created 2019-07-09 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

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

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

set fRes to retUUIDfilePath(aFile, "png") of me
set sRes to saveNSImageAtPathAsGreyPNG(aImage, fRes) of me

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

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsGreyPNG(anImage, outPath)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep
  
  
–ビットマップをグレースケール変換
  
set bRawimg to convBitMapToDeviceGrey(aRawimg) of me
  
  
set pathString to NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
  
set myNewImageData to (bRawimg’s representationUsingType:(NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –true/false
end saveNSImageAtPathAsGreyPNG

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

★Click Here to Open This Script 

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

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

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

set nsImageRes to convNSImageAsGrey(aImage) of me

–NSImageをグレースケールに変換する(NSImageで入出力)
on convNSImageAsGrey(anImage)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep
  
set aSpace to NSColorSpace’s deviceGrayColorSpace()
  
set bRawimg to aRawimg’s bitmapImageRepByConvertingToColorSpace:aSpace renderingIntent:(NSColorRenderingIntentDefault)
  
set outImage to NSImage’s alloc()’s initWithSize:(bRawimg’s |size|())
  
outImage’s addRepresentation:(bRawimg)
  
return outImage
end convNSImageAsGrey

★Click Here to Open This Script 

Posted in Color file File path Image | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSBitmapImageRep NSColorRenderingIntentPerceptual NSColorSpace NSImage NSPNGFileType NSString NSUUID | Leave a comment

アラートダイアログ上にTexViewを表示_ヘルプ付き_半透明

Posted on 7月 8, 2019 by Takaaki Naganoya

アラートダイアログ上にTextViewを表示して、指定のテキストを閲覧するAppleScriptです。

# 前バージョンの「自分のソースコード」表示というのは意味不明だったので、プロセス一覧を取得してみました

ヘルプボタン(?)を付け、アラートダイアログのウィンドウ背景を半透明に設定。そのままでは配色の都合上Dark Mode/Light Modeの切り替え時に読みづらい文字なども出てきたため、モード判定を行って表示色などを変更しています。

アプレット書き出ししたときに、スクロールビューがマウスのスクロールホイールの操作に追従したスクロールを行ってくれないので、そのあたり何か追加でNSScrollViewに設定を行う必要があるのだろうかと。


▲スクリプトエディタ上で実行@macOS 10.14.5。左がLight Mode、右がDark Mode(以下同様)


▲ヘルプボタンをクリックしたところ。本当にアンカーを指定して指定のヘルプコンテンツを表示させることもできる模様。そのための基礎的な試験


▲AppleScriptアプレット書き出しして実行したところ


▲Script Debugger上で実行@macOS 10.14.5。Dark Modeに対応できていない(次バージョンで対応することでしょう)


▲Script DebuggerからAppleScript Applet (Enhanced)で書き出して実行したところ。マウスのスクロールホイールの操作を受け付けて文字がスクロールする

AppleScript名:アラートダイアログ上にTexViewを表示_ヘルプ付き_半透明
— Created 2019-07-08 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSFont : a reference to current application’s NSFont
property NSView : a reference to current application’s NSView
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSTextView : a reference to current application’s NSTextView
property NSScrollView : a reference to current application’s NSScrollView
property NSRunningApplication : a reference to current application’s NSRunningApplication

property returnCode : 0

–Get Self Source Code (a kind of joke)
set asStr to do shell script "ps -ax"
set paramObj to {myMessage:"Main Message", mySubMessage:"Sub information", mes1:(asStr), mesWidth:400, mesHeight:200, fontName:"HiraginoSans-W3", fontSize:11.0}

–my dispTextViewWithAlertdialog:paramObj–for debug
my performSelectorOnMainThread:"dispTextViewWithAlertdialog:" withObject:paramObj waitUntilDone:true

on dispTextViewWithAlertdialog:paramObj
  –Receive Parameters
  
set aMainMes to (myMessage of paramObj) as string –Main Message
  
set aSubMes to (mySubMessage of paramObj) as string –Sub Message
  
set mesStr to (mes1 of paramObj) as string –Text Input field 1 Label
  
set aWidth to (mesWidth of paramObj) as integer –TextView width
  
set aHeight to (mesHeight of paramObj) as integer –TextView height
  
set aFontName to (fontName of paramObj) as string –TextView font name
  
set aFontSize to (fontSize of paramObj) as real –TextView font size
  
  
–Detect Dark Mode
  
set dMode to retLIghtOrDark() of me
  
if dMode = true then
    set tvCol to 1
    
set tvAlpha to 0.8
    
set bCol to 0.1
    
set bAlpha to 0.8
  else
    set tvCol to 1
    
set tvAlpha to 1.0
    
set bCol to 1
    
set bAlpha to 0.7
  end if
  
  
— Create a TextView with Scroll View
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
set aView to NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
aView’s setRichText:true
  
aView’s useAllLigatures:true
  
aView’s setTextColor:(NSColor’s cyanColor()) –cyanColor
  
aView’s setFont:(NSFont’s fontWithName:aFontName |size|:aFontSize)
  
set aColor to NSColor’s colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:(tvAlpha)
  
aView’s setBackgroundColor:aColor
  
aView’s setOpaque:(false)
  
aView’s setString:mesStr
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
— set up alert
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    –for Messages
    
its setMessageText:(aMainMes)
    
its setInformativeText:(aSubMes)
    
    
–for Buttons
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
    
–Add Accessory View
    
its setAccessoryView:(aScroll)
    
    
–for Help Button
    
its setShowsHelp:(true)
    
its setDelegate:(me)
    
    
set myWindow to its |window|
  end tell
  
  
myWindow’s setOpaque:(false)
  
myWindow’s setBackgroundColor:(NSColor’s colorWithCalibratedWhite:(bCol) alpha:(bAlpha))
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
end dispTextViewWithAlertdialog:

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

on alertShowHelp:aNotification
  display dialog "Help Me!" buttons {"OK"} default button 1 with icon 1
  
return false –trueを返すと親ウィンドウ(アラートダイアログ)がクローズする
end alertShowHelp:

–ダークモードの判定。ダークモード時:true、ライトモード時:falseが返る
on retLIghtOrDark()
  set curMode to (current application’s NSUserDefaults’s standardUserDefaults()’s stringForKey:"AppleInterfaceStyle") as string
  
return (curMode = "Dark") as boolean
end retLIghtOrDark

★Click Here to Open This Script 

Posted in Color dialog GUI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSAlert NSColor NSFont NSRunningApplication NSScrollView NSTextView NSURL NSView | Leave a comment

アラートダイアログ上にTextViewを表示

Posted on 7月 8, 2019 by Takaaki Naganoya

アラートダイアログ上にTextViewを表示して、指定のテキストを閲覧するAppleScriptです。

とくにこれといって何か表示するものを思いつかなかったので、自分自身のソースコードを取得して表示しています。スクリプトエディタやScript Debugger上で実行した場合には自分自身のソースコードをテキストビュー上で表示します。

読み取り専用のスクリプトやアプレットで実行している場合にはソースコードを取得できません。何か適宜自分で表示させたいテキストを与えてみてください。

AppleScript名:アラートダイアログ上にTexViewを表示
— Created 2019-07-02 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "OSAKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSFont : a reference to current application’s NSFont
property NSView : a reference to current application’s NSView
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSTextView : a reference to current application’s NSTextView
property NSScrollView : a reference to current application’s NSScrollView
property NSRunningApplication : a reference to current application’s NSRunningApplication
property OSAScript : a reference to current application’s OSAScript

property returnCode : 0

–Get Self Source Code (a kind of joke)
set mePath to path to me
set asStr to getASsourceFor(mePath) of me

set paramObj to {myMessage:"Main Message", mySubMessage:"Sub information", mes1:(asStr), mesWidth:400, mesHeight:200, fontName:"HiraginoSans-W3", fontSize:11.0}

–my dispTextViewWithAlertdialog:paramObj–for debug
my performSelectorOnMainThread:"dispTextViewWithAlertdialog:" withObject:paramObj waitUntilDone:true

on dispTextViewWithAlertdialog:paramObj
  –Receive Parameters
  
set aMainMes to (myMessage of paramObj) as string –Main Message
  
set aSubMes to (mySubMessage of paramObj) as string –Sub Message
  
set mesStr to (mes1 of paramObj) as string –Text Input field 1 Label
  
set aWidth to (mesWidth of paramObj) as integer –TextView width
  
set aHeight to (mesHeight of paramObj) as integer –TextView height
  
set aFontName to (fontName of paramObj) as string –TextView font name
  
set aFontSize to (fontSize of paramObj) as real –TextView font size
  
  
— Create a TextView with Scroll View
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
set aView to NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
aView’s setRichText:true
  
aView’s useAllLigatures:true
  
aView’s setTextColor:(current application’s NSColor’s cyanColor()) –cyanColor
  
aView’s setFont:(current application’s NSFont’s fontWithName:aFontName |size|:aFontSize)
  
set aColor to current application’s NSColor’s colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.5
  
aView’s setBackgroundColor:aColor
  
aView’s setString:mesStr
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
— set up alert
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aScroll
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
end dispTextViewWithAlertdialog:

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

–指定AppleScriptファイルのソースコードを取得する(実行専用Scriptからは取得できない)
— Original Created 2014-02-23 Shane Stanley
on getASsourceFor(anAlias as {alias, string})
  set aURL to |NSURL|’s fileURLWithPath:(POSIX path of anAlias)
  
set theScript to OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
  
if theScript is equal to missing value then
    error "Compile Error" — handle error
  else
    set sourceText to theScript’s source()
  end if
  
  
return sourceText as string
end getASsourceFor

★Click Here to Open This Script 

Posted in Color file File path Font GUI Text URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSAlert NSColor NSFont NSRunningApplication NSScrollView NSTextView NSURL OSAScript | Leave a comment

Cocoa ObjectをキーにしたDictionaryから合致するObjectを取得

Posted on 7月 7, 2019 by Takaaki Naganoya

Cocoa ObjectをキーにしたDictionaryから、Cocoa Objectでキー検索を行い、キーが合致する要素に定義されているオブジェクトを取得するAppleScriptです。

AppleScriptのrecord型変数は、本当に基本的な機能しか用意されておらず、

{keyLabel1:value1, keyLabel2:value2, keyLabel3:value3 } 

のような、キーとなるラベルには「空白文字や使用禁止文字を含まない」文字しか使えませんし、キーに何らかのオブジェクトを指定することはできません。

そんな中、macOS 10.10でCocoa Scriptingが標準搭載されたため、CocoaのNSDictionaryを調べて「へー、キーにオブジェクトが使えるのか!」などと喜んでいました(macOS 10.10が出た頃)。

{Cocoa Object 1:value1, Cocoa Object 2:value2, Cocoa Object 3:value3 } 
{Cocoa Object 1:some object 1, Cocoa Object 2:some object 2, Cocoa Object 3:some object 3 } 

ちょうどそういう(CocoaオブジェクトをキーにしたDictionaryの検索)プログラムを組もうとして、Dictionaryから「valueForKey:」でvalueを取り出そうとして(エラーに遭遇して)試行錯誤していました。

(NSDictionary) {
	NSCalibratedRGBColorSpace 0 1 0 1:"Green",
	NSCalibratedRGBColorSpace 0 0 1 1:"Blue",
	NSCalibratedRGBColorSpace 1 0 0 1:"Red"
}

実際にはこれは「objectForKey:」で取り出さないとエラーになってしまうんですね。その確認のために書いた基礎確認用のAppleScriptです。やっぱり、基礎の再確認はとても大事です。

AppleScript名:Cocoa ObjectをキーにしたDictionaryから合致するObjectを取得
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/06
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

set aCol to current application’s NSColor’s redColor()
set bCol to current application’s NSColor’s greenColor()
set cCol to current application’s NSColor’s blueColor()

set aDict to current application’s NSMutableDictionary’s new()
aDict’s addObject:"Red" forKey:aCol
aDict’s addObject:"Green" forKey:bCol
aDict’s addObject:"Blue" forKey:cCol

set dCol to current application’s NSColor’s blueColor()

set aRes to (aDict’s objectForKey:dCol) as string
–> "Blue"

★Click Here to Open This Script 

Posted in Color Record | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSColor NSMutableDictionary | Leave a comment

構文色分け情報を取得(Color Spaceを考慮)

Posted on 7月 4, 2019 by Takaaki Naganoya

macOS標準搭載のスクリプトエディタで定義している、AppleScriptの構文要素ごとの色分け情報。これを設定ファイルから取り出してレコード型データ(を入れた配列)に変換するAppleScriptの、カラースペースを考慮したデータの取り出しを行う改修版です。

AppleScriptの構文色分け情報は、ユーザーごとに異なります。一応、OSデフォルトの趣味の悪い配色なんかもありますが、

 (1)美的センスがなく見た目に気持ち悪い(ほら変更したいでしょ? 自分の好きなように変えてね、というメッセージだと受け止めました)

 (2)重複した色が設定されている構文要素がたくさんある(構文要素ごとの見分けがしにくいので、デフォルトのままだと無意味。ほら変更したくなったでしょ、というメッセージだと受け止めました)

ということから、AppleScript入門初日に設定色を変更。何度か細かい変更を行いつつも、今日までだいたい同じ感じの設定を使い続けています。

他のScripterがどのような配色にしているかはあまり知りません。Scripterごとに違うんだろうな、ぐらいの感じです。

ところが、蓋を開けてみたらこの構文色分け設定に「RGB以外の色」が設定できることが判明。けっこう長い間、この処理系使い続けてきましたけれど、昨日はじめて知りました。

具体的に言えば、RGB以外の「CMYK色」と「グレースケール色」の2つを設定可能なことが判明。CMYK色は、何度かアクセスしているうちに勝手にRGB色に置き換わってしまうようですが、グレースケールで指定した色はそのまま色種別がグレースケールのまま保持される(RGBに変換されたりしない)ようです。そのため、NSColorからredValue()などのメソッドで数値を取り出そうとするとエラーになる事例が発生したのでした。

そこで、RGBの各チャンネルの値を取り出す前にNSColorの色空間(グレースケール色空間というのはないので、種別ぐらい?)をチェックし、RGB以外であれば変換処理を行うようにしてみました。

ただし、この色空間(色モデル)の確認にNSColorのcolorSpaceNameというメソッドを使っている点に注意が必要です。これはmacOS 10.13で非推奨(deprecated)になっています。ヘッダーファイル上の説明を読むかぎりだと、Color Space(色空間)といいながら実際には色空間に該当する(HSBとかL*a*b*とか)ものを指定しているわけではないので、色タイプと言い換えることにした、という説明が行われていました。

このため、macOS 10.15betaでは未確認ではあるものの、このNSColorからRGB値を取り出すという処理自体を書き換える必要が出てくるため、本ルーチンだけ別のライブラリに分離しておくとか、メンテナンス時にわかるように書いておくとよいでしょう(NSColorのtypeを取得してみたものの、いまひとつサンプルなどもなく不明。macOS 10.14上で全部一律で0が返ってくるし)。

AppleにOS内部の機能修正リクエストを出す場合、「実際に機能不全を起こしているんだから直してほしい」と依頼してもなかなか直らない一方で、「学術的に正しくない」という指摘をされるととっとと変更するんだなーという発見をしたような気がします。

AppleScript名:構文色分け情報を取得(Color Spaceを考慮).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/04
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

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 NSUnarchiver : a reference to current application’s NSUnarchiver

set cList to getAppleScriptSourceColors() of me

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

–NSColorからRGBの値を取り出す
on retColListFromNSColor(aCol, aMAX as integer)
  set aSpace to (aCol’s colorSpaceName()) as string
  
  
if aSpace is in {"NSDeviceRGBColorSpace", "NSCalibratedRGBColorSpace"} then
    –do nothing
  else
    –RGB以外の色空間の色は、RGBに変換
    
–CMYKとグレースケールは同一メソッドでRGBに変換できることを確認済み
    
set cCol to aCol’s colorUsingColorSpaceName:"NSCalibratedRGBColorSpace"
    
if cCol = missing value then error "Color Space Conversion Error (" & aSpace & " to NSCalibratedRGBColorSpace)"
    
copy cCol to aCol
  end if
  
  
set aRed to round ((aCol’s redComponent()) * aMAX) rounding as taught in school
  
set aGreen to round ((aCol’s greenComponent()) * aMAX) rounding as taught in school
  
set aBlue to round ((aCol’s blueComponent()) * aMAX) rounding as taught in school
  
  
if aRed > aMAX then set aRed to aMAX
  
if aGreen > aMAX then set aGreen to aMAX
  
if aBlue > aMAX then set aBlue to aMAX
  
  
return {aRed, aGreen, aBlue}
end retColListFromNSColor

★Click Here to Open This Script 

Posted in Color list Record System | Tagged 10.12savvy 10.13savvy 10.14savvy NSArray NSColor NSDictionary NSString NSUnarchiver | Leave a comment

Handle diff v2

Posted on 7月 3, 2019 by Takaaki Naganoya

Script Debugger上でオープン中の2つのAppleScript書類のうち、名称が同じハンドラ(サブルーチン)の内容同士を比較して、お互いに合っているかどうかをチェックするAppleScriptです。

アプリケーション書き出しして、Script Debuggerのスクリプトメニューに入れて実行します(AppleScript書類のままだと、Myriad Tables Lib内のフレームワークが呼べないため)。


▲本Scriptはスクリプトエディタの環境設定で行うAppleScriptの構文色分け設定色が「RGBカラー」でないとエラーになります。CMYKとかグレースケールカラーで指定して、そのままRGBに変換されずに保持される(CMYK色はアクセスしているうちにRGBに変換されるが、グレースケールは保持される)ため、色空間の判定を行ってRGB色に変換してから処理する必要があります(自分用メモ)

スクリプトエディタ上で設定する構文色分け設定をもとに、AppleScriptの構文要素を考慮したハンドラ一覧を作成し、2つのAppleScript書類の間に共通して存在するハンドラ名のハンドラ(サブルーチン)のAppleScriptソースを取得。インデント(tab)を削除したのちに比較を実行。

共通名称のハンドラすべてをチェックして、結果を表インタフェースで表示します。初版(v1)では実行するたびに1つのハンドラをチェックしていたのですが、あまりにかったるいので即座にループですべて調べてまとめて結果を表示するようにしました(v2)。

–> download executable archive (mainly for macOS 10.14 or later)

ただし、1つのAppleScript書類内にScript Object(JavaScriptでいうところのClosureみたいなもの)で論理分割された同名のハンドラが複数回登場するパターンは想定していません。複数検出するとエラーになります。

とくにScript Debuggerを対象にせずスクリプトエディタを対象にしてもよいのですが、些細な変更で実現できるため、興味のある方はやってみてください。あと、本Scriptは必要に迫られまくって作ったものなので、動作でおかしい箇所があったらぜひぜひご指摘を。

個人的には、ハンドラ名称を構文要素を考慮しつつ取得している一方で、ハンドラの内容は単なる文字列検索で取り出しているというあたりにアンバランスさを感じます。ただ、趣味のScriptではないので若干の手抜きを(^ー^;;

macOS 10.14.5上のスクリプトエディタで、構文色分け情報を何回設定しても「黒」になるという現象に遭遇したのですが、他のユーザー環境上での再現性については未知数であるため、まだレポートできない状況です。

→ その後、本ツールは強化されて、構文色分け設定にRGB以外の色が設定してあってもRGBに変換して処理する機能や、構文色分け設定を参照したコメント除去機能や、各種書式情報の取得を3倍高速化するカラーキャッシュなどの機能を実装したプログラムに(必要に迫られて)成長しました。

AppleScript名:Handle diff v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/02
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5" — Sierra (10.12) or later (maybe 10.11 is OK but not confirmed)
use framework "Foundation"
use scripting additions
use framework "OSAKit"
use script "Myriad Tables Lib" version "1.0.9" –https://www.macosxautomation.com/applescript/apps/Script_Libs.html

property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property OSAScript : a reference to current application’s OSAScript
property NSPredicate : a reference to current application’s NSPredicate
property NSDictionary : a reference to current application’s NSDictionary
property NSUnarchiver : a reference to current application’s NSUnarchiver
property NSCountedSet : a reference to current application’s NSCountedSet

–構文色分け設定に重複色がないかチェック
set cList to getAppleScriptSourceColors() of me
set cRes to chkASLexicalFormatColorConfliction(cList) of me –構文色分けの重複色チェック
if cRes = false then error "There is some duplicate(s) color among AppleScript’s lexical color settings"

–Script Debugger上でオープン中の2つのAppleScript書類のパスを取得
set dList to retTwoPathList() of me
if dList = false then return

copy dList to {d1Path, d2Path}

–各AppleScript書類のハンドラ名称一覧を取得する
set hList1 to retHandlerNamesFromAppleScriptSource(d1Path as alias) of me
set hList2 to retHandlerNamesFromAppleScriptSource(d2Path as alias) of me

–2つのAppleScript書類のハンドラの共通項目(名称のみ)を抽出する
set resList to returnDuplicatesOnly(hList1 & hList2) of me
if resList = {} then
  –共通のハンドラ(サブルーチン)が指定の2つのScriptに存在していなかった
  
display dialog "There is no common handler between the scripts." buttons {"OK"} default button 1
  
return
end if

–各AppleScript書類のソースを取得して、指定のハンドラのテキストを取得する
set s1Source to getASsourceFor(d1Path as alias) of me
set s2Source to getASsourceFor(d2Path as alias) of me

if (s1Source = false) or (s2Source = false) then
  display dialog "Error occured in getteing AS source" buttons {"OK"} default button 1
  
return
end if

set outList to {}
repeat with i in resList
  set resHandler to contents of i
  
set s1Source to extractHandlerSourceOnly(s1Source, resHandler) of me
  
set s2Source to extractHandlerSourceOnly(s2Source, resHandler) of me
  
set compareF to (s1Source is equal to s2Source) as boolean
  
set the end of outList to {resHandler, compareF}
end repeat

–結果表示
tell me to activate
display table with data outList with prompt "Handler contents compare results" column headings {"Handler name", "Match?"} with title "Handler Diff Results"

–指定のハンドラの内容を抽出する(コメントぐらいは結果から削除してもいいような気もする)
–Script Objectの使用は考慮していない。1つのAppleScript書類からScript Objectで論理分割された同名のハンドラが複数検出されるケースは想定していない
on extractHandlerSourceOnly(wholeScript as string, handlerName as string)
  –インデント文字(Tab)をすべて削除
  
set targScript to repChar(wholeScript, tab, "") of me
  
  
–"on"ではじまるハンドラと仮定して抽出
  
set handlerStr to extractStrFromTo(targScript, "on " & handlerName, "end " & handlerName) of me
  
if handlerStr = false then
    –"to"ではじまるハンドラと仮定して抽出
    
set handlerStr to extractStrFromTo(targScript, "to " & handlerName, "end " & handlerName) of me
    
if handlerStr = false then return false
  else
    return handlerStr
  end if
end extractHandlerSourceOnly

on retHandlerNamesFromAppleScriptSource(aFile)
  set aRec to getAttrRecFromASPath(aFile) of me
  
set cList to getAppleScriptSourceColors() of me
  
  
set targAttr to contents of item 7 of cList –ハンドラあるいは変数
  
set tmpCoStr to ((redValue of targAttr) as string) & " " & ((greenValue of targAttr) as string) & " " & ((blueValue of targAttr) as string)
  
  
set ontoColItem to contents of item 3 of cList –スクリプティング予約語(on/to)
  
set ontoCoStr to ((redValue of ontoColItem) as string) & " " & ((greenValue of ontoColItem) as string) & " " & ((blueValue of ontoColItem) as string)
  
  
  
–変数あるいはハンドラ名称をリストアップ(variables & handler)
  
set tmp1Array to NSArray’s arrayWithArray:aRec
  
set thePred0 to NSPredicate’s predicateWithFormat_("colorStr == %@", tmpCoStr)
  
set dArray to (tmp1Array’s filteredArrayUsingPredicate:thePred0) as list
  
  
–改行を含むデータをリストアップ(text data contains return)
  
set thePred1 to NSPredicate’s predicateWithFormat_("stringVal CONTAINS %@", return)
  
set eArray to ((tmp1Array’s filteredArrayUsingPredicate:thePred1)’s valueForKeyPath:"itemIndex") as list
  
  
set the beginning of eArray to 0 –ハンドラ宣言部がTopに来る場合に備える
  
  
–"on"(ハンドラ宣言)の項目をリストアップ 文字と色で抽出
  
set thePred2 to NSPredicate’s predicateWithFormat_("stringVal == %@ && colorStr == %@ ", "on", ontoCoStr)
  
set fArray to ((tmp1Array’s filteredArrayUsingPredicate:thePred2)’s valueForKeyPath:"itemIndex") as list
  
  
–"to"(ハンドラ宣言ないしは代入対象指定) の項目をリストアップ文字と色で抽出
  
set thePred3 to NSPredicate’s predicateWithFormat_("stringVal == %@ && colorStr == %@ ", "to", ontoCoStr)
  
set gArray to ((tmp1Array’s filteredArrayUsingPredicate:thePred3)’s valueForKeyPath:"itemIndex") as list
  
  
  
set handlerList to {}
  
  
–on ではじまるハンドラの抽出
  
repeat with i in eArray –改行を含むテキストのアイテム番号リスト
    set j to (contents of i) as integer
    
repeat with ii in fArray –"on"の項目リスト
      set jj to (contents of ii) as integer
      
      
set handlerStr to missing value
      
      
if (j + 1) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      else if (j + 2) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      end if
      
      
if handlerStr is not in {"error", missing value} and handlerStr is not in handlerList then
        set the end of handlerList to handlerStr
      end if
      
    end repeat
  end repeat
  
  
  
–to ではじまるハンドラの抽出
  
repeat with i in eArray –改行を含むテキストのアイテム番号リスト
    set j to (contents of i) as integer
    
repeat with ii in gArray –"to"の項目リスト
      set jj to (contents of ii) as integer
      
      
set handlerStr to missing value
      
      
if (j + 1) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      else if (j + 2) = jj then
        set handlerStr to stringVal of (item (jj + 2) of (aRec as list))
      end if
      
      
if handlerStr is not in {"error", missing value} and handlerStr is not in handlerList then
        set the end of handlerList to handlerStr
      end if
      
    end repeat
  end repeat
  
  
return handlerList
end retHandlerNamesFromAppleScriptSource

–ソースを取得してコンパイル(構文確認)する方式から、URL(fileURL)を指定してコンパイル(構文確認)する方式に変更した
on getAttrRecFromASPath(aFile)
  set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of aFile)
  
set theScript to OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
  
if theScript is equal to missing value then
    — handle error
    
error "Compile Error"
  else
    –set sourceText to theScript’s source() –No Use
    
set styledSourceText to theScript’s richTextSource()
  end if
  
  
set attrRes to getAttributeRunsFromAttrString(styledSourceText) of me
  
return attrRes
end getAttrRecFromASPath

–指定AppleScriptファイルのソースコードを取得する(実行専用Scriptからは取得できない)
— Original Created 2014-02-23 Shane Stanley
on getASsourceFor(anAlias as {alias, string})
  set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of anAlias)
  
set theScript to OSAScript’s alloc()’s initWithContentsOfURL:aURL |error|:(missing value)
  
  
if theScript is equal to missing value then
    — handle error
    
error "Compile Error"
  else
    set sourceText to theScript’s source()
  end if
  
  
return sourceText as string
end getASsourceFor

–Attributed StringをDictionary化
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
  
set itemCount to 1
  
  
repeat until (startIndex = theLength)
    set {theAtts, theRange} to theStyledText’s attributesAtIndex:startIndex longestEffectiveRange:(specifier) 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, itemIndex:itemCount}
    
set startIndex to current application’s NSMaxRange(theRange)
    
    
set itemCount to itemCount + 1
  end repeat
  
  
return (styleList of aSpd)
  
end getAttributeRunsFromAttrString

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

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

–AS書式で配色に重複がないかどうかチェック
on chkASLexicalFormatColorConfliction(aList)
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set bList to (anArray’s valueForKeyPath:"redValue.stringValue") as list
  
set cList to (anArray’s valueForKeyPath:"greenValue.stringValue") as list
  
set dList to (anArray’s valueForKeyPath:"blueValue.stringValue") as list
  
  
set colStrList to {}
  
repeat with i from 1 to (length of bList)
    set bItem to contents of item i of bList
    
set cItem to contents of item i of cList
    
set dItem to contents of item i of dList
    
set the end of colStrList to bItem & " " & cItem & " " & dItem
  end repeat
  
  
set aRes to returnDuplicatesOnly(colStrList) of me
  
log aRes
  
if aRes is equal to {} then
    return true –重複が存在しなかった場合
  else
    return false –重複があった場合
  end if
end chkASLexicalFormatColorConfliction

on returnDuplicatesOnly(aList as list)
  set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bList to (aSet’s allObjects()) as list
  
  
set dupList to {}
  
repeat with i in bList
    set aRes to (aSet’s countForObject:i)
    
if aRes > 1 then
      set the end of dupList to (contents of i)
    end if
  end repeat
  
  
return dupList
end returnDuplicatesOnly

on retTwoPathList()
  tell application "Script Debugger"
    set dList to name of every document
    
set dResList to choose from list dList with prompt "Select two documents" with multiple selections allowed
    
if dResList = false then return false
    
if length of dResList is not equal to 2 then
      display dialog "Please Select two documents to compare handler contents" buttons {"OK"} default button 1 with icon 1 with title "Selection Error"
      
return false
    end if
    
    
set dPathList to {}
    
repeat with i in dResList
      set j to contents of i
      
tell document j
        set tmpPath to (file spec) as string –HFS path string
      end tell
      
      
set the end of dPathList to tmpPath
    end repeat
  end tell
  
  
return dPathList
end retTwoPathList

–Written By Philip Aker
–文字置換ルーチン
on repChar(origText as string, targStr as string, repStr as string)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

–指定文字と終了文字に囲まれた内容を抽出
on extractStrFromTo(aParamStr, fromStr, toStr)
  set theScanner to current application’s NSScanner’s scannerWithString:aParamStr
  
set anArray to current application’s NSMutableArray’s array()
  
  
repeat until (theScanner’s isAtEnd as boolean)
    set {theResult, theKey} to theScanner’s scanUpToString:fromStr intoString:(specifier)
    
theScanner’s scanString:fromStr intoString:(missing value)
    
set {theResult, theValue} to theScanner’s scanUpToString:toStr intoString:(specifier)
    
if theValue is missing value then set theValue to "" –>追加
    
theScanner’s scanString:toStr intoString:(missing value)
    
anArray’s addObject:theValue
  end repeat
  
  
if anArray’s |count|() is not equal to 1 then return false
  
  
return first item of (anArray as list)
end extractStrFromTo

★Click Here to Open This Script 

Posted in Color OSA Record Text | Tagged 10.12savvy 10.13savvy 10.14savvy NSArray NSCountedSet NSDictionary NSPredicate NSString NSUnarchiver OSAScript Script Debugger | Leave a comment

Keynote書類のテキスト色を置換

Posted on 6月 9, 2019 by Takaaki Naganoya

最前面のKeynote書類の文字色を置換するAppleScriptです。

# 初出時にはmacOS 10.13であったため、スクリプトエディタ上からも野良Framework呼び出しができましたが、macOS 10.14以降ではSIPを解除するかScript Debugger上で実行する必要があります

Keynoteは文字色の置換をする機能が実装されていないので、個別に手で色を変更するか、あるいはスタイルを編集して一括で修正するやり方になります。

そこで、AppleScriptで色置換を行う処理を書いてみました。表の背景色を置換する処理を書いたときの部品を大幅に使いまわしています。

文字色の取得や判定は、テキストアイテムの1文字目の情報で判断しています。途中で色を変更しているような場合にはうまく検出できません(処理スピードを重視したことと、自分の利用方法の範囲ではそういう文字ごとに異なる色を指定するところまではサポートしなくてよいと考えたためです。仕事ならもうちょっと真面目に作り込むかもしれませんが、、、、)。

ポップアップメニュー中の色名の動的な推定に、オープンソースの「DBColorNames」をフレームワーク化した
「dbColNamesKit.framework」を利用しています。

–> dbColNamesKit.framework (To ~/Library/Frameworks)


▲左上の時刻部分の色を置換したい


▲本Scriptを実行した直後。最前面のKeynote書類のすべてのテキストを走査して文字色を取得する


▲取得した文字色リスト。この中から置換対象を選択する。色データから色名を動的に生成し、色IDとともに名称で個別に指定したり識別したりできる


▲変更後の色をカラーピッカーで選択


▲Keynote書類上の文字色を変更してみた

AppleScript名:Keynote書類の現在のテキスト色を置換.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/06/08
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5" — Yosemite (10.11) or later
use framework "Foundation"
use framework "AppKit"
use framework "dbColNamesKit" –https://github.com/daniel-beard/DBColorNames/
use scripting additions

property NSView : a reference to current application’s NSView
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSMenu : a reference to current application’s NSMenu
property NSImage : a reference to current application’s NSImage
property NSIndexSet : a reference to current application’s NSIndexSet
property NSTextField : a reference to current application’s NSTextField
property NSColorWell : a reference to current application’s NSColorWell
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 NSMutableArray : a reference to current application’s NSMutableArray
property NSRunningApplication : a reference to current application’s NSRunningApplication

property returnCode : 0
property pop1ind : 0

–スライド枚数をカウント
tell application "Keynote"
  tell front document
    set sCount to count every slide
  end tell
end tell

–すべてのテキストアイテム、タイトルから色情報を取得する
set cList to {}
repeat with sNum from 1 to sCount
  set cList to cList & getEveryTextColorOfSlide(sNum) of me
end repeat

–文字色のユニーク化
set dList to makeUniqueListOf(cList) of me

set paramObj to {mainDat:dList, myTitle:"テキスト色置換", mySubTitle:"Keynoteのテキストアイテム、デフォルトアイテム(タイトル)の文字色置換", myColorRangeMax:65535}
my getPopupValues:paramObj

if pop1ind = false then return –timed out
set fromCol to (contents of item pop1ind of dList)

–カラーピッカーで置換色選択
set tCol to choose color default color fromCol

–Keynote書類中のテキストの文字色を置換
repeat with sNum from 1 to sCount
  set cList to cList & repEveryTextColorOfSlide(sNum, fromCol, tCol) of me
end repeat

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  set ap1List to (mainDat of (paramObj as record)) as list
  
set winTitle to (myTitle of (paramObj as record)) as string
  
set subTitle to (mySubTitle of (paramObj as record)) as string
  
set aColMax to (myColorRangeMax of (paramObj as record)) as list
  
  
–Viewをつくる
  
set aView to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 360, 80))
  
  
–Labelをつくる
  
set a1TF to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 40, 80, 20))
  
a1TF’s setEditable:false
  
a1TF’s setStringValue:"From Color:"
  
a1TF’s setDrawsBackground:false
  
a1TF’s setBordered:false
  
  
–Ppopup Buttonをつくる
  
set a1Button to NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(80, 40, 200, 20)) pullsDown:false
  
a1Button’s removeAllItems()
  
  
set a1Menu to NSMenu’s alloc()’s init()
  
set aCDB to current application’s DBColorNames’s alloc()’s init()
  
  
–Popup Menuをつくる
  
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 makeRoundedNSImageWithFilledWithColor(64, 64, nsCol, 4) of me
    
    
–色名をRGB値から動的に生成(あらかじめdbNamesが持っているカラーパレットの近似色の色名を返す)
    
set aTitle to "#" & (iCount as string) & " " & (aCDB’s nameForColor:nsCol) as string
    
    
–Menu Itemを作成する
    
set aMenuItem to (NSMenuItem’s alloc()’s initWithTitle:aTitle action:"actionHandler:" keyEquivalent:"")
    (
aMenuItem’s setImage:anImage)
    (
aMenuItem’s setEnabled:true)
    (
aMenuItem’s setTarget:me)
    (
a1Menu’s addItem:aMenuItem)
    
    
set iCount to iCount + 1
  end repeat
  
  
–Popup ButtonにPopup Menuを設定する
  
a1Button’s setMenu:a1Menu
  
  
–ViewにPopup Buttonとテキストラベルを入れる
  
aView’s addSubview:a1TF
  
aView’s addSubview:a1Button
  
aView’s setNeedsDisplay:true
  
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:winTitle
    
its setInformativeText:subTitle
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aView
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
  
  
set s1Val to ((a1Button’s indexOfSelectedItem() as number) + 1)
  
copy s1Val to my pop1ind
end getPopupValues:

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

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

–aMaxValを最大値とする数値でNSColorを作成して返す
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

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

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す、anRadiusの半径の角丸で
on makeRoundedNSImageWithFilledWithColor(aWidth as integer, aHeight as integer, fillColor, anRadius as real)
  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 bezierPathWithRoundedRect:theRect xRadius:anRadius yRadius:anRadius
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
  
return anImage
end makeRoundedNSImageWithFilledWithColor

–最前面のKeynote書類のすべてのスライドから、テキストアイテムとタイトルアイテムの文字色を取得
on getEveryTextColorOfSlide(sNum)
  set cList to {}
  
  
tell application "Keynote"
    tell front document
      set sMax to count every slide
      
if sMax < sNum then return false
      
      
tell slide sNum
        –すべての文字アイテムの先頭の文字の色情報を取得
        
try
          set tCount to count every text item
          
repeat with i from 1 to tCount
            set s1List to color of character 1 of object text of text item i
            
set the end of cList to s1List
          end repeat
        on error
          –set s1List to {}
        end try
        
        
–タイトルの先頭の文字の色情報を取得
        
try
          set s2List to color of character 1 of object text of default title item
          
set the end of cList to s2List
        on error
          set s2List to {}
        end try
      end tell
      
    end tell
  end tell
  
  
return cList
end getEveryTextColorOfSlide

–最前面のKeynote書類の指定番号のスライドで、テキストアイテムとタイトルアイテムの文字色を置換
on repEveryTextColorOfSlide(sNum, fromCol, toCol)
  tell application "Keynote"
    tell front document
      set sMax to count every slide
      
if sMax < sNum then return false
      
      
tell slide sNum
        –すべての文字アイテムの先頭の文字の色情報を置換
        
try
          set tCount to count every text item
          
repeat with i from 1 to tCount
            set s1List to color of character 1 of object text of text item i
            
if s1List = fromCol then
              ignoring application responses
                set color of every character of object text of text item i to toCol
              end ignoring
            end if
          end repeat
        on error
          —
        end try
        
        
–タイトルの先頭の文字の色情報を置換
        
try
          set s2List to color of character 1 of object text of default title item
          
if s2List = fromCol then
            ignoring application responses
              set color of every character of object text of default title item to toCol
            end ignoring
          end if
        on error
          set s2List to {}
        end try
      end tell
      
    end tell
  end tell
end repEveryTextColorOfSlide

–Listのユニーク化
on makeUniqueListOf(theList)
  set theSet to current application’s NSOrderedSet’s orderedSetWithArray:theList
  
return (theSet’s array()) as list
end makeUniqueListOf

★Click Here to Open This Script 

Posted in Color dialog GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy Keynote NSAlert NSBezierPath NSColor NSColorWell NSImage NSIndexSet NSMenu NSMenuItem NSMutableArray NSPopUpButton NSRunningApplication NSTextField NSView | Leave a comment

Numbersで選択中の表のセルの範囲を背景色で頻度集計

Posted on 6月 6, 2019 by Takaaki Naganoya

Numbersでオープン中の書類の現在のシート上にある表の選択範囲のセルに対して、背景色(Background color)で登場頻度の集計を行って、どの色が何回登場しているかを色プレビューしつつ表示するAppleScriptです。

集計をRGB値で数値的に行うことは容易ですが、結局のところ色なんてRGB値で見せられてもわからず、実際に目で見える色で表示しないと判断できません。そのため、アラートダイアログを作成してその上にColorWellで表示しています。


▲Numbersの表でセルを選択


▲Numbersの表のセルに指定されている背景色の登場頻度で集計し、色プレビューと登場回数を表示(スクリプトエディタ@macOS 10.14.5上の表示、Dark Mode)


▲Numbersの表のセルに指定されている背景色の登場頻度で集計し、色プレビューと登場回数を表示(Script Debugger@macOS 10.14.5上の表示、Dark Mode)

上記サンプル表は本Blog上での説明用のために簡略化した表ですが、実際には数十行の入り組んだNumbersの表を相手にしており、かつ、手作業で色付きセルだけを数えるなんて考えたくもないレベルで頻繁に確認しなくてはならなかったために、本Scriptを作ってみました。

Numbersにかぎらず、iWorkアプリケーション(Keynote、Pages、Numbers)で共通の仕様ですが、背景色を塗らないセルから背景色を取得するとmissing valueが返ります。

本ScriptはScript Menuに入れて実行するとアラートダイアログが最前面に出てこないなど、Script書類(.scpt、.scptd)のままで実行すると問題が発生。Script Menuに入れる場合にはアプレット(.app)書き出しする必要があります。


▲スクリプトメニューにアプレット書き出しした実行ファイルを入れて呼び出し(macOS 10.14.5)。スクリプトメニューは最前面にあるGUIアプリケーションに応じて、それぞれのアプリケーション用のメニューを表示できるようになっている

AppleScript名:選択中の表のセルの範囲を背景色で頻度集計.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/06/06
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

property NSView : a reference to current application’s NSView
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSIndexSet : a reference to current application’s NSIndexSet
property NSTextField : a reference to current application’s NSTextField
property NSColorWell : a reference to current application’s NSColorWell
property NSScrollView : a reference to current application’s NSScrollView
property NSMutableArray : a reference to current application’s NSMutableArray
property NSRunningApplication : a reference to current application’s NSRunningApplication

property theResult : 0
property returnCode : 0
property theDataSource : {}

tell application "Numbers"
  tell front document
    tell active sheet
      try
        set theTable to first table whose class of selection range is range
      on error
        return "No Selection" –何も選択されてなかった場合
      end try
      
      
tell theTable
        set bgColList to background color of every cell of selection range
        
–> {{18572, 45937, 65452}, {18572, 45937, 65452}, {3001, 24801, 44056}, {18572, 45937, 65452}, {18572, 45937, 65452}, {64899, 33134, 31509}, {64899, 33134, 31509}, {18572, 45937, 65452}, {18572, 45937, 65452}, {3001, 24801, 44056}, {18572, 45937, 65452}, {18572, 45937, 65452}, {26149, 65534, 58650}, {26149, 65534, 58650}, {26149, 65534, 58650}, {26149, 65534, 58650}, {18572, 45937, 65452}, {18572, 45937, 65452}}
      end tell
    end tell
  end tell
end tell

set bgColList to countItemsByItsAppearance(bgColList) of me
–> {{theName:{65535, 65533, 65534}, numberOfTimes:73}, {theName:{65535, 65535, 21706}, numberOfTimes:73}, {theName:missing value, numberOfTimes:27}}

set paramObj to {mainDat:bgColList, myTitle:"色別集計", mySubTitle:"Numbers上で選択したセルの背景色の頻度集計"}
–my browseColors:paramObj–for debug

my performSelectorOnMainThread:"browseColors:" withObject:(paramObj) waitUntilDone:true

on browseColors:paramObj
  set aParamList to (mainDat of (paramObj as record)) as list
  
set winTitle to (myTitle of (paramObj as record)) as string
  
set subTitle to (mySubTitle of (paramObj as record)) as string
  
  
set aLen to length of aParamList
  
  
set aHeight to 100
  
set aWidth to 300
  
  
–NSViewをつくる
  
set aNSV to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight * 1.5))
  
aNSV’s setNeedsDisplay:true
  
  
— NSScroll Viewをつくる
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
aScroll’s setDocumentView:aNSV
  
  
aNSV’s enclosingScrollView()’s setHasHorizontalScroller:true
  
aNSV’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
–NSColorWell+ NSTextFieldをつくる
  
set aStep to 1
  
repeat with i in aParamList
    set aColorWell to (NSColorWell’s alloc()’s initWithFrame:(current application’s NSMakeRect(10, ((aLen – aStep + 1) * 30), 60, 20)))
    
    
set myName to (theName of i)
    
set myTimes to (numberOfTimes of i)
    
    
if myName is not equal to missing value then
      copy (myName as list) to {rNum, gNum, bNum}
      
set myTimes to numberOfTimes of i
      
      
set myColor to makeNSColorFromRGBAval(rNum, gNum, bNum, 65535, 65535) of me
      (
aColorWell’s setColor:myColor)
      (
aColorWell’s setBordered:false)
      (
aNSV’s addSubview:aColorWell)
      
      
set aTF to makeNSTextField(80, ((aLen – aStep + 1) * 30), 100, 20, false, myTimes as string, true, true) of me
      (
aNSV’s addSubview:aTF)
      
      
set aStep to aStep + 1
    end if
  end repeat
  
  
–NSScrollViewを強制的にトップにスクロール
  
set aPT to current application’s NSMakePoint(0.0, aHeight)
  
aScroll’s documentView()’s scrollPoint:aPT
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:winTitle
    
its setInformativeText:subTitle
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aScroll
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
  
end browseColors:

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

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

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

★Click Here to Open This Script 

Posted in Color dialog list Record | Tagged 10.12savvy 10.13savvy 10.14savvy NSAlert NSColor NSColorWell NSCountedSet NSDictionary NSIndexSet NSMutableArray NSRunningApplication NSScrollView NSSortDescriptor NSTextField NSView Numbers | Leave a comment

Keynote書類の現在のスライド上の選択中の表の背景色を置換 v2

Posted on 5月 4, 2019 by Takaaki Naganoya

Keynoteでオープン中の最前面の書類の現在表示中のスライドに存在する選択中の表オブジェクトの背景色を置換するAppleScriptです。

–> Keynote_table_color_replace v2 Run-Only (Download Run-only script with Framework and Library)

初版ではtable 1を決め打ちで指定していましたが、選択中の表オブジェクトへの参照を取得するルーチンを組み込んで、選択中の表を処理できるように機能アップしました。

Scriptの状態で、macOS 10.12.6+Keynote v8.1上で動作確認。Appletの状態で、macOS 10.14.4/10.13.6+Keynote v9.0.1上で動作確認してあります。

本Scriptは大量のセルを持つ表を高速に色置換するために作成したものなので、時間がかかってもよくてのんびり色置換するだけでよければ、このコードの10分の1以下で書けます。

(1)セルを1つずつ塗るのではなく、複数セルを一度に塗る高速化
(2)セルの連続範囲を縦方向と横方向にセル連続区間を検出・カウントを実行。どちらか処理が早く終わる方を採用(処理前に2方向でシミュレーション)
(3)Keynoteとの間で非同期処理を行って処理高速化
(4)色選択のためにカラーポップアップメニューを、独自で作成したウィンドウ上に表示
(5)色の内容を把握しやすいように、色のRGB数値から色名をその場で生成
(6)カラーポップアップ上に表示する色プレビューを角丸で表示

といった高速化、高機能化のための実装をふんだんに投下しています。これらをすべて撤去すれば相当に記述量は少なくて済むことでしょう。

AppleScript名:Keynote書類の現在のスライド上の選択中の表の背景色を置換 v2
— Created 2019-01-29 by Takaaki Naganoya
— Modified 2019-05-04 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "dbColNamesKit" –https://github.com/daniel-beard/DBColorNames/
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

–v1:Convert Pages version to Keynote
–v2:Prepare Selected Table

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 NSFloatingWindowLevel : a reference to current application’s NSFloatingWindowLevel
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton

property windisp : true
property wController : missing value
property pop1ind : 1

–初期化
set (my windisp) to true
set (my pop1ind) to 1
load framework

–選択中のTableオブジェクトへの参照を取得する
set theTable to getSelectedTable() of me

–選択中のTableオブジェクトの塗り色をすべて取得
tell application "Keynote"
  tell theTable
    set c1List to background color of every cell
    
set aProp to properties
    
set xCount to column count of aProp
  end tell
end tell

–Convert 1D List to 2D List
set c3List to (current application’s SMSForder’s subarraysFrom:c1List groupedBy:xCount |error|:(missing value)) as list

–色データをユニーク化(重複削除)
set bList to uniquifyList(c1List) of me

–missing value(背景色なし)を除外する
set c2List to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bList)) as list

–Popup Menuで置換色選択
set paramObj to {c2List, 65535, "OK", "Select Target Color", 180} –Timeout = 180 sec, Color val range = 16bit
my performSelectorOnMainThread:"getPopupValues:" withObject:(paramObj) waitUntilDone:true
if pop1ind = false then return –timed out
set fromCol to (contents of item pop1ind of c2List)

–カラーピッカーで置換色選択
set tCol to choose color default color fromCol

set d1 to current date

–実際に表の背景色を置換する
set hitList to findDataFrom2DList(fromCol, c3List) of me –データ上で当該色のセル情報を計算する

–Rangeを横スキャンと縦スキャンの2通りで試算(Two way Simulation)
set rList1 to retRangeFromPosListHorizontal(hitList) of me –横方向へのrange評価
set rList2 to retRangeFromPosListVertival(hitList) of me –縦方向へのrange評価

–Simulationの結果、要素数の少ない方(=処理時間の短い方=高速な方)を採用する
log {"Simulation", (length of rList1), (length of rList2)}
if (length of rList1) < (length of rList2) then
  copy rList1 to rangeList
else
  copy rList2 to rangeList
end if

tell application "Keynote"
  activate
  
  
tell theTable
    repeat with i in rangeList
      set j to contents of i
      
      
ignoring application responses –非同期実行モードで高速実行
        set background color of range j to tCol
      end ignoring
      
    end repeat
  end tell
  
end tell

set d2 to current date
return d2 – d1

on getSelectedTable()
  tell application "Keynote"
    tell front document
      tell current slide
        try
          set theTable to first table whose class of selection range is range
        on error
          set tCount to count every table
          
if tCount = 0 then
            error "No Selected Table Objects…"
          else
            –選択セルがない場合はTable 1を全選択
            
set theTable to table 1
          end if
        end try
        
        
return theTable
      end tell
    end tell
  end tell
end getSelectedTable

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  copy (paramObj as list) to {ap1List, aColMax, aButtonMSG, aSliderValMSG, 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 aCDB to current application’s DBColorNames’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 makeRoundedNSImageWithFilledWithColor(64, 64, nsCol, 4) of me
    
    
set aTitle to "#" & (iCount as string) & " " & (aCDB’s nameForColor:nsCol) 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:(NSMomentaryLightButton)
  
bButton’s setBezelStyle:(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, aSliderValMSG))
  
  
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 number) + 1)
  else
    set s1Val to false
  end if
  
  
copy s1Val to my pop1ind
  
end getPopupValues:

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

–make Window for Display
on makeWinWithView(aView, aWinWidth as integer, aWinHeight as integer, aTitle as string)
  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:(NSFloatingWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
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:

–aMaxValを最大値とする数値でNSColorを作成して返す
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

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

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す、anRadiusの半径の角丸で
on makeRoundedNSImageWithFilledWithColor(aWidth as integer, aHeight as integer, fillColor, anRadius as real)
  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 bezierPathWithRoundedRect:theRect xRadius:anRadius yRadius:anRadius
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
  
return anImage
end makeRoundedNSImageWithFilledWithColor

on uniquifyList(aList as list)
  set aArray to NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

on findDataFrom2DList(anItem, aList as list)
  script spd
    property aList : {}
    
property resList : {}
  end script
  
  
set (aList of spd) to aList
  
set (resList of spd) to {}
  
  
set yCount to 1
  
  
repeat with i in (aList of spd)
    
    
set aResList to (Bplus’s indexesOfItem:anItem inList:i inverting:false) as list
    
    
set tmpList to {}
    
if aResList is not equal to {} then
      repeat with ii in aResList
        set jj to contents of ii
        
set the end of tmpList to {jj, yCount}
      end repeat
      
set (resList of spd) to (resList of spd) & tmpList
    end if
    
    
set yCount to yCount + 1
  end repeat
  
  
return (resList of spd) –return {{x, y}…..} item list (1-based)
end findDataFrom2DList

on retRangeFromPosListVertival(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
–縦方向へのrange評価に都合がいいようにソート
  
set (posList2 of rangeSPD) to shellSortListAscending(posList, {1, 2}) of me
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 = tmpX) and (curY1 + 1 = tmpY) then
      –Y方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListVertival

on retRangeFromPosListHorizontal(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
copy posList to (posList2 of rangeSPD)
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 + 1 = tmpX) and (curY1 = tmpY) then
      –X方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListHorizontal

–2008/05/01 By Takaaki Naganoya
–10進数数値をExcel 2004/2008的カラム表現にエンコードするサブルーチン を使いまわし
–1〜1351までの間であれば正しいエンコーディング結果を返す
on aNumToExcelColumn(origNum as integer)
  if origNum > 1351 then
    error "エラー:Excel 2004/2008的カラム表現(A1形式)への変換ルーチンにおいて、想定範囲外(1351以上)のパラメータが指定されました"
  end if
  
  
set upperDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
set lowerDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
  
set oNum to origNum
  
set nTh to 26
  
set stringLength to 4
  
  
–数字が1桁の場合の対応
  
if origNum < 27 then
    set aRes to (item origNum of upperDigitEncTable) as string
    
return aRes
  end if
  
  
  
if origNum > 702 then
    –3桁になる場合
    
set upupNum to oNum div 676 –整数除算–上の上の桁
    
set oNum to oNum – (upupNum * 676)
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upupChar to (item upupNum of upperDigitEncTable) as string
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upupChar & upChar & lowChar
    
  else
    –2桁の場合
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upChar & lowChar
    
  end if
  
  
return resText
end aNumToExcelColumn

–入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  return sort2DList(a, keyItem, {true}) of me
end shellSortListAscending

–入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  return sort2DList(a, keyItem, {false}) of me
end shellSortListDecending

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
  
  
–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
  
set newIndex to {}
  
repeat with i in sortIndexes
    set j to contents of i
    
set j to j – 1
    
set the end of newIndex to j
  end repeat
  
  
–Sort TypeのListを作成(あえて外部から指定する内容でもない)
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to "compare:"
  end repeat
  
  
–Sort
  
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list
  
  
return resList
end sort2DList

★Click Here to Open This Script 

Posted in Color dialog GUI | Leave a comment

指定単語の花文字テキストを取得する(Retina対応)英文字用 v2

Posted on 3月 29, 2019 by Takaaki Naganoya

英語版の花文字テキストを作成してテキストエディタ(CotEditor)に出力するAppleScriptです。

描画用の英単語と、塗りつぶし用の英単語を別々に指定できます。invertFをtrueに設定すると、白黒反転出力を行います。

おおもとの元ネタは、大型計算機を大勢のユーザーで共有していた時代(ぱそこん登場前)、計算結果を高速プリンタの帳票に出力するようになっていたころにさかのぼります。どのユーザーの計算結果かを大量のプリンタの出力結果の中から仕分けるため、印刷出力の1ページ目をユーザー名などの情報を印字した「バナー」として使用。

そのさい、ドットインパクトプリンターだったので、決められた固定ドット数の文字しか印字できないため、英数字を組み合わせて擬似的に大きな文字でバナーを印刷していたことに端を発します。

その時代の「残り香」ともいえるバナーがパソコンの電子メールやBBSの時代にお遊びの「花文字」として引き継がれ、原始的なアスキーアートの一種として楽しまれてきました。

いまでも、shell commandの「banner」コマンドにその末裔を見ることができます。

先週のmacOS nativeのデモ時に「祝」という花文字を「呪」の文字で出力するという、定番の持ちネタを披露したところ、たいへんウケておりました。

ただ、これを海外のScripter向けにそのままデモしても受けません。

この、花文字テキストを出力するプログラムの英語版としては、love.scptといういにしえのデータをそのまま使いまわしたものがありますが、描画パターンを数値データで保持しているため、異なるパターンを表示させることはできません。

そこで、日本語版の花文字テキスト出力プログラムに若干手をくわえ、英単語の出力が行えるようにしてみました。

テキストの出力はCotEditorに対して行なっていますが、新規書類を指定文字で作成する程度なので、AppleScriptに対応しているテキストエディタならどれでも作り変えられます。また、表示を等幅フォントにしておく必要があります(あとから指定してもOK)。

AppleScript名:指定単語の花文字テキストを取得する(Retina対応)英文字用 v2
— Created 2017-12-12 by Takaaki Naganoya
— Modified 2019-03-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

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

property fillCharList : {}
property fillCharCounter : 1

set aString to "Love"
set bString to "hate"
set hanaSize to 24
set thisFont to selectAFont(first character of aString) of me
if thisFont = false then return –Cancel

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

–花文字文字列を計算して返す
on getEnglishHanamojiStr(aFontSize as real, aFontName as string, aString as string, fillString as string, aThread as real, incFontName as boolean, invertF as boolean)
  
  
set my fillCharList to characters of fillString
  
set my fillCharCounter to 1
  
  
–指定文字コードが指定フォント中に存在するかチェック
  
repeat with i in (characters of aString)
    set fRes to retGlyphsInFont(aFontName, id of i) of me
    
if fRes = false then return false
  end repeat
  
  
set aThreadShould to 768 * aThread
  
if (chkMultiByteChar(first character of 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 invertF = false then
        
        
–通常描画(invert = false)時
        
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 getChar() of me
            else
              set the end of strListX to spaceChar
            end if
          else
            set the end of strListX to spaceChar
          end if
        end if
        
      else
        –白黒反転(invert = true)時
        
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 spaceChar
            else
              set the end of strListX to getChar() of me
            end if
          else
            set the end of strListX to getChar() of me
          end if
        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 "Font=" & fName & return & return & aRes
  end if
  
  
return aRes
end getEnglishHanamojiStr

on getChar()
  set retChar to item (my fillCharCounter) of (my fillCharList)
  
if (my fillCharCounter) = length of (my fillCharList) then
    set (my fillCharCounter) to 1
  else
    set (my fillCharCounter) to (my fillCharCounter) + 1
  end if
  
return retChar
end getChar

–指定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 

Posted in Color Image RTF Text | Tagged 10.12savvy 10.13savvy 10.14savvy CotEditor NSArray NSBezierPath NSBitmapImageRep NSColor NSColorSpace NSDictionary NSFont NSFontManager NSImage NSMutableAttributedString NSMutableDictionary NSPredicate NSString | 1 Comment

クリップボード内のRTFをStyled Stringとして解釈して行ごとに分割して画面描画サイズ幅で昇順ソートして再結合

Posted on 2月 27, 2019 by Takaaki Naganoya

クリップボードにコピーしておいた書式つきテキストを、行ごとに画面上の描画サイズで昇順ソートし、再結合してクリップボードに転送するAppleScriptです。

ほぼ毎日使っているAppleScriptの改良版です。

Cocoaの機能を呼び出すと、AppleScript冒頭にproperty宣言文を書くことになりますが(書かなくてもいいんですが)、この宣言文を「プロポーショナルフォントを考慮しつつ実際の画面上の描画サイズを考慮」して短いものから長いものにソートして掲載しています。

ただし、従来のバージョンでは実際のフォントではなく一律に指定フォントで描画したさいの描画幅でソートしていたため、ごくまれに掲載時のリストが短い順になっていませんでした(世界中で誰も気にしてねえよ! ^ー^;)。

これを、実際の指定フォントやサイズを考慮した行単位のスタイル付きテキストに分解し、描画幅でソートしたあとにスタイル付きテキストを再合成するようにしました。

従来のOld Style AppleScriptではスタイル付きテキストの操作は一切できませんでしたが、Cocoaの機能を活用することでこのように自由度の高い処理ができるようになった、という好例です。

なお、本ルーチンによって厳密に描画幅でソートしても、Web掲載時にはWebブラウザのレンダリングのルール(&ユーザー側で指定しているWebブラウザのフォント)が適用されるため、macOS上のアプリケーション上での見た目と若干違いが出るという残念な結果も出ています。

macOS標準装備のスクリプトメニューに入れて呼び出しています。

AppleScript名:クリップボード内のRTFをStyled Stringとして解釈して行ごとに分割して画面描画サイズ幅で昇順ソートして再結合
— Created 2017-04-24 by Shane Stanley
— Modified 2019-02-27 by Takaaki Naganoya
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

property NSFont : a reference to current application’s NSFont
property NSColor : a reference to current application’s NSColor
property NSPasteboard : a reference to current application’s NSPasteboard
property NSAttributedString : a reference to current application’s NSAttributedString
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName

–クリップボードの内容をNSAttributedStringに
set anAttr to my getClipboardASStyledText()
if anAttr = missing value then return

–Split Attributed Strings into lines
set attrList to splitAttributedStringByLines(anAttr) of me

–Sort by Width in ascending
set sortedList to shellSortListAscending(attrList, 1) of me

–Append Attributed Strings
set mutableReturn to NSMutableAttributedString’s alloc()’s initWithString:(return)
set outStr to NSMutableAttributedString’s alloc()’s initWithString:""

repeat with i in sortedList
  copy i to {tmpWidth, tmpAttr}
  (
outStr’s appendAttributedString:tmpAttr)
  
  
set tmpStr to tmpAttr’s |string|() as string
  
if (tmpStr does not end with string id 10) and (tmpStr does not end with string id 13) then
    (outStr’s appendAttributedString:mutableReturn)
  end if
end repeat

— Set Styled String to Clipboard
set theArray to {outStr}
restoreClipboard(theArray) of me

–Clipboardにデータを設定する
on restoreClipboard(theArray as list)
  set thePasteboard to NSPasteboard’s generalPasteboard()
  
thePasteboard’s clearContents()
  
thePasteboard’s writeObjects:theArray
end restoreClipboard

— クリップボードの内容をNSAttributedStringとして取り出して返す
on getClipboardASStyledText()
  try
    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
  on error
    return missing value
  end try
end getClipboardASStyledText

on splitAttributedStringByLines(theStyledText)
  set outList to {}
  
set outAttr to NSMutableAttributedString’s alloc()’s initWithString:""
  
  
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 –String
    
    
set aColor to (theAtts’s valueForKeyPath:"NSColor") –Color
    
set aFont to (theAtts’s valueForKeyPath:"NSFont") –Font
    
if aFont is equal to missing value then error "Not font name and size are specified" –Font Name error
    
set aDFontName to aFont’s displayName() –Font Name
    
set aDFontSize to aFont’s pointSize() –Font Size
    
    
set tmpAttrStr to generateAttributedString(aText, aDFontName, aDFontSize, aColor) of me
    
outAttr’s appendAttributedString:tmpAttrStr
    
    
if (aText contains return) or (aText contains string id 10) then –CR or LF
      set tmpSize to outAttr’s |size|()
      
set tmpWidth to retWidthFromSize(tmpSize) of me
      
      
set the end of outList to {tmpWidth, outAttr}
      
set outAttr to NSMutableAttributedString’s alloc()’s initWithString:""
    end if
    
    
set startIndex to current application’s NSMaxRange(theRange)
  end repeat
  
  
set tmpSize to outAttr’s |size|()
  
set tmpWidth to retWidthFromSize(tmpSize) of me
  
set the end of outList to {tmpWidth, outAttr}
  
  
return outList
end splitAttributedStringByLines

on retWidthFromSize(tmpSize)
  if class of tmpSize = record then
    –macOS 10.10, 10.11, 10.12
    
set tmpWidth to width of tmpSize
  else
    –macOS 10.13, 10.14
    
set tmpWidth to first item of tmpSize
  end if
  
return tmpWidth
end retWidthFromSize

on generateAttributedString(aStr, aFontPSName, aFontSize, aColor)
  set tmpAttr to NSMutableAttributedString’s alloc()’s initWithString:aStr
  
set aRange to current application’s NSMakeRange(0, tmpAttr’s |length|())
  
set aVal1 to NSFont’s fontWithName:aFontPSName |size|:aFontSize
  
tmpAttr’s beginEditing()
  
tmpAttr’s addAttribute:(NSFontAttributeName) value:aVal1 range:aRange
  
tmpAttr’s addAttribute:(NSForegroundColorAttributeName) value:aColor range:aRange
  
tmpAttr’s endEditing()
  
return tmpAttr
end generateAttributedString

–入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  return sort2DList(a, keyItem, {true}) of me
end shellSortListAscending

–入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  return sort2DList(a, keyItem, {false}) of me
end shellSortListDecending

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
  load framework
  
–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
  
set newIndex to {}
  
repeat with i in sortIndexes
    set j to contents of i
    
set j to j – 1
    
set the end of newIndex to j
  end repeat
  
  
–Sort TypeのListを作成(あえて外部から指定する内容でもない)
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to "compare:"
  end repeat
  
  
–Sort
  
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list
  
return resList
end sort2DList

★Click Here to Open This Script 

Posted in Clipboard Color list RTF Sort Text | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSAttributedString NSColor NSFont NSFontAttributeName NSForegroundColorAttributeName NSMutableAttributedString NSPasteboard | Leave a comment

アラートダイアログの背景色を指定してTable Viewを表示

Posted on 2月 25, 2019 by Takaaki Naganoya

指定色のアラートダイアログを作成し、その上にScroll View+Table Viewを表示して選択肢の選択を行うAppleScriptです。

アラートダイアログの背景色変更のテストを行なったものです。また、メソッド名をテキストで(Table Viewから)取得し、そのメソッド名で色を作成するテスト(NSSelectorFromString)も行いました。

Table Viewで選択した色は、次回実行時に反映されます(スクリプトエディタ/Script Debugger上で)。

本当はTable View上で行を選択したときに、アラートダイアログの背景色を変更させたかったのですが、試してみたもののうまく動かなかったので、その機能は削りました。最初から指定色のダイアログウィンドウを表示するだけなら問題はないので、現状のようなコードに落ち着きました。

AppleScript名:アラートダイアログの背景色を指定してTable Viewを表示
— Created 2019-02-25 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSIndexSet : a reference to current application’s NSIndexSet
property NSScrollView : a reference to current application’s NSScrollView
property NSTableView : a reference to current application’s NSTableView
property NSTableColumn : a reference to current application’s NSTableColumn
property NSMutableArray : a reference to current application’s NSMutableArray
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSAlertSecondButtonReturn : a reference to current application’s NSAlertSecondButtonReturn
property NSFullSizeContentViewWindowMask : a reference to current application’s NSFullSizeContentViewWindowMask

property theResult : 0
property returnCode : 0
property theDataSource : {}
property theColList : {}
property theWindow : missing value
property selectedColor : missing value

set paramObj to {myMessage:"Choose a color", mySubMessage:"Choose an appropriate color from color name list", aTableList:{"redColor", "blueColor", "yellowColor", "greenColor", "grayColor", "blackColor"}}
set aRes to my chooseItemByTableView:paramObj

on chooseItemByTableView:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set aTList to (aTableList of paramObj) as list
  
  
— make table view with scroll view
  
set aScrollWithTable to makeTableView(aTList, 300, 120) of me
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aScrollWithTable
  end tell
  
  
— customize alert’s window style and color
  
if selectedColor = missing value then
    set tmpColor to NSColor’s grayColor()
  else
    set tmpSel to current application’s NSSelectorFromString(selectedColor)
    
set tmpColor to NSColor’s performSelector:tmpSel
  end if
  
  
set theWindow to theAlert’s |window|()
  
theWindow’s setTitleVisibility:false
  
–theWindow’s setStyleMask:( NSFullSizeContentViewWindowMask)
  
theWindow’s setTitlebarAppearsTransparent:true
  
theWindow’s setBackgroundColor:tmpColor
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
  
  
return (aScrollWithTable’s documentView’s selectedRow()) + 1
end chooseItemByTableView:

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

on makeTableView(aList as list, aWidth as number, aHeight as number)
  set aOffset to 40
  
  
set sourceList to {}
  
repeat with i in aList
    set the end of sourceList to {dataItem:(contents of i)}
  end repeat
  
  
set theDataSource to NSMutableArray’s alloc()’s init()
  
theDataSource’s addObjectsFromArray:sourceList
  
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
  
set aView to NSTableView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aOffset, aWidth, aHeight))
  
  
  
set aColumn to (NSTableColumn’s alloc()’s initWithIdentifier:"dataItem")
  (
aColumn’s setWidth:aWidth)
  (
aColumn’s headerCell()’s setStringValue:"dataItem")
  (
aView’s addTableColumn:aColumn)
  
  
aView’s setDelegate:me
  
aView’s setDataSource:me
  
aView’s reloadData()
  
  
aScroll’s setDocumentView:aView
  
aView’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
–1行目を選択
  
set aIndexSet to NSIndexSet’s indexSetWithIndex:0
  
aView’s selectRowIndexes:aIndexSet byExtendingSelection:false
  
  
–強制的にトップにスクロール
  
set aDBounds to aScroll’s documentView()’s |bounds|()
  
if class of aDBounds = list then
    –macOS 10.13 or later
    
set maxHeight to item 2 of item 1 of aDBounds
  else
    –macOS 10.10….10.12
    
set maxHeight to height of |size| of aDBounds
  end if
  
  
set aPT to current application’s NSMakePoint(0.0, -40.0) —— (aScroll’s documentView()’s |bounds|()’s |size|()’s height))
  
aScroll’s documentView()’s scrollPoint:aPT
  
  
return aScroll
end makeTableView

–TableView Event Handlers
on numberOfRowsInTableView:aView
  return my theDataSource’s |count|()
end numberOfRowsInTableView:

on tableView:aView objectValueForTableColumn:aColumn row:aRow
  set selRow to (aRow as number)
  
set aRec to (my theDataSource)’s objectAtIndex:selRow
  
set aTitle to (aColumn’s headerCell()’s title()) as string
  
set aRes to (aRec’s valueForKey:aTitle) as string
  
set my selectedColor to aRes
  
  
return aRes
end tableView:objectValueForTableColumn:row:

on tableView:aView shouldEditTableColumn:aTableColumn row:rowIndex
  return false –Not Editable
end tableView:shouldEditTableColumn:row:

★Click Here to Open This Script 

Posted in Color GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSAlert NSAlertSecondButtonReturn NSColor NSFullSizeContentViewWindowMask NSIndexSet NSMutableArray NSRunningApplication NSScrollView NSTableColumn NSTableView | Leave a comment

Keynote書類の現在のスライド上の表1の背景色を置換 v1

Posted on 1月 31, 2019 by Takaaki Naganoya

Keynoteでオープン中の最前面の書類の現在表示中のスライドに存在する表1の背景色を置換するAppleScriptです。

Pages用のScriptをごく一部修正してkeynoteの表に対して処理できるようにしてみました。macOS 10.11, 10.12, 10.13ではスクリプトエディタ上で動作します。macOS 10.14ではSIPを解除してスクリプトエディタで動かすか、アプレット形式で書き出して、アプレットのバンドル中にdbColNamesKit.frameworkを入れると動きます。

Script DebuggerとScript Menu上では動作しません。

ポップアップメニュー中に色の名称の動的な推定に、オープンソースの「DBColorNames」をフレームワーク化した
「dbColNamesKit.framework」を利用しています。

–> dbColNamesKit.framework (To ~/Library/Frameworks)

AppleScript名:Keynote書類の現在のスライド上の表の背景色を置換 v1
— Created 2019-01-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "dbColNamesKit" –https://github.com/daniel-beard/DBColorNames/
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

–v1:Convert Pages version to Keynote

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 NSFloatingWindowLevel : a reference to current application’s NSFloatingWindowLevel
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton

property windisp : true
property wController : missing value
property pop1ind : 1

–初期化
set (my windisp) to true
set (my pop1ind) to 1
load framework

–Pagesの1ページ目にある表の塗り色を取得
tell application "Keynote"
  tell front document
    tell current slide
      tell table 1
        set c1List to background color of every cell
        
set aProp to properties
        
set xCount to column count of aProp
      end tell
    end tell
  end tell
end tell

–Convert 1D List to 2D List
set c3List to (current application’s SMSForder’s subarraysFrom:c1List groupedBy:xCount |error|:(missing value)) as list

–色データをユニーク化(重複削除)
set bList to uniquifyList(c1List) of me

–missing value(背景色なし)を除外する
set c2List to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bList)) as list

–Popup Menuで置換色選択
set paramObj to {c2List, 65535, "OK", "Select Target Color", 180} –Timeout = 180 sec, Color val range = 16bit
my performSelectorOnMainThread:"getPopupValues:" withObject:(paramObj) waitUntilDone:true
if pop1ind = false then return –timed out
set fromCol to (contents of item pop1ind of c2List)

–カラーピッカーで置換色選択
set tCol to choose color default color fromCol

set d1 to current date

–実際に表の背景色を置換する
set hitList to findDataFrom2DList(fromCol, c3List) of me –データ上で当該色のセル情報を計算する

–Rangeを横スキャンと縦スキャンの2通りで試算(Two way Simulation)
set rList1 to retRangeFromPosListHorizontal(hitList) of me –横方向へのrange評価
set rList2 to retRangeFromPosListVertival(hitList) of me –縦方向へのrange評価

–Simulationの結果、要素数の少ない方(=処理時間の短い方=高速な方)を採用する
log {"Simulation", (length of rList1), (length of rList2)}
if (length of rList1) < (length of rList2) then
  copy rList1 to rangeList
else
  copy rList2 to rangeList
end if

tell application "Keynote"
  activate
  
tell front document
    tell current slide
      tell table 1
        repeat with i in rangeList
          set j to contents of i
          
          
ignoring application responses –非同期実行モードで高速実行
            set background color of range j to tCol
          end ignoring
          
        end repeat
      end tell
    end tell
  end tell
end tell

set d2 to current date
return d2 – d1

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  copy (paramObj as list) to {ap1List, aColMax, aButtonMSG, aSliderValMSG, 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 aCDB to current application’s DBColorNames’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 makeRoundedNSImageWithFilledWithColor(64, 64, nsCol, 4) of me
    
    
set aTitle to "#" & (iCount as string) & " " & (aCDB’s nameForColor:nsCol) 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:(NSMomentaryLightButton)
  
bButton’s setBezelStyle:(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, aSliderValMSG))
  
  
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 number) + 1)
  else
    set s1Val to false
  end if
  
  
copy s1Val to my pop1ind
  
end getPopupValues:

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

–make Window for Display
on makeWinWithView(aView, aWinWidth as integer, aWinHeight as integer, aTitle as string)
  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:(NSFloatingWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
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:

–aMaxValを最大値とする数値でNSColorを作成して返す
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

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

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す、anRadiusの半径の角丸で
on makeRoundedNSImageWithFilledWithColor(aWidth as integer, aHeight as integer, fillColor, anRadius as real)
  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 bezierPathWithRoundedRect:theRect xRadius:anRadius yRadius:anRadius
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
  
return anImage
end makeRoundedNSImageWithFilledWithColor

on uniquifyList(aList as list)
  set aArray to NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

on findDataFrom2DList(anItem, aList as list)
  script spd
    property aList : {}
    
property resList : {}
  end script
  
  
set (aList of spd) to aList
  
set (resList of spd) to {}
  
  
set yCount to 1
  
  
repeat with i in (aList of spd)
    
    
set aResList to (Bplus’s indexesOfItem:anItem inList:i inverting:false) as list
    
    
set tmpList to {}
    
if aResList is not equal to {} then
      repeat with ii in aResList
        set jj to contents of ii
        
set the end of tmpList to {jj, yCount}
      end repeat
      
set (resList of spd) to (resList of spd) & tmpList
    end if
    
    
set yCount to yCount + 1
  end repeat
  
  
return (resList of spd) –return {{x, y}…..} item list (1-based)
end findDataFrom2DList

on retRangeFromPosListVertival(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
–縦方向へのrange評価に都合がいいようにソート
  
set (posList2 of rangeSPD) to shellSortListAscending(posList, {1, 2}) of me
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 = tmpX) and (curY1 + 1 = tmpY) then
      –Y方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListVertival

on retRangeFromPosListHorizontal(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
copy posList to (posList2 of rangeSPD)
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 + 1 = tmpX) and (curY1 = tmpY) then
      –X方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListHorizontal

–2008/05/01 By Takaaki Naganoya
–10進数数値をExcel 2004/2008的カラム表現にエンコードするサブルーチン を使いまわし
–1〜1351までの間であれば正しいエンコーディング結果を返す
on aNumToExcelColumn(origNum as integer)
  if origNum > 1351 then
    error "エラー:Excel 2004/2008的カラム表現(A1形式)への変換ルーチンにおいて、想定範囲外(1351以上)のパラメータが指定されました"
  end if
  
  
set upperDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
set lowerDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
  
set oNum to origNum
  
set nTh to 26
  
set stringLength to 4
  
  
–数字が1桁の場合の対応
  
if origNum < 27 then
    set aRes to (item origNum of upperDigitEncTable) as string
    
return aRes
  end if
  
  
  
if origNum > 702 then
    –3桁になる場合
    
set upupNum to oNum div 676 –整数除算–上の上の桁
    
set oNum to oNum – (upupNum * 676)
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upupChar to (item upupNum of upperDigitEncTable) as string
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upupChar & upChar & lowChar
    
  else
    –2桁の場合
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upChar & lowChar
    
  end if
  
  
return resText
end aNumToExcelColumn

–入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  return sort2DList(a, keyItem, {true}) of me
end shellSortListAscending

–入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  return sort2DList(a, keyItem, {false}) of me
end shellSortListDecending

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
  
  
–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
  
set newIndex to {}
  
repeat with i in sortIndexes
    set j to contents of i
    
set j to j – 1
    
set the end of newIndex to j
  end repeat
  
  
–Sort TypeのListを作成(あえて外部から指定する内容でもない)
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to "compare:"
  end repeat
  
  
–Sort
  
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list
  
  
return resList
end sort2DList

★Click Here to Open This Script 

Posted in Color GUI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote NSArray NSBezierPath NSButton NSColor NSImage NSMenu NSMenuItem NSPopUpButton NSScreen NSTextField NSView NSWindow NSWindowController | 1 Comment

Numbers書類の現在のシート上の表1の背景色を置換 v1

Posted on 1月 31, 2019 by Takaaki Naganoya

Numbersでオープン中の最前面の書類の現在表示中のシートに存在する表1の背景色を置換するAppleScriptです。

Pages用のScriptをごく一部修正してNumbersの表に対して処理できるようにしてみました。macOS 10.11, 10.12, 10.13ではスクリプトエディタ上で動作します。macOS 10.14ではSIPを解除してスクリプトエディタで動かすか、アプレット形式で書き出して、アプレットのバンドル中にdbColNamesKit.frameworkを入れると動きます。

Script DebuggerとScript Menu上では動作しません。

ポップアップメニュー中に色の名称の動的な推定に、オープンソースの「DBColorNames」をフレームワーク化した
「dbColNamesKit.framework」を利用しています。

–> dbColNamesKit.framework (To ~/Library/Frameworks)

AppleScript名:Numbers書類の現在のシート上の表1の背景色を置換 v1
— Created 2019-01-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "dbColNamesKit" –https://github.com/daniel-beard/DBColorNames/
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

–v1:Change Pages part to Numbers

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 NSFloatingWindowLevel : a reference to current application’s NSFloatingWindowLevel
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton

property windisp : true
property wController : missing value
property pop1ind : 1

–初期化
set (my windisp) to true
set (my pop1ind) to 1
load framework

–Pagesの1ページ目にある表の塗り色を取得
tell application "Numbers"
  tell front document
    tell active sheet
      tell table 1
        set c1List to background color of every cell
        
set aProp to properties
        
set xCount to column count of aProp
      end tell
    end tell
  end tell
end tell

–Convert 1D List to 2D List
set c3List to (current application’s SMSForder’s subarraysFrom:c1List groupedBy:xCount |error|:(missing value)) as list

–色データをユニーク化(重複削除)
set bList to uniquifyList(c1List) of me

–missing value(背景色なし)を除外する
set c2List to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bList)) as list

–Popup Menuで置換色選択
set paramObj to {c2List, 65535, "OK", "Select Target Color", 180} –Timeout = 180 sec, Color val range = 16bit
my performSelectorOnMainThread:"getPopupValues:" withObject:(paramObj) waitUntilDone:true
if pop1ind = false then return –timed out
set fromCol to (contents of item pop1ind of c2List)

–カラーピッカーで置換色選択
set tCol to choose color default color fromCol

set d1 to current date

–実際に表の背景色を置換する
set hitList to findDataFrom2DList(fromCol, c3List) of me –データ上で当該色のセル情報を計算する

–Rangeを横スキャンと縦スキャンの2通りで試算(Two way Simulation)
set rList1 to retRangeFromPosListHorizontal(hitList) of me –横方向へのrange評価
set rList2 to retRangeFromPosListVertival(hitList) of me –縦方向へのrange評価

–Simulationの結果、要素数の少ない方(=処理時間の短い方=高速な方)を採用する
if (length of rList1) < (length of rList2) then
  copy rList1 to rangeList
else
  copy rList2 to rangeList
end if

tell application "Numbers"
  activate
  
tell front document
    tell active sheet
      tell table 1
        repeat with i in rangeList
          set j to contents of i
          
          
ignoring application responses –非同期実行モードで高速実行
            set background color of range j to tCol
          end ignoring
          
        end repeat
      end tell
    end tell
  end tell
end tell

set d2 to current date
return d2 – d1

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  copy (paramObj as list) to {ap1List, aColMax, aButtonMSG, aSliderValMSG, 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 aCDB to current application’s DBColorNames’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 makeRoundedNSImageWithFilledWithColor(64, 64, nsCol, 4) of me
    
    
set aTitle to "#" & (iCount as string) & " " & (aCDB’s nameForColor:nsCol) 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:(NSMomentaryLightButton)
  
bButton’s setBezelStyle:(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, aSliderValMSG))
  
  
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 number) + 1)
  else
    set s1Val to false
  end if
  
  
copy s1Val to my pop1ind
  
end getPopupValues:

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

–make Window for Display
on makeWinWithView(aView, aWinWidth as integer, aWinHeight as integer, aTitle as string)
  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:(NSFloatingWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
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:

–aMaxValを最大値とする数値でNSColorを作成して返す
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

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

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す、anRadiusの半径の角丸で
on makeRoundedNSImageWithFilledWithColor(aWidth as integer, aHeight as integer, fillColor, anRadius as real)
  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 bezierPathWithRoundedRect:theRect xRadius:anRadius yRadius:anRadius
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
  
return anImage
end makeRoundedNSImageWithFilledWithColor

on uniquifyList(aList as list)
  set aArray to NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

on findDataFrom2DList(anItem, aList as list)
  script spd
    property aList : {}
    
property resList : {}
  end script
  
  
set (aList of spd) to aList
  
set (resList of spd) to {}
  
  
set yCount to 1
  
  
repeat with i in (aList of spd)
    
    
set aResList to (Bplus’s indexesOfItem:anItem inList:i inverting:false) as list
    
    
set tmpList to {}
    
if aResList is not equal to {} then
      repeat with ii in aResList
        set jj to contents of ii
        
set the end of tmpList to {jj, yCount}
      end repeat
      
set (resList of spd) to (resList of spd) & tmpList
    end if
    
    
set yCount to yCount + 1
  end repeat
  
  
return (resList of spd) –return {{x, y}…..} item list (1-based)
end findDataFrom2DList

on retRangeFromPosListVertival(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
–縦方向へのrange評価に都合がいいようにソート
  
set (posList2 of rangeSPD) to shellSortListAscending(posList, {1, 2}) of me
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 = tmpX) and (curY1 + 1 = tmpY) then
      –Y方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListVertival

on retRangeFromPosListHorizontal(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
copy posList to (posList2 of rangeSPD)
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 + 1 = tmpX) and (curY1 = tmpY) then
      –X方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListHorizontal

–2008/05/01 By Takaaki Naganoya
–10進数数値をExcel 2004/2008的カラム表現にエンコードするサブルーチン を使いまわし
–1〜1351までの間であれば正しいエンコーディング結果を返す
on aNumToExcelColumn(origNum as integer)
  if origNum > 1351 then
    error "エラー:Excel 2004/2008的カラム表現(A1形式)への変換ルーチンにおいて、想定範囲外(1351以上)のパラメータが指定されました"
  end if
  
  
set upperDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
set lowerDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
  
set oNum to origNum
  
set nTh to 26
  
set stringLength to 4
  
  
–数字が1桁の場合の対応
  
if origNum < 27 then
    set aRes to (item origNum of upperDigitEncTable) as string
    
return aRes
  end if
  
  
  
if origNum > 702 then
    –3桁になる場合
    
set upupNum to oNum div 676 –整数除算–上の上の桁
    
set oNum to oNum – (upupNum * 676)
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upupChar to (item upupNum of upperDigitEncTable) as string
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upupChar & upChar & lowChar
    
  else
    –2桁の場合
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upChar & lowChar
    
  end if
  
  
return resText
end aNumToExcelColumn

–入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  return sort2DList(a, keyItem, {true}) of me
end shellSortListAscending

–入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  return sort2DList(a, keyItem, {false}) of me
end shellSortListDecending

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
  
  
–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
  
set newIndex to {}
  
repeat with i in sortIndexes
    set j to contents of i
    
set j to j – 1
    
set the end of newIndex to j
  end repeat
  
  
–Sort TypeのListを作成(あえて外部から指定する内容でもない)
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to "compare:"
  end repeat
  
  
–Sort
  
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list
  
  
return resList
end sort2DList

★Click Here to Open This Script 

Posted in Color GUI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSBezierPath NSButton NSColor NSImage NSMenu NSMenuItem NSPopUpButton NSRoundedBezelStyle NSScreen NSTextField NSTitledWindowMask NSView NSWindow NSWindowController Numbers | Leave a comment

Pages書類の1ページ目の表の背景色を置換 v4

Posted on 1月 30, 2019 by Takaaki Naganoya

Pagesでオープン中の最前面の書類の1ページ目に存在する表オブジェクト中の背景色を置換するAppleScriptです。

例によって、Pages書類上の表オブジェクトは「配置」を「移動しない」に設定しないとAppleScriptからアクセスできないので、あらかじめ「移動しない」設定にしておく必要があります。

本バージョンでは、データの連続部分をrangeとしてまとめて処理する方法を、1行ずつ横方向に(左→右)スキャンした場合と、1列ずつ(上→下)縦方向にスキャンした場合の2パターンで処理し、より少ないデータ単位(より多くのセルを一括で指定)で処理できる方の方式を採用するようにしました。

このため、処理データによって塗りつぶし動作が変わってきます。横方向のみのスキャンでは大幅に遅くなるタイプのデータ(縦に処理対象セルが並んでいて、横方向にはつながっていない)でも「遅くならない」ことがテーマです。

ほかには、オープンソースの「DBColorNames」を利用して色から色名称を動的に取得したり、ポップアップメニューに表示する色イメージ画像を角丸にしたりしています。

–> dbColNamesKit.framework (To ~/Library/Frameworks)

これ以上の高速化は、「縦横混在のrangeシミュレーション」でも行わないとできないと思いますが、方法についてはいろいろ思いつくので論理的には可能だと思います。ただ、単に塗りつぶしを高速化するためだけに何日も試行錯誤するのはちょっと………なので、このぐらいにしておこうかと。

macOS 10.14上では、「csrutil disable」でSIPをオフにすると、ホームディレクトリ下の~/Library/Frameworksフォルダ内のFrameworkにアクセスでき、本Scriptをそのままスクリプトエディタで実行できました。アプレット形式で書き出して、アプレット内にFrameworkを入れればSIPをオフにしなくても実行できるはずです。Script Debugger/Script Menu上では実行できないというあたりが困りどころです。

AppleScript名:Pages書類の1ページ目の表の背景色を置換 v4.1
— Created 2017-07-15 by Takaaki Naganoya
— Modified 2019-01-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "dbColNamesKit" –https://github.com/daniel-beard/DBColorNames/
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

–v1:First Version
–v2:Pick Up target cells by calculate every background color (35% speed up)
–v3:Draw cells by range (x20 speed up)
–v3.1:Bug Fix (retRangeFromPosList)
–v3.1.1:Bug Fix (retRangeFromPosList)
–v4:Two-way Simulation (Horizontal / Vertical scan), Corner-Rounded NSImage, Dynamic Color Naming
–v4.1:Correct Vertical Scan simulation (Sort list for vertical range evaluation, at first)

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 NSFloatingWindowLevel : a reference to current application’s NSFloatingWindowLevel
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton

property windisp : true
property wController : missing value
property pop1ind : 1

–初期化
set (my windisp) to true
set (my pop1ind) to 1
load framework

–Pagesの1ページ目にある表の塗り色を取得
tell application "Pages"
  tell front document
    tell table 1
      set c1List to background color of every cell
      
set aProp to properties
      
set xCount to column count of aProp
    end tell
  end tell
end tell

–色データをユニーク化(重複削除)
set bList to uniquifyList(c1List) of me

–Convert 1D List to 2D List
set c3List to (current application’s SMSForder’s subarraysFrom:c1List groupedBy:xCount |error|:(missing value)) as list

–missing value(背景色なし)を除外する
set c2List to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bList)) as list

–Popup Menuで置換色選択
set paramObj to {c2List, 65535, "OK", "Select Target Color", 180} –Timeout = 180 sec, Color val range = 16bit
my performSelectorOnMainThread:"getPopupValues:" withObject:(paramObj) waitUntilDone:true
if pop1ind = false then return –timed out
set fromCol to (contents of item pop1ind of c2List)

–カラーピッカーで置換色選択
set tCol to choose color default color fromCol

set d1 to current date

–実際に表の背景色を置換する
set hitList to findDataFrom2DList(fromCol, c3List) of me –データ上で当該色のセル情報を計算する

–Rangeを横スキャンと縦スキャンの2通りで試算(Two way Simulation)
set rList1 to retRangeFromPosListHorizontal(hitList) of me –横方向へのrange評価
set rList2 to retRangeFromPosListVertival(hitList) of me –縦方向へのrange評価

–Simulationの結果、要素数の少ない方(=処理時間の短い方=高速な方)を採用する
log {"Simulation", (length of rList1), (length of rList2)}
if (length of rList1) < (length of rList2) then
  copy rList1 to rangeList
else
  copy rList2 to rangeList
end if

tell application "Pages"
  activate
  
tell front document
    tell table 1
      repeat with i in rangeList
        set j to contents of i
        
        
ignoring application responses –非同期実行モードで高速実行
          set background color of range j to tCol
        end ignoring
        
      end repeat
    end tell
  end tell
end tell

set d2 to current date
return d2 – d1

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  copy (paramObj as list) to {ap1List, aColMax, aButtonMSG, aSliderValMSG, 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 aCDB to current application’s DBColorNames’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 makeRoundedNSImageWithFilledWithColor(64, 64, nsCol, 4) of me
    
    
set aTitle to "#" & (iCount as string) & " " & (aCDB’s nameForColor:nsCol) 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:(NSMomentaryLightButton)
  
bButton’s setBezelStyle:(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, aSliderValMSG))
  
  
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 number) + 1)
  else
    set s1Val to false
  end if
  
  
copy s1Val to my pop1ind
  
end getPopupValues:

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

–make Window for Display
on makeWinWithView(aView, aWinWidth as integer, aWinHeight as integer, aTitle as string)
  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:(NSFloatingWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
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:

–aMaxValを最大値とする数値でNSColorを作成して返す
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

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

–指定サイズのNSImageを作成し、指定色で塗ってNSImageで返す、anRadiusの半径の角丸で
on makeRoundedNSImageWithFilledWithColor(aWidth as integer, aHeight as integer, fillColor, anRadius as real)
  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 bezierPathWithRoundedRect:theRect xRadius:anRadius yRadius:anRadius
  
—
  
fillColor’s |set|() –色設定
  
theNSBezierPath’s fill() –ぬりつぶし
  
—
  
anImage’s unlockFocus()
  
  
return anImage
end makeRoundedNSImageWithFilledWithColor

on uniquifyList(aList as list)
  set aArray to NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

on findDataFrom2DList(anItem, aList as list)
  script spd
    property aList : {}
    
property resList : {}
  end script
  
  
set (aList of spd) to aList
  
set (resList of spd) to {}
  
  
set yCount to 1
  
  
repeat with i in (aList of spd)
    
    
set aResList to (Bplus’s indexesOfItem:anItem inList:i inverting:false) as list
    
    
set tmpList to {}
    
if aResList is not equal to {} then
      repeat with ii in aResList
        set jj to contents of ii
        
set the end of tmpList to {jj, yCount}
      end repeat
      
set (resList of spd) to (resList of spd) & tmpList
    end if
    
    
set yCount to yCount + 1
  end repeat
  
  
return (resList of spd) –return {{x, y}…..} item list (1-based)
end findDataFrom2DList

on retRangeFromPosListVertival(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
–縦方向へのrange評価に都合がいいようにソート
  
set (posList2 of rangeSPD) to shellSortListAscending(posList, {1, 2}) of me
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 = tmpX) and (curY1 + 1 = tmpY) then
      –Y方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListVertival

on retRangeFromPosListHorizontal(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
copy posList to (posList2 of rangeSPD)
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 + 1 = tmpX) and (curY1 = tmpY) then
      –X方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosListHorizontal

–2008/05/01 By Takaaki Naganoya
–10進数数値をExcel 2004/2008的カラム表現にエンコードするサブルーチン を使いまわし
–1〜1351までの間であれば正しいエンコーディング結果を返す
on aNumToExcelColumn(origNum as integer)
  if origNum > 1351 then
    error "エラー:Excel 2004/2008的カラム表現(A1形式)への変換ルーチンにおいて、想定範囲外(1351以上)のパラメータが指定されました"
  end if
  
  
set upperDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
set lowerDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
  
set oNum to origNum
  
set nTh to 26
  
set stringLength to 4
  
  
–数字が1桁の場合の対応
  
if origNum < 27 then
    set aRes to (item origNum of upperDigitEncTable) as string
    
return aRes
  end if
  
  
  
if origNum > 702 then
    –3桁になる場合
    
set upupNum to oNum div 676 –整数除算–上の上の桁
    
set oNum to oNum – (upupNum * 676)
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upupChar to (item upupNum of upperDigitEncTable) as string
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upupChar & upChar & lowChar
    
  else
    –2桁の場合
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upChar & lowChar
    
  end if
  
  
return resText
end aNumToExcelColumn

–入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  return sort2DList(a, keyItem, {true}) of me
end shellSortListAscending

–入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  return sort2DList(a, keyItem, {false}) of me
end shellSortListDecending

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
  
  
–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
  
set newIndex to {}
  
repeat with i in sortIndexes
    set j to contents of i
    
set j to j – 1
    
set the end of newIndex to j
  end repeat
  
  
–Sort TypeのListを作成(あえて外部から指定する内容でもない)
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to "compare:"
  end repeat
  
  
–Sort
  
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list
  
  
return resList
end sort2DList

★Click Here to Open This Script 

Posted in Color GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSBezierPath NSButton NSColor NSImage NSMenu NSMenuItem NSPopUpButton NSScreen NSTextField NSView NSWindow NSWindowController Pages | 2 Comments

Pages書類の1ページ目の表の背景色を置換 v3.1(約20倍速)

Posted on 1月 29, 2019 by Takaaki Naganoya

Pagesでオープン中の最前面の書類の1ページ目に存在する表オブジェクト中の背景色を置換するAppleScriptの高速化版です。

初版では表中のセルをすべて取得し、すべてのセルについて順次背景色を求め、置換対象色であれば塗り直していました。セル1個ずつ塗っていたので、それなりの時間(テストデータでは20秒)がかかっていました。GUIアプリケーションを操作するために存在しているAppleScriptですが、アプリケーションとの通信はコストが高いので、この通信部分を減らすことが高速化の基本です。

ちなみに、「ignoring application responses」〜「end ignoring」で囲った範囲は非同期実行モードで実行され、2.5倍ぐらい高速になります。AppleScriptでは、GUIアプリケーションに対してコマンドを実行した場合、「コマンド実行」「コマンド処理」「コマンド結果受信」の3ステップを行なっています。非同期実行モードでは「コマンド実行」だけを行うので高速ですが、設定値や状態を知りたいような場合には(結果が返ってこないので)使う意味がありません。本Blogを「ignoring application responses」で検索しても、あまり出てこないはずです。

v2では、高速化のために全セルの背景色を抽出したあとに、2次元配列データ上で当該セルの座標を計算し、塗り替え対象セルのみ処理することで約35%のスピードアップを行いました。GUIアプリケーションにコマンドを送る(そして、処理を待って結果を受信する)よりも配列変数上で検索を行ったほうがはるかに高速です。

本v3では、さらなる高速化のために、2次元配列データ上で当該セルの座標を計算したあと、それらを横方向にスキャンして、点ではなく範囲(range)として評価し、極力複数のセルを連続する範囲(range)としてまとめて、rangeを一括塗りすることで初版から約20倍の高速化を行なったものです。v1やv2ではセルを1つずつ塗りつぶしていましたが、v3からは横方向に複数まとめてぬりつぶします。

実際のPages書類上の表の塗りつぶし領域が、ヘッダーや年表のような横方向に連続した塗りエリアを持つことが多いことに着目して、複数セルを一度に塗りつぶすことで高速化しました(1セル塗るのと複数セルを塗るのとで時間かわらず)。本Scriptでも1マスごとに塗りつぶしが存在するようなハッチング模様の表の塗りつぶし色を変更する場合にはパフォーマンスが最悪の状態に落ち込みますが、v2のレベル以下に落ちることはないでしょう。

この世のどこかには、さらにデータを1D Arrayではなく2D Arrayとして評価して、最大限まとめた面積のrangeとみなすことで本ルーチンの2倍ぐらいの速度で処理できるプログラムも存在しそうですが、人類の叡智のレベルを超えそうなので、自分はこのぐらいの速度が出れば満足です(総当たり的なアプローチで全パターンをシミュレーションして、一番いい結果が出るものを採用というのも考えないではないですが、シミュレーションをていねいに行うと処理時間が余計にかかるので、、、)。

1D Listに入っている座標値をX軸方向に評価して、連続値であればrangeに変換するルーチン「retRangeFromPosList」については、それほど真剣にテストしていないので処理が間違っている可能性もあります。
→ 処理に誤りがあったので修正しました(v3.1)

また、数値からExcelのA1形式のアドレスに変換するために作ってホコリをかぶっていた「aNumToExcelColumn」ルーチンも、一応テストはしてありますが変換できるアドレスの上限値が存在しているため注意が必要です。

AppleScript名:Pages書類の1ページ目の表の背景色を置換 v3.11
— Created 2017-07-15 by Takaaki Naganoya
— Modified 2019-01-29 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

–v1:First Version
–v2:Pick Up target cells by calculate every background color (35% speed up)
–v3:Draw cells by range (x20 speed up)
–v3.1:Bug Fix (retRangeFromPosList)
–v3.1.1:Bug Fix (retRangeFromPosList)

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 : true
property wController : missing value
property pop1ind : 1

–初期化
set (my windisp) to true
set (my pop1ind) to 1
load framework

–Pagesの1ページ目にある表の塗り色を取得
tell application "Pages"
  tell front document
    tell table 1
      set c1List to background color of every cell
      
set aProp to properties
      
set xCount to column count of aProp
    end tell
  end tell
end tell

–色データをユニーク化(重複削除)
set bList to uniquifyList(c1List) of me

–Convert 1D List to 2D List
set c3List to (current application’s SMSForder’s subarraysFrom:c1List groupedBy:xCount |error|:(missing value)) as list

–missing value(背景色なし)を除外する
load framework
set c2List to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bList)) as list

–Popup Menuで置換色選択
set aButtonMSG to "OK"
set aSliderValMSG to "Select Target Color"
set paramObj to {c2List, 65535, aButtonMSG, aSliderValMSG, 20}
my performSelectorOnMainThread:"getPopupValues:" withObject:(paramObj) waitUntilDone:true
set fromCol to (contents of item pop1ind of c2List)

–カラーピッカーで置換色選択
set tCol to choose color default color fromCol

set d1 to current date

–実際に表の背景色を置換する
set hitList to findDataFrom2DList(fromCol, c3List) of me –データ上で当該色のセル情報を計算する

set rangeList to retRangeFromPosList(hitList) of me

tell application "Pages"
  tell front document
    tell table 1
      repeat with i in rangeList
        set j to contents of i
        
        
ignoring application responses –非同期実行モードで高速実行
          set background color of range j to tCol
        end ignoring
      end repeat
    end tell
  end tell
end tell

set d2 to current date
return d2 – d1

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  copy (paramObj as list) to {ap1List, aColMax, aButtonMSG, aSliderValMSG, 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:(NSMomentaryLightButton)
  
bButton’s setBezelStyle:(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, aSliderValMSG))
  
  
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 number) + 1)
  else
    set s1Val to false
  end if
  
  
copy s1Val to my pop1ind
  
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 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 setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
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:

–aMaxValを最大値とする数値でNSColorを作成して返す
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

–指定サイズのNSImageを作成し、指定色で塗って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 uniquifyList(aList as list)
  set aArray to NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

on findDataFrom2DList(anItem, aList)
  script spd
    property aList : {}
    
property resList : {}
  end script
  
  
set (aList of spd) to aList
  
set (resList of spd) to {}
  
  
set yCount to 1
  
  
repeat with i in (aList of spd)
    
    
set aResList to (Bplus’s indexesOfItem:anItem inList:i inverting:false) as list
    
    
set tmpList to {}
    
if aResList is not equal to {} then
      repeat with ii in aResList
        set jj to contents of ii
        
set the end of tmpList to {jj, yCount}
      end repeat
      
set (resList of spd) to (resList of spd) & tmpList
    end if
    
    
set yCount to yCount + 1
  end repeat
  
  
return (resList of spd) –return {{x, y}…..} item list (1-based)
end findDataFrom2DList

on retRangeFromPosList(posList as list)
  script rangeSPD
    property posList2 : {}
  end script
  
  
copy posList to (posList2 of rangeSPD)
  
  
–先頭データをピックアップ
  
set firstData to first item of (posList2 of rangeSPD)
  
set (posList2 of rangeSPD) to rest of (posList2 of rangeSPD)
  
  
copy firstData to {curX1, curY1}
  
set tmpRangeStr to aNumToExcelColumn(curX1) of me & (curY1 as string) & ":"
  
  
set tmpRange to {}
  
set hitF to false
  
  
set outList to {}
  
  
repeat with i in (posList2 of rangeSPD)
    copy i to {tmpX, tmpY}
    
    
–log {"{curX1, curY1}", {curX1, curY1}}
    
–log {"{tmpX, tmpY}", {tmpX, tmpY}}
    
    
    
if (curX1 + 1 = tmpX) and (curY1 = tmpY) then
      –X方向への連続値を拾っている最中
      
if hitF = false then
        –log "case 1a"
        
–log {"hitF", hitF}
        
set hitF to true
      else
        –log "case 1b"
        
–log {"hitF", hitF}
        
–横に連続しているブロックの途中
      end if
    else
      –直前の値と連続していない
      
if hitF = false then
        –log "case 2a"
        
–log {"hitF", hitF}
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
      else
        –log "case 2b"
        
–log {"hitF", hitF}
        
–連続ブロックの末尾を拾った
        
set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
        
set the end of outList to tmpRangeStr
        
set tmpRangeStr to aNumToExcelColumn(tmpX) of me & (tmpY as string) & ":"
        
set hitF to false
        
–log {"tmpRangeStr", tmpRangeStr}
      end if
    end if
    
    
copy {tmpX, tmpY} to {curX1, curY1}
  end repeat
  
  
–log {tmpRangeStr, hitF}
  
  
if (hitF = true) or (tmpRangeStr is not equal to "") then
    set tmpRangeStr to tmpRangeStr & aNumToExcelColumn(curX1) of me & (curY1 as string)
    
set the end of outList to tmpRangeStr
  end if
  
  
return outList
end retRangeFromPosList

–2008/05/01 By Takaaki Naganoya
–10進数数値をExcel 2004/2008的カラム表現にエンコードするサブルーチン を使いまわし
–1〜1351までの間であれば正しいエンコーディング結果を返す
on aNumToExcelColumn(origNum as integer)
  if origNum > 1351 then
    display dialog "エラー:Excel 2004/2008的カラム表現(A1形式)への変換ルーチンにおいて、想定範囲外(1351以上)のパラメータが指定されました" buttons {"OK"} default button 1
    
return ""
  end if
  
  
set upperDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
set lowerDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
  
set oNum to origNum
  
set nTh to 26
  
set stringLength to 4
  
  
–数字が1桁の場合の対応
  
if origNum < 27 then
    set aRes to (item origNum of upperDigitEncTable) as string
    
return aRes
  end if
  
  
  
if origNum > 702 then
    –3桁になる場合
    
set upupNum to oNum div 676 –整数除算–上の上の桁
    
set oNum to oNum – (upupNum * 676)
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upupChar to (item upupNum of upperDigitEncTable) as string
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upupChar & upChar & lowChar
    
  else
    –2桁の場合
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–超つじつま合わせ処理
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upChar & lowChar
    
  end if
  
  
return resText
end aNumToExcelColumn

★Click Here to Open This Script 

Posted in Color GUI list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSBackingStoreBuffered NSBezierPath NSButton NSColor NSImage NSMenu NSMenuItem NSMomentaryLightButton NSNormalWindowLevel NSPopUpButton NSRoundedBezelStyle NSScreen NSTextField NSTitledWindowMask NSView NSWindow NSWindowController Pages | Leave a comment

Pages書類の1ページ目の表の背景色を置換

Posted on 1月 28, 2019 by Takaaki Naganoya

Pagesでオープン中の最前面の書類の1ページ目に存在する表オブジェクト中の背景色を置換するAppleScriptです。

Pages書類の「表オブジェクト」にAppleScriptからアクセスするためには、Pages上で表オブジェクトを選択した状態で、

「オブジェクトの配置」を「移動しない」に事前に設定しておく必要があります。

本AppleScriptを実行可能なランタイム環境は、スクリプトエディタ、アプレットの2つです。スクリプトメニューおよびScript Debuggerでは各GUI部品のクリックイベントを拾えないために、実行しても選択などが行えません。

のように、1ページのみのPages書類に表オブジェクトを入れて、「移動しない」設定にしてある状態で本AppleScriptを実行。

表のセル中の色をすべて取得して、ユニーク化してポップアップメニューから「変更元」の色を選択できます。

選択して、「OK」ボタンをクリック。ここで選択した色が置換されます。

選択した色をどの色に変更(置換)するのかを指定します。

黒い色を選択。

ちょっと置換に時間がかかりますが(テストデータ+開発環境で20秒前後)、セルの背景色をします。このあたり、Pagesの表オブジェクト中のセルに対して、background colorでフィルタ参照できればよかったのですが、自分が試した範囲ではフィルタ参照で抽出できませんでした。全セルを取得してループで背景色のチェックと置換を行なっています。

こういう機能が最初からPagesに実装されているわけでもないので、手作業よりははるかに高速なのでしばらく放っておけば終わるのでいいんじゃないでしょうか。

本来であれば、指定色に該当するセルをフィルタ参照で抽出して、ヒットしたセルだけでループして背景色を変更できるとベストですが、実際にフィルタ参照で抽出できるかどうかはアプリケーション側の対応度次第なので、実際にやってみないとわかりません。

AppleScript名:Pages書類の1ページ目の表の背景色を置換
— Created 2017-07-15 by Takaaki Naganoya
— Created 2019-01-28 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

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
property wController : false
property pop1ind : missing value

–Pagesの1ページ目にある表の塗り色を取得
tell application "Pages"
  tell front document
    tell table 1
      set cList to background color of every cell
    end tell
  end tell
end tell

–色データをユニーク化(重複削除)
set bList to uniquifyList(cList) of me

–missing value(背景色なし)を除外する
load framework
set cList to (current application’s SMSForder’s arrayByDeletingBlanksIn:(bList)) as list

–Popup Menuで置換色選択
set aButtonMSG to "OK"
set aSliderValMSG to "Select Target Color"
set paramObj to {cList, 65535, aButtonMSG, aSliderValMSG, 20}
my performSelectorOnMainThread:"getPopupValues:" withObject:(paramObj) waitUntilDone:true

–カラーピッカーで色選択
set fromCol to (contents of item pop1ind of cList)
set tCol to choose color default color fromCol

–実際に表の背景色を置換する
tell application "Pages"
  tell front document
    tell table 1
      set cellList to every cell
      
      
repeat with i in cellList
        set aBG to background color of i
        
        
if aBG = fromCol then
          ignoring application responses
            set background color of i to tCol
          end ignoring
        end if
      end repeat
    end tell
  end tell
end tell

–カラーポップアップメニューをウィンドウ表示
on getPopupValues:paramObj
  copy (paramObj as list) to {ap1List, aColMax, aButtonMSG, aSliderValMSG, 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 0
  
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:(NSMomentaryLightButton)
  
bButton’s setBezelStyle:(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, aSliderValMSG))
  
  
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 number) + 1)
  else
    set s1Val to false
  end if
  
  
copy s1Val to my pop1ind
  
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 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 setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
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:

–aMaxValを最大値とする数値でNSColorを作成して返す
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

–指定サイズのNSImageを作成し、指定色で塗って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 uniquifyList(aList as list)
  set aArray to NSArray’s arrayWithArray:aList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquifyList

★Click Here to Open This Script 

Posted in Color GUI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSBackingStoreBuffered NSBezierPath NSButton NSColor NSImage NSMenu NSMenuItem NSMomentaryLightButton NSNormalWindowLevel NSPopUpButton NSRoundedBezelStyle NSScreen NSTextField NSTitledWindowMask NSView NSWindow NSWindowController Pages | 1 Comment

指定画像の指定座標の色情報をRGBで取得

Posted on 11月 15, 2018 by Takaaki Naganoya

指定画像の指定座標のピクセルの色を8ビットRGB値で返すAppleScriptです。

使用する座標系は左上が{0,0}です。

AppleScript名:指定画像の指定座標の色情報をRGBで取得.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/11/15
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Cocoa" –Foundation + AppKit
use scripting additions

property NSImage : a reference to current application’s NSImage
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep

set aFile to POSIX path of (choose file of type {"public.image"})
set {xNum, yNum} to {0, 0}

set cRes to getColorRGBNumFromImageByPosition(aFile, xNum, yNum) of me
–> {255, 0, 0}

on getColorRGBNumFromImageByPosition(aFilePath, xPos as integer, yPos as integer)
  set anNSImage to NSImage’s alloc()’s initWithContentsOfFile:aFilePath
  
set aRawimg to NSBitmapImageRep’s imageRepWithData:(anNSImage’s TIFFRepresentation())
  
  
set aColor to (aRawimg’s colorAtX:xPos y:yPos)
  
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 getColorRGBNumFromImageByPosition

★Click Here to Open This Script 

Posted in Color Image list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSBitmapImageRep NSImage | Leave a comment

Stickiesからのデータ取り出し v2

Posted on 9月 6, 2018 by Takaaki Naganoya

スティッキーズ(Stickies.app)のデータをまとめて引っこ抜いてListに入れるAppleScriptです。色情報、1行目の内容をタイトルとみなしてタイトル情報も付加して出力するようにしてみました。

オープンソースのStickiesViewerをFramework化したstickiesLib.frameworkを経由してデータを読み出します。データベースファイルから情報を直接読み取るので、Stickies.appが起動している必要はありません。

–> Download stickiesLib.framework(To ~/Library/Frameworks/)

–> {creationDate:date “2006年1月15日日曜日 11:02:32″, aTitle:”WX-310Kの画像サイズ”, modificationDate:date “2006年1月15日日曜日 11:03:09″, aContents:”WX-310Kの画像サイズ
ケータイ:120×160
壁紙:240×320″, colorName:”Yellow”}

StickiesDatabaseからまとめて一括で全部抽出するので、個別に何かのIDで指定して抽出するといった動作にはなりません。

93個のスティッキーズ書類(93個のウィンドウが表示されている状態、1つのDBを指定)から、全データを取得して本AppleScriptで0.1秒程度です。

AppleScript名:Stickiesからのデータ取り出し v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/09/05
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use framework "AppKit"
use framework "stickiesLib"
use scripting additions

property NSColor : a reference to current application’s NSColor
property |NSURL| : a reference to current application’s |NSURL|
property SVReader : a reference to current application’s SVReader
property NSFileManager : a reference to current application’s NSFileManager
property NSMutableArray : a reference to current application’s NSMutableArray

set sRes to retStickiesData() of me
–>
(*
{{creationDate:date "2006年1月15日日曜日 11:02:32", aTitle:"WX-310Kの画像サイズ", modificationDate:date "2006年1月15日日曜日 11:03:09", aContents:"WX-310Kの画像サイズ
ケータイ:120×160
壁紙:240×320", colorName:"Yellow"}, ….}
*)

on retStickiesData()
  set dbPath to POSIX path of (path to library folder from user domain) & "StickiesDatabase"
  
set aExt to (NSFileManager’s defaultManager()’s fileExistsAtPath:dbPath) as boolean
  
  
if aExt = false then
    set dbPath to POSIX path of (choose file with prompt "Select StickiesDatabase file")
  end if
  
  
set aURL to |NSURL|’s fileURLWithPath:dbPath
  
set aStickDB to SVReader’s notesWithContentsOfURL:aURL
  
  
set aList to aStickDB as list
  
  
–スティッキーズの色データ
  
set cList to {{"Yellow", {254, 244, 156}}, {"Blue", {173, 244, 255}}, {"Green", {178, 255, 161}}, {"Pink", {255, 199, 199}}, {"Purple", {182, 202, 255}}, {"Gray", {238, 238, 238}}}
  
  
  
set outArray to NSMutableArray’s new()
  
  
repeat with i in aList
    set anAttrStr to i’s attributedString()
    
set aStr to (anAttrStr’s |string|()) as string
    
    
set curTitle to first paragraph of aStr
    
    
set aColor to i’s |color|()
    
set cDate to i’s dateCreated() as date
    
set mDate to i’s dateModified() as date
    
    
set c1List to retColListFromNSColor(aColor, 255) of me
    
    
–Find Color Name
    
set hitF to false
    
repeat with ii in cList
      set {colName, colList} to ii
      
if c1List = colList then
        set hitF to true
        
exit repeat
      end if
    end repeat
    
    
if hitF = false then error "Color name did not hit"
    
    
set curName to colName
    (
outArray’s addObject:{creationDate:cDate, modificationDate:mDate, aContents:aStr, colorName:curName, aTitle:curTitle})
    
  end repeat
  
  
return outArray as list
end retStickiesData

on retColorFromRGBnum(r, g, b)
  return (NSColor’s colorWithCalibratedRed:r / 255.0 green:g / 255.0 blue:b / 255.0 alpha:1.0)
end retColorFromRGBnum

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

★Click Here to Open This Script 

Posted in Color File path RTF System | Tagged 10.11savvy 10.12savvy 10.13savvy NSColor NSFileManager NSMutableArray NSURL Stickies | Leave a comment

色付き単色画像を作成する(自由色指定&色名推定)

Posted on 7月 17, 2018 by Takaaki Naganoya

指定画像を任意の色で単色化し、指定色名をファイル名に反映させてファイル出力するAppleScriptです。

もとは、「色付き単色画像を作成する」AppleScriptに、

 ・choose colorによるユーザー選択色を反映
 ・choose colorで指定した色のざっくりとした色名検出

などの機能をつなぎ合わせたものです。

日本地図の白地図からカラーバリエーション画像を出力する際に作成しました。線が黒で書かれている白地図(白地図というのはそういうものですが)から、さまざまな色のバリエーションを作成。その際に、どのような色を指定したかをファイル名に反映させておいたほうが便利だったので、そのようにしてみました。

GPUImage.frameworkを利用しています。

–> GPUImage.framework (To ~/Library/Frameworks/)

色名推定のロジックもけっこうしっくりきていますが、明度も反映して、明るいものは「light-」、暗いものは「dark-」と出力させてもいいような気がします。ただし、「dark-orange」はBrownのことですし、ほかにも色名を別途振り直したほうがいいパターンもあるように思われます。

AppleScript名:色付き単色画像を作成する(自由色指定&色名推定)
— Created 2017-02-11 by Takaaki Naganoya
— Modified 2018-07-15 by Takaaki Naganoya
— 2017-2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "GPUImage" –https://github.com/BradLarson/GPUImage

property NSUUID : a reference to current application’s NSUUID
property NSColor : a reference to current application’s NSColor
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property NSBezierPath : a reference to current application’s NSBezierPath
property NSPNGFileType : a reference to current application’s NSPNGFileType
property GPUImagePicture : a reference to current application’s GPUImagePicture
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep

–Select Image File
set aFile to POSIX path of (choose file of type {"public.image"} with prompt "Select image")

–Select Color
set {rCol, gCol, bCol} to choose color

set fillColorR to makeNSColorFromRGBAval(rCol, gCol, bCol, 65535, 65535) of me
set fillColorRName to retColorDomainNameFromNSColor(fillColorR) of me –だいたいの色名称を計算

set imgRes to makeMonoColoredImage(aFile, fillColorR) of me
set fRes to retUUIDandKeyfilePath(aFile, fillColorRName, "png") of me
set bRes to saveNSImageAtPathAsPNG(imgRes, fRes) of me

— return "UUID_aKey.aEXT" full path
on retUUIDandKeyfilePath(aPath, aKey, aEXT)
  set aUUIDstr to ((NSUUID’s UUID()’s UUIDString()) as string) & "_" & aKey
  
set aPath to ((NSString’s stringWithString:aPath)’s stringByDeletingLastPathComponent()’s stringByAppendingPathComponent:aUUIDstr)’s stringByAppendingPathExtension:aEXT
  
return aPath
end retUUIDandKeyfilePath

on makeMonoColoredImage(aFile, NScolorObj)
  set aImage to NSImage’s alloc()’s initWithContentsOfFile:aFile
  
return makeColoredNSImageWithColor(aImage, NScolorObj) of me –色付き単色画像を作成する
end makeMonoColoredImage

on makeColoredNSImageWithColor(aImage, fillColor)
  set aSize to aImage’s |size|()
  
set aWidth to width of aSize
  
set aHeight to height of aSize
  
set newNSImage to makeNSImageWithFilledWithColor(aWidth, aHeight, fillColor)
  
set grayImage to filterWithNSImage(aImage, "GPUImageGrayscaleFilter") of me
  
set compImage to composeImageWithBlendFilter(grayImage, newNSImage, "GPUImageScreenBlendFilter") of me
  
return compImage
end makeColoredNSImageWithColor

on filterWithNSImage(aNSImage, filterName as string)
  set aClass to current application’s NSClassFromString(filterName)
  
set aImageFilter to aClass’s alloc()’s init()
  
set aProcImg to (aImageFilter’s imageByFilteringImage:aNSImage)
  
return aProcImg
end filterWithNSImage

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

–指定サイズの画像を作成し、指定色で塗ってNSImageで返す
on makeNSImageWithFilledWithColor(aWidth, aHeight, fillColor)
  –Imageの作成  
  
set curSize to current application’s NSMakeSize(aWidth, aHeight)
  
set anImage to NSImage’s alloc()’s initWithSize:curSize
  
  
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() –描画ここまで
  
  
–生成した画像のRaw画像を作成
  
set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep
  
  
set newImg to NSImage’s alloc()’s initWithSize:curSize
  
newImg’s addRepresentation:aRawimg
  
return newImg
end makeNSImageWithFilledWithColor

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

–NSColor(内容はRGBAカラー)からだいたいの色名を推測
on retColorDomainNameFromNSColor(aCol)
  set hueVal to aCol’s hueComponent()
  
set satVal to aCol’s saturationComponent()
  
set brightVal to aCol’s brightnessComponent()
  
  
if satVal ≤ 0.01 then set satVal to 0.0
  
  
set colName to ""
  
  
if satVal = 0.0 then
    if brightVal ≤ 0.2 then
      set colName to "black"
    else if (brightVal > 0.95) then
      set colName to "white"
    else
      set colName to "gray"
    end if
  else
    if hueVal ≤ (15.0 / 360) or hueVal ≥ (330 / 360) then
      set colName to "red"
    else if hueVal ≤ (45.0 / 360) then
      set colName to "orange"
    else if hueVal < (70.0 / 360) then
      set colName to "yellow"
    else if hueVal < (150.0 / 360) then
      set colName to "green"
    else if hueVal < (190.0 / 360) then
      set colName to "green(cyan)"
    else if (hueVal < 250.0 / 360.0) then
      set colName to "blue"
    else if (hueVal < 290.0 / 360.0) then
      set colName to "purple"
    else
      set colName to "red(magenta)"
    end if
  end if
  
  
return colName
end retColorDomainNameFromNSColor

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

★Click Here to Open This Script 

Posted in Color file Image | Tagged 10.11savvy 10.12savvy 10.13savvy NSBezierPath NSBitmapImageRep NSColor NSImage NSString NSUUID | Leave a comment

Post navigation

  • Older posts
  • Newer posts

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

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 13.6.5 AS系のバグ、一切直らず
  • CotEditorで2つの書類の行単位での差分検出
  • Apple純正マウス、キーボードのバッテリー残量取得
  • macOS 15, Sequoia
  • 初心者がつまづきやすい「log」コマンド
  • 指定のWordファイルをPDFに書き出す
  • Adobe AcrobatをAppleScriptから操作してPDF圧縮
  • メキシカンハットの描画
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • 与えられた文字列の1D Listのすべての順列組み合わせパターン文字列を返す v3(ベンチマーク用)
  • 2023年に書いた価値あるAppleScript
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AdobeがInDesign v19.4からPOSIX pathを採用
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • Cocoa Scripting Course 続刊計画
  • NaturalLanguage.frameworkでNLEmbeddingの処理が可能な言語をチェック
  • macOS 14.xでScript Menuの実行速度が大幅に下がるバグ
  • Numbersで選択範囲のセルの前後の空白を削除
  • AppleScriptによる並列処理

Tags

10.11savvy (1102) 10.12savvy (1243) 10.13savvy (1392) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (207) 13.0savvy (173) 14.0savvy (123) 15.0savvy (100) CotEditor (64) Finder (51) iTunes (19) Keynote (115) NSAlert (61) NSArray (51) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (53) NSDictionary (28) NSFileManager (23) NSFont (21) NSImage (41) NSJSONSerialization (21) NSMutableArray (63) NSMutableDictionary (22) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (119) NSURL (98) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (72) Pages (53) Safari (44) Script Editor (27) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

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

アーカイブ

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

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

メタ情報

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

Forum Posts

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

メタ情報

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