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

カテゴリー: list

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

Finder上で選択中のファイルをDMGに変換して圧縮 v2

Posted on 6月 6, 2019 by Takaaki Naganoya

Finder上で選択中のファイルをあらたに作ったDiskImageに入れてZip圧縮するAppleScriptです。

Script Menuに入れて実行することを前提にして作ってあります。

Google DriveなどのクラウドストレージにAppleScriptアプレットなどの実行ファイルをアップロードすると、バンドルが壊れたり、実行できなくなったりします。

そのため、仕方なくZip圧縮してアップロードしたりするわけですが、どうもZipの中身までGoogle Drive側が内容を展開して確認するらしく、ウィルスと疑われてZip圧縮した実行ファイルをダウンロードできないケースが見られます。

また、.dmgファイルに入れただけでもGoogle Driveが中身をスキャンして実行ファイルに警告を出すとのこと。一般的にはウィルスの拡散を防止する機能として好意的に受け止められるべきものですが、本当にプログラムを受け渡す必要がある場合には、こまった仕様です。

そこで、Diskimageに入れて、本来であればパスワードをつけてZip圧縮したいところですが、取り回しが悪くなるので、パスワードはつけないでアーカイブ化するようにしてみました。


▲Finder上で選択中のファイル(複数可)


▲本Scriptでdmg化してZip圧縮したもの


▲Zipアーカイブを展開してdiskimageファイルをマウントしたところ

本Scriptは、おおよそ自分で組んだ記憶がないのと、プログラムの構造が自分らしくないので、おそらくMacScripter.netあたりで拾ってきたScriptをそのまま使っていたものでしょう。それを一部修正してみました。オリジナルのScriptではFinder上で選択中のフォルダのみ処理するようになっていましたが、実際にはファイルをやりとりしたい(AppleScriptアプレットのケース多し)ので、ファイルをそのままdmg化できるように変更しました(単にフォルダを作成してコピーするだけですが)。

本ScriptはmacOS 10.15Beta1上では、macOS 10.15側にバグがあるため動作しません(POSIX pathへの変換程度でバグを作ってほしくないなー)。

AppleScript名:Finder上で選択中のファイルをDMGに変換して圧縮 v2
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/06/06
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

property NSUUID : a reference to current application’s NSUUID

property deleteV : true –DMG変換後に対象フォルダを削除しない(trueで削除)
property zipDmg : true –DMG作成後にZip圧縮する(trueで圧縮+DMG削除)

–Finder上の選択項目を取得、選択されていない場合には処理終了
tell application "Finder"
  set selList to selection as alias list
  
if selList = {} or selList = "" or selList = missing value then
    activate
    
display dialog "何も選択されていません。" buttons {"OK"} default button 1 with icon 1
    
return
  end if
end tell

–一時フォルダを作って選択中のアイテムをコピー
set aUUID to NSUUID’s UUID()’s UUIDString() as text

set aTmp to POSIX path of (path to desktop) –macOS 10.15 beta1ではおかしな結果が返ってくる
set tmpDir to aTmp & aUUID
do shell script "mkdir -p " & quoted form of tmpDir

set targFol to (POSIX file tmpDir) as alias

try
  tell application "Finder"
    duplicate selList to folder targFol
  end tell
on error
  display dialog "エラー:ファイルのコピー中にエラーが発生" buttons {"OK"} default button 1 with icon 1
  
return
end try

set aList to {targFol}

tell application "Finder"
  
  
set dmgList to {}
  
  
–選択中のアイテムを順次処理するループ
  
repeat with i in aList
    set the end of dmgList to makeDMGfromFolderAlias(i, "") of me –パスワードは付けない
    
    
–処理後のフォルダを削除する処理
    
if (deleteV as boolean) = true then
      deleteFolderItself(i) of me
    else
      –元フォルダを削除しない場合、元フォルダの名前を変更する
      
tell application "Finder"
        set aName to name of i
      end tell
      
      
set aName to aName & "_origFol"
      
      
tell application "Finder"
        set name of i to aName
      end tell
    end if
  end repeat
  
  
if zipDmg = true then
    repeat with i in dmgList
      set j to contents of i
      
      
set f1Path to quoted form of j –DMGファイルのPOSIX Path
      
set f2Path to quoted form of (j & ".zip") –ZipファイルのPOSIX Path
      
      
–タイムアウト時間は2時間
      
with timeout of 7200 seconds
        do shell script "/usr/bin/zip -r -j " & f2Path & " " & f1Path
        
do shell script "/bin/rm -f " & f1Path
      end timeout
      
    end repeat
  end if
end tell

–指定のフォルダ(alias)をDiskImageに変換する
on makeDMGfromFolderAlias(aaSel, aPassword)
  
  
set aPassword to aPassword as string
  
  
tell application "Finder"
    set fn to name of aaSel
  end tell
  
  
set aDir to (POSIX path of aaSel)
  
set aDir to quoted form of aDir
  
  
set fp2 to do shell script "dirname " & aDir
  
set fp2 to fp2 & "/"
  
  
set outPath to (fp2 & fn & ".dmg")
  
  
if aPassword is not equal to "" then
    –パスワードつきの場合
    
set aCMD to "printf ’" & aPassword & "’ | hdiutil create -encryption -srcfolder " & aDir & " " & (quoted form of outPath)
  else
    –パスワードなしの場合
    
set aCMD to "hdiutil create -srcfolder " & aDir & " " & (quoted form of outPath)
  end if
  
  
set fp3 to do shell script aCMD
  
  
return outPath
  
end makeDMGfromFolderAlias

–指定フォルダ内をすべて削除し、そのフォルダ自体も削除
on deleteFolderItself(aFol)
  set aU to (quoted form of POSIX path of aFol)
  
do shell script "rm -rf " & aU
end deleteFolderItself

★Click Here to Open This Script 

Posted in file list | Tagged 10.12savvy 10.13savvy 10.14savvy Finder NSUUID | Leave a comment

リストの差分を取得して、登場順序が変わっていても1D List同士の登場要素が同じかをチェック

Posted on 5月 27, 2019 by Takaaki Naganoya

2つの1D List(1次元配列)同士の全要素をチェックし、登場順序に変更があったとしても要素自体に差がないかどうかをチェックするAppleScriptです。

……ソートしてから比較すれば、もっと短くて済むような気もしないでもないですが、もし違った場合には何が足りなくて(minusitems)、何が余計なのか(additems)をレポートしてくれるので実用的だと思います。

AppleScript名:リストの差分を取得して、登場順序が変わっていても1D List同士の登場要素が同じかをチェック
— Created 2019-05-27 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set aList to {3, 2, 1, 7, 6, 4}
set bList to {1, 2, 3, 4, 6, 7}
set a1Res to checkAllItemsAreSame(aList, bList) of me
–> true (配列要素の登場順序が変わっていても要素はすべて同じ)

set aList to {3, 2, 1, 7, 6}
set bList to {1, 2, 3, 4, 6, 7}
set a2Res to checkAllItemsAreSame(aList, bList) of me
–> addItems:{4}, minusItems:{}}–配列要素に過不足があった

–1D List同士の全要素が(登場順序が変更になっていても)同じかどうかをチェック
on checkAllItemsAreSame(aList, bList)
  set dRes to getDiffBetweenLists(aList, bList) of me
  
set ddRes to (dRes is equal to {addItems:{}, minusItems:{}}) as boolean
  
if ddRes = true then
    return true
  else
    return dRes
  end if
end checkAllItemsAreSame

–1D List同士のdiffを検出
on getDiffBetweenLists(aArray as list, bArray as list)
  set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to (allSet’s allObjects()) as list
  
  
set aSet to current application’s NSMutableSet’s setWithArray:aArray
  
set bSet to current application’s NSMutableSet’s setWithArray:resArray
  
aSet’s intersectSet:bSet –積集合
  
set addRes to aSet’s allObjects() as list
  
  
set cSet to current application’s NSMutableSet’s setWithArray:bArray
  
cSet’s intersectSet:bSet –積集合
  
set minusRes to cSet’s allObjects() as list
  
  
return {addItems:minusRes, minusItems:addRes}
end getDiffBetweenLists

★Click Here to Open This Script 

Posted in list Record | Tagged 10.12savvy 10.13savvy 10.14savvy NSMutableSet NSSet | Leave a comment

Photosで選択中の写真をKeynoteの現在の書類の現在のスライド以降に配置 v2

Posted on 5月 27, 2019 by Takaaki Naganoya

Photosで選択中の写真をKeynoteで現在オープン中の書類の現在のスライド(ページ)以降に配置していくAppleScriptの改良版です。

作業の過程をiPhoneで写真撮影。撮影した写真を写真.app(Photos.app)経由でKeynote書類にまとめる作業を行なっていました。作業工程を時間こみで表示できないとわかりにくかったので、Keynoteの各スライドに時刻を入れるようにAppleScriptを書いておきました。

初版では写真.app(Photos)上の選択項目を一切ソートなどしなかったため、exifから取得した撮影日付で昇順ソートしています。


▲写真.app(Photos)上でKeynoteに配置したい写真を選択


▲あらかじめKeynote上でマスタースライド「画像(横長)」上のアイテムを編集しておくといいかも


▲AppleScriptによって写真.app上の写真をKeynote書類上に順次割り付け。タイトル部分にexifに記録されていた撮影時刻が入る


▲実行結果。写真.appから割り付けた写真は撮影日時でソートされている

AppleScript名:Photosで選択中の写真をKeynoteの現在の書類の現在のスライド以降に配置 v2
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/05/26
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
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
use mdLib : script "Metadata Lib" version "2.0.0" –https://www.macosxautomation.com/applescript/apps/Script_Libs.html#Metadata_Lib

property NSUUID : a reference to current application’s NSUUID
property NSString : a reference to current application’s NSString
property SMSForder : a reference to current application’s SMSForder
property NSFileManager : a reference to current application’s NSFileManager

tell application "Keynote"
  if (count every document) = 0 then return
end tell

–Photosで選択中の写真をすべて書き出してalias listを取得する
set aList to exportSelectedPhotoOnPhotos() of me
if aList = {} or aList = false then return

set aLen to length of aList

–書き出した画像の親フォルダを求めておく(あとで削除するため)
tell application "Finder"
  set parentFol to parent of (item 1 of aList)
end tell

–exifから撮影日時を取得して2D List化
set aaList to {}
repeat with i in aList
  set j to contents of i
  
set exifDate to readExifDateTimeOriginal(j) of me
  
set the end of aaList to {j, exifDate, (time string of exifDate)}
end repeat

–撮影日時で昇順ソート
set aaaList to sortList2DAscending(aaList, {2}) of me

tell application "Keynote"
  tell front document
    tell current slide
      set curNum to slide number –現在表示中のスライドの番号(ページ数)を取得する
    end tell
    
    
–Photosから取得した写真のアイテム数でループ
    
repeat with i from 1 to aLen
      copy (item i of aaaList) to {aPhoto, aDateObj, creTime}
      
      
set newSlide to make new slide at slide (curNum + i) with properties {base slide:master slide "画像(横長)"} –This item is localized!! Maybe a "Photo"
      
      
tell newSlide
        set object text of default title item to creTime
        
set file name of image 1 to aPhoto –place an image to image placeholder
      end tell
      
      
–配置画像を削除
      
tell application "Finder"
        delete aPhoto –配置した写真を削除
      end tell
    end repeat
  end tell
end tell

–あとしまつ
tell application "Finder"
  delete parentFol –画像のダウンロードフォルダを削除
end tell

–Photosで選択中のファイルをtmporaryフォルダに書き出してalias listで返す
on exportSelectedPhotoOnPhotos()
  set dtPath to (path to temporary items) as text
  
set aUUID to NSUUID’s UUID()’s UUIDString() as text
  
  
set dirPath to ((POSIX path of dtPath) & aUUID)
  
set fileManager to NSFileManager’s defaultManager()
  
set aRes to (fileManager’s createDirectoryAtPath:dirPath withIntermediateDirectories:true attributes:(missing value) |error|:(reference))
  
set dtPath to dtPath & aUUID
  
  
tell application "Photos"
    set a to selection
    
if a = {} then return {}
    
set aRes to (export a to file dtPath)
  end tell
  
  
tell application "Finder"
    tell folder dtPath
      set fList to (every file) as alias list
    end tell
  end tell
  
  
if fList = {} then return false
  
return fList
end exportSelectedPhotoOnPhotos

–指定JPEG画像のExif情報からDateTimeOriginalを取得してAS dateオブジェクトに変換して返す
on readExifDateTimeOriginal(aTargFileAlias)
  set theMetadata to readMetadataFrom(aTargFileAlias) of me
  
if theMetadata = false then return false
  
  
set keysList to theMetadata’s allKeys()
  
  
if "{Exif}" is not in (keysList as list) then return false
  
  
set exifDate to theMetadata’s valueForKeyPath:"{Exif}.DateTimeOriginal"
  
if exifDate = missing value then return false
  
  
set a to NSString’s stringWithString:exifDate
  
set {aDateStr, aTimeStr} to (a’s componentsSeparatedByString:" ") as list
  
set bDateStr to repChar(aDateStr, ":", "/") of me
  
set fullDate to date (bDateStr & " " & aTimeStr)
  
  
return fullDate
end readExifDateTimeOriginal

–指定のファイルからメタデータを取得する
on readMetadataFrom(imageFile)
  load framework
  
set {theRecord, theError} to SMSForder’s metadataFromImage:imageFile |error|:(reference)
  
if theRecord = missing value then — there was a problem, so extract the error description
    error false
  else
    return theRecord
  end if
end readMetadataFrom

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

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

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

–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
  
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to "compare:"
  end repeat
  
  
set resList to (SMSForder’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as {missing value, list}
  
  
return resList
end sort2DList

★Click Here to Open This Script 

Posted in Calendar exif file Image list | Tagged 10.12savvy 10.13savvy 10.14savvy Finder Keynote NSFileManager NSString NSUUID Photos | Leave a comment

Photosで選択中の写真をKeynoteの現在の書類の現在のスライド以降に配置

Posted on 5月 27, 2019 by Takaaki Naganoya

Photosで選択中の写真をKeynoteで現在オープン中の書類の現在のスライド(ページ)以降に配置していくAppleScriptです。

作業の過程をiPhoneで写真撮影。撮影した写真を写真.app(Photos.app)経由でKeynote書類にまとめる作業を行なっていました。作業工程を時間こみで表示できないとわかりにくかったので、Keynoteの各スライドに時刻を入れるようにAppleScriptを書いておきました(同じ作業が二度あるかは不明ですが、二度目からは明らかに時間の節約。つまり時間の貯金ができることになります)。

写真.app(Photos)上でKeynoteに配置したい写真を選択しておき、本Scriptを実行します。

Keynote書類上に新規スライドを追加し、撮影時刻と写真を配置していきます。

実行直後にPhotosで選択中の写真をファイルに書き出すため、若干待たされます。

# 複数のマシンでiCloudを介して写真を同期した場合に、写真.appのライブラリの写真の並び順は撮影日時どおりにならないようなので、明示的にソートしておく必要があるようです

ちなみに、写真の自作キーボードキットはこの後フットペダルにつなぎなおして、PPSSPP用の足踏みコントローラー化する予定です(「戦場の絆ポータブル」用)。

AppleScript名:Photosで選択中の写真をKeynoteの現在の書類の現在のスライド以降に配置
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/05/26
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
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
use mdLib : script "Metadata Lib" version "2.0.0" –https://www.macosxautomation.com/applescript/apps/Script_Libs.html#Metadata_Lib

property NSUUID : a reference to current application’s NSUUID
property NSString : a reference to current application’s NSString
property NSFileManager : a reference to current application’s NSFileManager

tell application "Keynote"
  if (count every document) = 0 then return
end tell

–Photosで選択中の写真をすべて書き出してalias listを取得する
set aList to exportSelectedPhotoOnPhotos() of me
if aList = {} or aList = false then return

set aLen to length of aList

–書き出した画像の親フォルダを求めておく(あとで削除するため)
tell application "Finder"
  set parentFol to parent of (item 1 of aList)
end tell

tell application "Keynote"
  tell front document
    tell current slide
      set curNum to slide number –現在表示中のスライドの番号(ページ数)を取得する
    end tell
    
    
–Photosから取得した写真のアイテム数でループ
    
repeat with i from 1 to aLen
      set aPhoto to contents of item i of aList
      
set newSlide to make new slide at slide (curNum + i) with properties {base slide:master slide "画像(横長)"} –This item is localized!! Maybe a "Photo"
      
set creTime to getCreationTime(aPhoto) of me
      
tell newSlide
        set object text of default title item to creTime
        
set file name of image 1 to aPhoto –place an image to image placeholder
      end tell
      
      
–配置画像を削除
      
tell application "Finder"
        delete aPhoto –配置した写真を削除
      end tell
    end repeat
  end tell
end tell

–あとしまつ
tell application "Finder"
  delete parentFol –画像のダウンロードフォルダを削除
end tell

–指定のaliasからExif情報の作成日の時刻情報を返す
on getCreationTime(anAlias)
  set exifDate to readExifDateTimeOriginal(anAlias) of me
  
return time string of exifDate
end getCreationTime

–Photosで選択中のファイルをtmporaryフォルダに書き出してalias listで返す
on exportSelectedPhotoOnPhotos()
  set dtPath to (path to temporary items) as text
  
set aUUID to NSUUID’s UUID()’s UUIDString() as text
  
  
set dirPath to ((POSIX path of dtPath) & aUUID)
  
set fileManager to NSFileManager’s defaultManager()
  
set aRes to (fileManager’s createDirectoryAtPath:dirPath withIntermediateDirectories:true attributes:(missing value) |error|:(reference))
  
set dtPath to dtPath & aUUID
  
  
tell application "Photos"
    set a to selection
    
if a = {} then return {}
    
set aRes to (export a to file dtPath)
  end tell
  
  
tell application "Finder"
    tell folder dtPath
      set fList to (every file) as alias list
    end tell
  end tell
  
  
if fList = {} then return false
  
return fList
end exportSelectedPhotoOnPhotos

–指定JPEG画像のExif情報からDateTimeOriginalを取得してAS dateオブジェクトに変換して返す
on readExifDateTimeOriginal(aTargFileAlias)
  set theMetadata to readMetadataFrom(aTargFileAlias) of me
  
if theMetadata = false then return false
  
  
set keysList to theMetadata’s allKeys()
  
  
if "{Exif}" is not in (keysList as list) then return false
  
  
set exifDate to theMetadata’s valueForKeyPath:"{Exif}.DateTimeOriginal"
  
if exifDate = missing value then return false
  
  
set a to NSString’s stringWithString:exifDate
  
set {aDateStr, aTimeStr} to (a’s componentsSeparatedByString:" ") as list
  
set bDateStr to repChar(aDateStr, ":", "/") of me
  
set fullDate to date (bDateStr & " " & aTimeStr)
  
  
return fullDate
end readExifDateTimeOriginal

–指定のファイルからメタデータを取得する
on readMetadataFrom(imageFile)
  load framework
  
set {theRecord, theError} to current application’s SMSForder’s metadataFromImage:imageFile |error|:(reference)
  
if theRecord = missing value then — there was a problem, so extract the error description
    error false
  else
    return theRecord
  end if
end readMetadataFrom

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

★Click Here to Open This Script 

Posted in Calendar exif file Image list | Tagged 10.12savvy 10.13savvy 10.14savvy Finder Keynote NSFileManager NSString NSUUID Photos | 1 Comment

Keynoteで表示中のスライド上の表を2つ、縦方向に連結する

Posted on 5月 21, 2019 by Takaaki Naganoya

Keynoteでオープン中の書類の表示中のスライド(ページ)上にある表を2つ選択して、縦方向に連結するAppleScriptです。

実行頻度から、横連結だけでいいかと思っていたのですが、結局縦連結のScriptも書いておきました。たぶん、こっち(縦連結)は(個人的には)使わないでしょう。

一定の実用性を確保するためには、各表のヘッダー行のラベルを見て、同じラベルのデータを同じ列に入れる必要があることでしょう。本Scriptの実装レベルだと、物理的にただ表をつなげるだけです。

また、ヘッダー部分の処理は一切行っていません。実用性を考えればヘッダー行やヘッダー列を無視して、データ部のみ連結するといった処理が必要になってくると思います。現状の実装では「(作った本人が)わかっているから別にそこまでしなくていい」という程度のお手軽実装です。


▲マージ対象の表


▲現在表示中のスライド(ページ)中に存在している表のタイトルが一覧表示される。座標位置をもとに上→下、左→右とソートした順で表示


▲複数項目を選択する場合にはCommandキーを押しながら選択


▲2つの表を縦方向にマージ(連結)。マージされたほうの表は削除

macOS 10.14.5+Keynote v9.0.2で作成および動作確認を行っています。macOS 10.14上ではBridgePlusを呼び出すためにScript Debugger上で実行するか、アプレット書き出しして実行する必要があります。または、アプレット書き出ししてスクリプトメニューから呼び出してもよいでしょう。

# 個人的には、めんどくさいのでmacOS 10.14環境ではSIP(System Integrity Protection)をオフにして使っています

macOS 10.13.x、macOS 10.12.xでは普通にスクリプトエディタなどから実行可能です。

AppleScript名:Keynoteで表示中のスライド上の表を2つ、縦方向に連結する.scpt
— Created 2019-05-21 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

tell application "Keynote"
  tell front document
    tell current slide
      set tCount to count every table
      
if tCount < 2 then
        display dialog "There is no tables to merge" buttons {"OK"} default button 1
        
return
      end if
      
      
set tList to every table
      
set tInfoList to {}
      
repeat with i in tList
        set {tPosX, tPosY} to position of i
        
set tName to name of i
        
set the end of tInfoList to {tName, tPosX, tPosY}
      end repeat
    end tell
  end tell
end tell

–表のY座標、X座標で昇順ソート(上→下、左→右の順で並べる)
set sortedList to sort2DList(tInfoList, {3, 2}, {true, true}) of me

–表リストから名前だけ抽出
set tmpTList to retSpecifiedItemFrom2DList({1}, sortedList) of me

–マージ対象のテーブルを名称で選択
set tRes to choose from list tmpTList with title "Vertial Merge Tables" with prompt "Select merge target two table names " & return & "(Sorted Up-> Down, Left->Right)" with multiple selections allowed
if tRes = false then
  display dialog "Canseled" buttons {"OK"} default button 1
  
return
end if

if length of tRes is not equal to 2 then
  display dialog "Select *two* tables" buttons {"OK"} default button 1
  
return
end if

–set mDirection to contents of (choose from list {"Vertival", "Horizontal"} with title "Select Merge Direction" without empty selection allowed)
set mDirection to "Vertival"

set f1Table to contents of item 1 of tRes –Left (Original)
set f2Table to contents of item 2 of tRes –Right (merged)

tell application "Keynote"
  tell front document
    tell current slide
      –マージ先の表のサイズを取得(幅、高さ)
      
tell table f1Table
        set f1Width to column count
        
set f1Height to row count
      end tell
      
      
–マージされるの表のサイズを取得(幅、高さ、データを2D Listで)
      
tell table f2Table
        set f2Width to column count
        
set f2Height to row count
        
set f2DatList to {}
        
repeat with i from 1 to f2Height
          tell row i
            set aRowDat to value of every cell
          end tell
          
set the end of f2DatList to aRowDat
        end repeat
      end tell
      
      
–マージ先の表のサイズを変更して新規追加したセルにデータを埋める
      
tell table f1Table
        set row count to row count + f2Height –表リサイズ
        
        
set rowCount to f1Height + 1
        
repeat with i in f2DatList
          set colCount to 1
          
          
tell row rowCount
            repeat with ii in i
              set jj to contents of ii
              
              
if jj is not equal to missing value then –空白セルを処理スキップ
                tell cell colCount
                  set value to jj
                end tell
              end if
              
              
set colCount to colCount + 1
            end repeat
          end tell
          
          
set rowCount to rowCount + 1
        end repeat
      end tell
      
      
delete table f2Table
    end tell
  end tell
end tell

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

–指定2Dリストから、各要素の指定アイテム目を取り出して(1D Listで)返す
on retSpecifiedItemFrom2DList(aList as list, bList as list)
  set newList to {}
  
repeat with i in aList
    repeat with ii in bList
      set j to contents of ii
      
set a to contents of (item i of j)
      
set the end of newList to a
    end repeat
  end repeat
  
return newList
end retSpecifiedItemFrom2DList

★Click Here to Open This Script 

Posted in list | Tagged 10.12savvy 10.13savvy 10.14savvy Keynote | Leave a comment

Keynoteで表示中のスライド上の表を2つ、横方向に連結する

Posted on 5月 21, 2019 by Takaaki Naganoya

Keynoteでオープン中の書類の表示中のスライド(ページ)上にある表を2つ選択して、横方向に連結するAppleScriptです。

Keynoteで資料を作っていて、あまりにこういう処理が多いのでScript化しました。縦方向に連結してもいいのですが(最初は連結方向を選択させかけた)、実際に扱っている表が横長のケースが(個人的に)多いので「横連結だけでいいや」ということに。


▲マージ対象の表


▲現在表示中のスライド(ページ)中に存在している表のタイトルが一覧表示される。座標位置をもとに上→下、左→右とソートした順で表示


▲複数項目を選択する場合にはCommandキーを押しながら選択


▲2つの表を横方向にマージ(連結)。マージされたほうの表は削除

macOS 10.14.5+Keynote v9.0.2で作成および動作確認を行っています。macOS 10.14上ではBridgePlusを呼び出すためにScript Debugger上で実行するか、アプレット書き出しして実行する必要があります。または、アプレット書き出ししてスクリプトメニューから呼び出してもよいでしょう。

# 個人的には、めんどくさいのでmacOS 10.14環境ではSIP(System Integrity Protection)をオフにして使っています

macOS 10.13.x、macOS 10.12.xでは普通にスクリプトエディタなどから実行可能です。

AppleScript名:Keynoteで表示中のスライド上の表を2つ、横方向に連結する.scpt
— Created 2019-05-21 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use Bplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

tell application "Keynote"
  tell front document
    tell current slide
      set tCount to count every table
      
if tCount < 2 then
        display dialog "There is no tables to merge" buttons {"OK"} default button 1
        
return
      end if
      
      
set tList to every table
      
set tInfoList to {}
      
repeat with i in tList
        set {tPosX, tPosY} to position of i
        
set tName to name of i
        
set the end of tInfoList to {tName, tPosX, tPosY}
      end repeat
    end tell
  end tell
end tell

–表のY座標、X座標で昇順ソート(上→下、左→右の順で並べる)
set sortedList to sort2DList(tInfoList, {3, 2}, {true, true}) of me

–表リストから名前だけ抽出
set tmpTList to retSpecifiedItemFrom2DList({1}, sortedList) of me

–マージ対象のテーブルを名称で選択
set tRes to choose from list tmpTList with title "Select Merge Tables" with prompt "Select merge target two table names " & return & "(Sorted Up-> Down, Left->Right)" with multiple selections allowed
if length of tRes is not equal to 2 then
  display dialog "Select *two* tables"
  
return
end if

–set mDirection to contents of (choose from list {"Vertival", "Horizontal"} with title "Select Merge Direction" without empty selection allowed)
set mDirection to "Horizontal"

set f1Table to contents of item 1 of tRes –Left (Original)
set f2Table to contents of item 2 of tRes –Right (merged)

tell application "Keynote"
  tell front document
    tell current slide
      –マージ先の表のサイズを取得(幅、高さ)
      
tell table f1Table
        set f1Width to column count
        
set f1Height to row count
      end tell
      
      
–マージされるの表のサイズを取得(幅、高さ、データを2D Listで)
      
tell table f2Table
        set f2Width to column count
        
set f2Height to row count
        
set f2DatList to {}
        
repeat with i from 1 to f2Height
          tell row i
            set aRowDat to value of every cell
          end tell
          
set the end of f2DatList to aRowDat
        end repeat
      end tell
      
      
–マージ先の表のサイズを変更して新規追加したセルにデータを埋める
      
tell table f1Table
        set column count to column count + f2Width –表リサイズ
        
        
set rowCount to 1
        
repeat with i in f2DatList
          set colCount to (f1Width + 1)
          
          
tell row rowCount
            repeat with ii in i
              set jj to contents of ii
              
              
if jj is not equal to missing value then –空白セルを処理スキップ
                tell cell colCount
                  set value to jj
                end tell
              end if
              
              
set colCount to colCount + 1
            end repeat
          end tell
          
          
set rowCount to rowCount + 1
        end repeat
      end tell
      
      
delete table f2Table
    end tell
  end tell
end tell

return f2DatList

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

–指定2Dリストから、各要素の指定アイテム目を取り出して(1D Listで)返す
on retSpecifiedItemFrom2DList(aList as list, bList as list)
  set newList to {}
  
repeat with i in aList
    repeat with ii in bList
      set j to contents of ii
      
set a to contents of (item i of j)
      
set the end of newList to a
    end repeat
  end repeat
  
return newList
end retSpecifiedItemFrom2DList

★Click Here to Open This Script 

Posted in list Sort | Tagged 10.12savvy 10.13savvy 10.14savvy Keynote | Leave a comment

Keynoteの各slideのtitleから目次のテキストを作成してNumbersの表を作成

Posted on 5月 20, 2019 by Takaaki Naganoya

現在オープン中の最前面のKeynote書類の各スライド(ページ)のタイトルを取得して、Numbersの新規書類上にページとタイトルの一覧表を作成するAppleScriptです。

こういうのが、一番オーソドックスで誰でも「そういうのがあったら楽なのに」と思わせるような用途でしょう。

Keynoteの書類を作成してページ数が増え、タイトル一覧をながめつつ削除したりアップデートしたりする対象を探したいような場合に、このような一覧表を作成させるとわかりやすくて便利です。

本Scriptは本当にありもののルーチンをつなげて最低限の処理を行わせたものですが、さらに手の込んだ処理を行うことも可能です。たとえば、別途Keynote書類をスライド(ページ)ごとに画像書き出ししておいて、Numbersのセル上にプレビュー画像として入れておくとか。あるいは、Keynote書類の各スライドのマスターアイテム名を見て処理を変えるとか。実にいろいろあります。

作成と動作確認はmacOS 10.14.5+Keynote 9.0.2で行っていますが、macOS 10.13/10.12でも動作するはずですしました。

AppleScript名:Keynoteの各slideのtitleから目次のテキストを作成してNumbersの表を作成
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/05/20
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

–Keynoteの各slideのタイトルを取得する
tell application "Keynote"
  tell document 1
    set aList to object text of default title item of every slide
  end tell
end tell

set aLen to (length of aList) + 1 –ヘッダー行の分を+1
set bLen to 2 –data width (columns)

–2D Listを作成する (Page, Title)
set newList to {}
set pCount to 1
repeat with i in aList
  set j to contents of i
  
set the end of newList to {pCount as string, j}
  
set pCount to pCount + 1
end repeat

–Numbersの書類を新規作成して、指定サイズの表を作成する
makeNewNumbersDocumentAndTable(aLen, bLen) of me

–作成した新規書類の表1に2D Listを入れる(ただし、100行分ぐらいを上限とする。それ以上は別途CSVを書き出してオープンさせたほうが圧倒的に高速)I
fillCurrentTable(newList) of me

on fillCurrentTable(aList)
  set aLen to length of aList
  
set aWidth to length of first item of aList
  
  
tell application "Numbers"
    tell front document
      tell active sheet
        tell table 1
          repeat with i from 1 to aLen
            tell row (i + 1)
              set aRowList to contents of item i of aList
              
repeat with ii from 1 to aWidth
                tell cell ii
                  set aTmpData to contents of item ii of aRowList
                  
ignoring application responses
                    set value to aTmpData
                  end ignoring
                end tell
              end repeat
            end tell
          end repeat
        end tell
      end tell
    end tell
  end tell
end fillCurrentTable

on makeNewNumbersDocumentAndTable(aHeight, aWidth)
  tell application "Numbers"
    make new document
    
    
tell front document
      tell active sheet
        delete every table
      end tell
    end tell
    
    
tell front document
      tell active sheet
        set tRes to make new table with properties {row count:aHeight, column count:aWidth}
        
return tRes
      end tell
    end tell
  end tell
end makeNewNumbersDocumentAndTable

★Click Here to Open This Script 

Posted in list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote Numbers | Leave a comment

2D Listの行列入れ替え(transpose)

Posted on 5月 16, 2019 by Takaaki Naganoya

2D List(2次元配列)の行列入れ替えを行うAppleScriptです。

本プログラムは前の(2018.1.31に消える前の)Blogに掲載していたものを動作検証を行いつつ再掲載したもので、そもそもはShane StanleyのBridgePlus AppleScript Libraryのドキュメントに掲載されているもの、ほぼそのままです。

BridgePlusの前身であるASObjCExras.frameworkのときにこの機能を見つけて、どうしてこの機能がこの仕様になっているのか、その当時は理解できていませんでした。

2次元配列の回転だけなら、単純にデータを(画像のように)回転させるだけの処理のはずですが(→ 時計まわりに90度回すサンプル)、そういうわけでもない。なんでこんな処理をShaneが書いたのか理解できず、当時は「なーんか使えないメソッドがついてんなー」ぐらいにしか思っていませんでした。

そして、出会ってしまったわけです。この機能がバリバリに必要なデータに。そして、深く理解しました。これはShaneが説明不足すぎです。そして、「致命的に必要な機能」だったので最初からついていたわけです。

ExcelでもNumbersでもGoogle Spreadsheetでも、1レコードといったら行ごとに配置されているのが普通です。プログラマーを10人集めて、2次元配列でそういうデータを表現しろと言われたら、世界中のどこのプログラマーでもだいたい10人とも行ごとにレコードを表現すると思います。

そんな中、1レコード=1行ではなく1レコード=1列とかいうデータがやってきて、途方に暮れたすえにNumbers上で「行と列を転置」機能を利用して縦横の入れ替えを行なって、ハッと気づきました。

 「これや……このためについとったんや」

調べてみたら、ビンゴ! まさに2D Listのtransposeのための機能がBridgePlusの、

SMSForder's colsToRowsIn:① |error|:②

だったわけです。

「プログラミングの身体性」ともいうべきものがあります。実体験をもとにするとデータやオブジェクトをどのように操作すべきなのかを深く理解でき、逆に実体験がともなっていないとまったく理解できないという話であり、これがまさにそれだったのでしょう(AppleScriptってプログラミングの身体性の塊のような気も、、、、一般のプログラマーが仕様だけ読んで組もうとして挫折した話をウンザリするほど聞くもので。実際にアプリケーションを動かしてみないと理解できないことが多すぎです)。

なので、こういう「息を飲むような非常識なデータ」を前に途方に暮れないかぎり、このメソッドの有用性は理解できないと思います(自分がそうだったので)。

AppleScript名:2D Listの行列入れ替え.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/05/16
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

set aList to {{"r0", "f1", "f2"}, {"r1", "f1r1", "f2r1"}, {"r2", "f1r2", "f2r2"}, {"r3", "f1r3", "f2r3"}}
set bList to transpose2DList(aList) of me
–> {{"r0", "r1", "r2", "r3"}, {"f1", "f1r1", "f1r2", "f1r3"}, {"f2", "f2r1", "f2r2", "f2r3"}}

on transpose2DList(aList as list)
  load framework
  
return (ASify from (current application’s SMSForder’s colsToRowsIn:aList |error|:(missing value)))
end transpose2DList

★Click Here to Open This Script 

Posted in list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Excel Numbers | Leave a comment

Mail.appで未読メール数を取得する

Posted on 5月 14, 2019 by Takaaki Naganoya

Mail.appで未読メールを取得するAppleScriptです。

まず、「未読メール」とは何かという話があります。未読メールとは、「まだ読んでいないメール」のことです。つまり、すべてのメッセージに未読/既読のフラグが用意されています。

極論すれば、すべてのメッセージの未読/既読状態を調べる必要があるわけですが、さすがにそれだと実用性がいまひとつなので、メールフォルダごとに未読メッセージのカウントが求められるようになっています。

一般的に「未読メール」といった場合、サブフォルダに仕分けしたメールの未読件数ではなく、受信メールボックス(INBOX)に入っている未読メールをカウントすることになることでしょう。

ただし、Mail.appには複数のメールアカウントを登録できるようになっているため、受信メールボックスのうちそれぞれのアカウントに該当するものが別々に返ってくることになります。

Apple純正のアプリケーションの多くはAppleScriptのオブジェクト名までローカライズされている(過剰ローカライズ)ことが多いのですが、Mail.appについては受信ボックス(=受信トレイ)は「INBOX」となっており、その他のボックスについても(ゴミ箱とか)ローカライズされていません。

画面上の表記 AppleScript上で指定する場合の名称
受信 INBOX
VIP —-
フラグ付き —-
下書き Drafts
送信済み Sent Messages
迷惑メール Junk
ゴミ箱 Deleted Messages
アーカイブ Archive
AppleScript名:メールアカウント名の一覧を取得
tell application "Mail"
  set nameList to name of every account
end tell
–> {"iCloud", "maro@XXXXXXXX"}

★Click Here to Open This Script 

AppleScript名:各アカウントのINBOXフォルダの未読メールを取得する
tell application "Mail"
  set tmpCount to unread count of mailbox "INBOX" of every account
end tell
–> {0, 0}–メールアカウントの数だけ配列要素が返ってくる

★Click Here to Open This Script 

AppleScript名:すべてのINBOXの未読メール数を合計して返す
set aCount to countAllUnreadMessages()
–> 0

on countAllUnreadMessages()
  tell application "Mail"
    set aCount to count every account
    
    
set totalUnreadCount to 0
    
repeat with i from 1 to aCount
      set tmpCount to unread count of mailbox "INBOX" of account i
      
set totalUnreadCount to totalUnreadCount + tmpCount
    end repeat
  end tell
  
  
return totalUnreadCount
end countAllUnreadMessages

★Click Here to Open This Script 

Posted in list | Tagged 10.12savvy 10.13savvy 10.14savvy Mail | Leave a comment

各種GUI要素なしでSafari上に新規ウィンドウ表示

Posted on 4月 29, 2019 by Takaaki Naganoya

Safari上で操作ボタンなどのGUI要素を表示しないで新規ウィンドウ表示するAppleScriptです。

1つのウィンドウを表示するのはすぐにできましたが、複数表示が大変でした(ーー; 結局、適宜delayコマンドで時間待ちをする必要があったのでした。やれやれー。

現時点で用途はまったく不明なのですが、いつか必要になることもあるでしょう(そういうの多いな!)。「resizable=no」という指定をしているのに、ウィンドウがリサイズできるあたりはご愛嬌。

ちなみに、Safariのdocumentが1つ以上存在することを前提条件としていますが、そこは省略して明示していません(初心者がひっかかりがちな「不明確な前提条件」なのですが本説明をもってかえさせていただきます)。

Twitter上でロシアのMacユーザーが「だれかAppleScriptについて教えてくれー」と言っていたので、「Google翻訳の範囲でなら(込み入った話でなければ)いいぞ」と返信したら、マンツーマンでやりとり。

初のロシア人とのチャットです。

本ScriptのおおもとになったAppleScriptをAlfred.appを使ってキーボードショートカットで呼び出していたそうで、1アクションから1つのサイトをオープンするだけなのが不満で、複数のサイト(URL)をオープンするように変更したかったとのこと。

Google翻訳を使ってコミュニケーションしてみて、いろいろ理解しました。

(1)ロシア人、とっても普通

(2)話した相手がプログラミングわからない人だったので、いろいろ追加で話をされたが、プログラマーが一番嫌がる内容(最初からゴール地点が設定されていない)になってきたので「ここから先は仕事としてならやるが、ギャラなしだったらやらない」と明言して打ち切り

(3)Google翻訳を通じて「ロシア語に翻訳できない表現」がいろいろあって焦る。おそらく、英語ほどには日本語との間の翻訳の用例が多く蓄積されておらず、翻訳できなかったものと想像。一応、日本語→ロシア語に翻訳してから、その文章を再度日本語に再翻訳してチェック。トンでもない表現に翻訳されて驚愕するも、何例か日本語の表現を変えてリトライ

あとから振り返って考えると、「日本語からロシア語に翻訳するより、英語からロシア語に翻訳した方がよかった」、「ダスビダーニャ(До свидания)って挨拶は知っていたのに使えなかったよ、ハラショー」といったところでしょうか。

あとは、固定でプログラム中にURLのデータを入れておかないで、外部ファイル……たとえばNumbers書類上のデータであるとか、DragThingのURLランチャーに登録してある現在選択中のタブからURLを取得してオープンするとかいった処理が考えられると「お、頑張ったね」というレベルでしょうか。

AppleScript名:各種GUI要素なしでSafari上に新規ウィンドウ表示
set aURLstr to "http://piyocast.com/as"

tell application "Safari"
  tell front document
    set jsStr to "open(’" & aURLstr & "’, ’test’,’scrollbars=no,resizable=no,status=no,location=no," & "toolbar=no,menubar=no,width=1024,height=720,left=0,top=0’);"
    
do JavaScript jsStr
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:各種GUI要素なしでSafari上に新規ウィンドウを複数表示
set aURLarray to {"http://piyocast.com/as", "http://www.apple.com", "http://www.microsoft.com"}

repeat with i in aURLarray
  set j to contents of i
  
openNewWindowWithoutGUIElements(j) of me
  
delay 3
end repeat

on openNewWindowWithoutGUIElements(aURLstr)
  set aNum to random number from 1 to 999
  
tell application "Safari"
    tell front document
      set jsStr to ("open(’" & aURLstr & "’, ’test" & aNum as string) & "’,’scrollbars=no,resizable=no,status=no,location=no," & "toolbar=no,menubar=no,width=1024,height=720,left=0,top=0’);"
      
do JavaScript jsStr
    end tell
  end tell
end openNewWindowWithoutGUIElements

★Click Here to Open This Script 

Posted in JavaScript list URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Safari | Leave a comment

RectangleBinPackを用いて2D Bin Packを解く

Posted on 4月 23, 2019 by Takaaki Naganoya

オープンソースの「RectangleBinPack」を用いて2D Bin Packagingを解き、Keynote上のshapeオブジェクトを指定矩形内に詰め込むAppleScriptです。

–> Download Script bundle with RectangleBinPack in its bundle

# This AppleScript requires RectangleBinPack executable in its bundle. So, download the whole AppleScript bundle archive from the link above (↑)

オープン中のKeynote書類の表示中のスライド(ページ)上にある矩形オブジェクト(Shape)を指定の矩形エリア内に2D Packingします。

github上で調査してみたところ、2D Bin Packのプログラムの多くはCないしC++で記述されており(JavaScriptも多いですね)、コンパイルしてAppleScriptのバンドル内に入れて呼び出せます。

ただし、それらの多くがゲーム開発用のものらしく、オブジェクトの回転をサポートしていたり(実用性を考えると回転してほしくない)、面積の大きな順に渡しても無視したり(優先順位をサポートしない)と、実際のGUIアプリケーション上のオブジェクトの整列には向いていないものがほとんどです。


▲Before Packing


▲AFter Packing

唯一、タグクラウドの画像を作りたい場合に本プログラムは向いていると思います。とくに、Keynoteのスライド上にタグクラウドっぽいページを作って、発表内容を示すとかいうのは実用性もありそうです。


▲本Scriptを文字アイテム処理用に書き換えて2D Bin Packした処理結果


▲本ScriptをAdobe Illustrator CC 2018用に書き換えて2D Bin Packした処理結果

AppleScript名:rectBinPack v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/23
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

–Packaging Target Area
set binSizeX to 600
set binSizeY to 500

set {tList, a0List} to retRectsFromKeynote() of me
set aList to sortList2DDecending(a0List, {2, 4, 3}) of me –Sorting key is Width(main) and Area(sub) and Height(sub)
–> {{2, 340, 243, 82620}, {3, 340, 73, 24820}, {8, 340, 73, 24820}, {1, 155, 240, 37200}, {4, 147, 125, 18375}, {5, 147, 125, 18375}, {6, 147, 125, 18375}, {7, 147, 125, 18375}}

set aRes to twoDBinPacking(binSizeX, binSizeY, aList) of me
if aRes = false then return
–> {{myPos:{0, 0}, myID:1}, {myPos:{0, 340}, myID:2}, {myPos:{243, 0}, myID:3}, {myPos:{316, 0}, myID:4}, {myPos:{340, 240}, myID:5}, {myPos:{465, 240}, myID:6}, {myPos:{590, 0}, myID:7}, {myPos:{590, 125}, myID:8}}

tell application "Keynote"
  tell front document
    tell current slide
      repeat with i in aRes
        set {posX, posY} to myPos of i
        
set itemIndex to myID of i
        
set aDeg to myDegree of i
        
        
set anObjID to item 1 of (item itemIndex of aList)
        
        
set rotation of shape anObjID to aDeg
        
set position of shape anObjID to {posX, posY}
        
      end repeat
    end tell
  end tell
end tell

on twoDBinPacking(binSizeX as integer, binSizeY as integer, boxList as list)
  set aParamList to {binSizeX, binSizeY}
  
repeat with i in boxList
    copy i to {tmpID, tmpX, tmpY, tmpArea}
    
set aParamList to aParamList & tmpX
    
set aParamList to aParamList & tmpY
  end repeat
  
  
set aParam to retDelimitedText(aParamList, " ") of me
  
–> "800 800 340 243 340 73 340 73 155 240 147 125 147 125 147 125 147 125"
  
  
–Parameters for result parsing
  
set s1Str to "Packed to (x,y)=("
  
set s2Str to ")"
  
set s3Str to ","
  
  
–https://github.com/juj/RectangleBinPack
  
set aPath to POSIX path of (path to resource "BinPackTest") –cause error if "BinPackTest" is not present in this script bundle
  
try
    set aRes to do shell script quoted form of aPath & " " & aParam
  on error
    return false
  end try
  
  
if aRes does not end with "Done. All rectangles packed." then return false
  
  
set aList to paragraphs of aRes
  
  
set bList to {}
  
set aCount to 1
  
repeat with i in aList
    set j to contents of i
    
if j begins with "Packing rectangle of size " and j does not contain "Failed!" then
      set xyRes to pickUpFromToStrAndParse(j, s1Str, s2Str, s3Str) of me
      
      
–RectangleBinPackがオブジェクトの回転をサポートしているため、その対処
      
if xyRes is not equal to false then
        set s11Str to "(w,h)=("
        
set s12Str to ")"
        
set s13Str to ","
        
        
set whRes to pickUpFromToStrAndParse(j, s11Str, s12Str, s13Str) of me
        
set tmpBox to item aCount of boxList
        
copy tmpBox to {tmpID, tmpX, tmpY, tmpArea}
        
        
if whRes = {tmpX, tmpY} then
          set aDeg to 0
        else if whRes = {tmpY, tmpX} then
          set aDeg to 90
        else
          error
        end if
        
        
set the end of bList to {myPos:xyRes, myID:aCount, myDegree:aDeg}
      end if
      
set aCount to aCount + 1
    end if
  end repeat
  
  
return bList
end twoDBinPacking

on pickUpFromToStrAndParse(aStr as string, s1Str as string, s2Str as string, s3Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
set {x, y} to parseByDelim(cStr, s3Str) of me
  
  
return {x as integer, y as integer}
end pickUpFromToStrAndParse

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

–リストを指定デリミタでテキスト化
on retDelimitedText(aList, aNewDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aNewDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retDelimitedText

on retRectsFromKeynote()
  tell application "Keynote"
    tell front document
      tell current slide
        set tList to every shape
        
set bList to {}
        
set iCount to 1
        
        
repeat with i in tList
          set aWidth to width of i
          
set aHeight to height of i
          
set {xPos, yPos} to position of i
          
set anArea to aWidth * aHeight
          
          
set the end of bList to {iCount, aWidth, aHeight, anArea}
          
set iCount to iCount + 1
        end repeat
        
        
return {tList, bList}
      end tell
    end tell
  end tell
end retRectsFromKeynote

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

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

–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 {missing value, list}
  
  
return resList
end sort2DList

★Click Here to Open This Script 

Posted in 2D Bin Packing list Record Sort | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote | 1 Comment

packit4meを利用して3D Bin Packingを解く

Posted on 4月 20, 2019 by Takaaki Naganoya

指定の広さの空間(Bin)に任意のサイズのブロックの組み合わせを最適化して詰め込むPackingの問題を解くAppleScriptです。

→ 別途、2D Bin PackingのAppleScriptを掲載しています「RectangleBinPackを用いて2D Bin Packを解く」

身の回りのさまざまな用途で利用されている2D/3D Bin Packing。ところが、実際に使ってみたいと思っても、使い勝手のよいプログラムが見当たりません。Cocoa Frameworkになっていて、NSRectをリストで渡すと結果を返してくれるようなものが個人的には理想的ですが、そういう仕様のものはほぼありません(完全にないわけではないものの、使い物にならない、、、)。

そこで、一応自分でも2D Bin Packing処理をAppleScriptで書いたものの、「ぴよまるソフトウェア」内で相談したところ外部公開はしにくい状況。

そうはいっても、2D Bin Packingを利用したあんな用途やこんな用途が山のようにあるので、外部のプログラムを呼び出してみるのがよいだろうかと(ふたたび)考え出したときに、まさかのREST APIで2D/3D Bin Packingの機能を提供しているpackit4meを発見(よく見つかったな)。

Web APIを呼び出して、3D Bin Packingを計算します。よくあるREST APIなので、プログラミングではなく「作業」のレベルで対処できます。

で、3D Bin Packingはいいものの、本命の2D Bin Packingを計算。

Keynote上のオブジェクトから情報を取得して….

packit4meで2D Bin Packを解かせてみると、Web上の3Dプレビュー(↑)はともかく、JSON(↓)で返してくる値が割とむちゃくちゃ。

[{"size": "40 x 30","id": "0","size_1": 40,"size_2": 30,"weight_limit": 3,"curr_weight": 3,"item_count": 3,"items": [{"id": "2","orig_size": "17 x 12","sp_size": "17 x 12","size_1": 17,"size_2": 12,"sp_size_1": 17,"sp_size_2": 12,"x_origin_in_bin": -11.5,"y_origin_in_bin": -9,"weight": 1,"constraints": 0},{"id": "1","orig_size": "7 x 12","sp_size": "7 x 12","size_1": 7,"size_2": 12,"sp_size_1": 7,"sp_size_2": 12,"x_origin_in_bin": 0.5,"y_origin_in_bin": -9,"weight": 1,"constraints": 0},{"id": "3","orig_size": "17 x 3","sp_size": "17 x 3","size_1": 17,"size_2": 3,"sp_size_1": 17,"sp_size_2": 3,"x_origin_in_bin": -11.5,"y_origin_in_bin": -1.5,"weight": 1,"constraints": 0}]}]

座標値にマイナスの値が含まれているなどうまく動いていない印象を受けます(制約条件が違うんだろか?)。

少なくとも、作者は2D Bin PackのJSON出力は検証していないのではないでしょうか、、、、残念!

AppleScript名:POST method REST API_packit4me
— Created 2019-04-20 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

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

set aBinPack to "bins=0:50:5x5x5&items=0:0:0:1x2x3,0:0:0:1x2x3,0:0:0:1x2x3&binId=0"

set aRes to binPackByPackIt4me(aBinPack) of me
–> {size_1:5, size_2:5, size_3:5, |id|:"0", weight_limit:50, curr_weight:0, |size|:"5 x 5 x 5", item_count:3, |items|:{{|id|:"0", sp_size_3:3, x_origin_in_bin:-2, orig_size:"1 x 2 x 3", weight:0, sp_size:"1 x 2 x 3", y_origin_in_bin:-1.5, constraints:0, size_3:3, sp_size_1:1, z_origin_in_bin:1, size_2:2, sp_size_2:2, size_1:1}, {|id|:"0", sp_size_3:3, x_origin_in_bin:-1, orig_size:"1 x 2 x 3", weight:0, sp_size:"1 x 2 x 3", y_origin_in_bin:-1.5, constraints:0, size_3:3, sp_size_1:1, z_origin_in_bin:1, size_2:2, sp_size_2:2, size_1:1}, {|id|:"0", sp_size_3:3, x_origin_in_bin:-2, orig_size:"1 x 2 x 3", weight:0, sp_size:"1 x 2 x 3", y_origin_in_bin:0.5, constraints:0, size_3:3, sp_size_1:1, z_origin_in_bin:1, size_2:2, sp_size_2:2, size_1:1}}}

on binPackByPackIt4me(aBinPack as string)
  set tmpData to (do shell script "curl -X POST -H \"Content-Type: application/x-www-form-urlencoded\" -d \"" & aBinPack & "\" http://www.packit4me.com/api/call/raw")
  
set jsonString to NSString’s stringWithString:tmpData
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
set aRec to aJsonDict as record
  
return aRec
end binPackByPackIt4me

★Click Here to Open This Script 

Posted in 2D Bin Packing list Record REST API | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSString NSURL NSUTF8StringEncoding | Leave a comment

Numbersで指定の2つの書類のデータのdiffを取る

Posted on 4月 19, 2019 by Takaaki Naganoya

指定の2つのNumbers書類(の中の現在表示中のシートのTable 1)同士のdiffを取るAppleScriptです。

# 書類内のシート内のどの表を処理するか、という階層化された対象選択を行うのにNSOutlineViewを用いたアラートダイアログを作っておきたい気持ちでいっぱいです

バージョン違いの書類間の差分を検出してレポートします。差分の評価は行単位で行なっており、同じデータでもカラムの順番を変えてあったりすると「別物」として検出します。

ただし、Numbersから2次元配列としてデータを抽出する際にすべてAppleScriptで処理するように書き換えた(macOS 10.14対策)ルーチンを使用しているので、大規模データの処理を行わせると(データ取得処理部分は)遅くなる可能性があります。

diffの計算部分はCocoaの機能に依存した(甘えまくった)処理を行なっているため、データが大きくてもそれほど遅くなりません。

612行の旧データと610行の新データをそれぞれ取得して差分を計算するのに、開発環境でだいたい3.5秒ぐらいです。同じ環境でBridgePlusを用いて1D List–> 2D List変換を行うバージョンを試してみたら、0.83秒ぐらいでした。

AppleScript名:Numbersで指定の2つの書類のデータのdiffを取る.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/19
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

tell application "Numbers"
  set dList to name of every document
  
set oldDoc to contents of first item of (choose from list dList with prompt "古いデータを選択してください")
  
set newDoc to contents of first item of (choose from list dList with prompt "新しいデータを選択してください")
end tell

set oldData to get2DListFromADoc(oldDoc) of me
set newData to get2DListFromADoc(newDoc) of me

–List同士のDiffを計算する
set dRes to getDiffBetweenLists(oldData, newData) of me
–> {addItems:{{"キャッツアイ恵庭", 42.87588548, 141.5834606, "北海道 恵庭市 住吉町 2-9-1"}}, minusItems:{{"セガワールド白河", 37.11931521, 140.1944139, "福島県 白河市 新高山 1-1 メガステージ白河内"}, {"プレイアイシー", 35.3721071, 139.272272, "神奈川県 秦野市 南矢名 1-15-1"}, {"駅前スタジアムIII", 33.8395736, 132.7521903, "愛媛県 松山市 大手町 2-4-1"}}}

on get2DListFromADoc(aDocName)
  tell application "Numbers"
    tell document aDocName
      tell active sheet
        set theTable to table 1
        
        
tell theTable
          set selection range to cell range
          
          
set hcCount to header column count
          
set hrCount to header row count
          
set frCount to footer row count
          
          
set cCount to column count
          
set rCount to row count
          
          
set outList to {}
          
          
repeat with i from (hrCount + 1) to rCount
            tell row i
              set tmpList to value of cells (hcCount + 1) thru cCount
              
set the end of outList to tmpList
            end tell
          end repeat
        end tell
        
        
return outList
        
      end tell
    end tell
  end tell
end get2DListFromADoc

on getDiffBetweenLists(aArray as list, bArray as list)
  set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to (allSet’s allObjects()) as list
  
  
set aSet to current application’s NSMutableSet’s setWithArray:aArray
  
set bSet to current application’s NSMutableSet’s setWithArray:resArray
  
aSet’s intersectSet:bSet –積集合
  
set addRes to aSet’s allObjects() as list
  
  
set cSet to current application’s NSMutableSet’s setWithArray:bArray
  
cSet’s intersectSet:bSet –積集合
  
set minusRes to cSet’s allObjects() as list
  
  
return {addItems:minusRes, minusItems:addRes}
end getDiffBetweenLists

★Click Here to Open This Script 

Posted in list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSMutableSet NSSet Numbers | Leave a comment

レコードのリストを複数Keyでソート

Posted on 4月 19, 2019 by Takaaki Naganoya

リストに入れたレコードを複数キー、キーごとのソート方向(ascending/descending)指定でソートするAppleScriptです。

ソート対象のラベルはサンプルのように階層構造ごと指定できます。キーとして列挙するラベルは、最初のものが主キーで、2番目以降はサブキーです。

AppleScript名:レコードのリストを複数Keyでソート.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/19
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

set aRecList to {{aName:"piyoko", aVal:10, bVal:{x:3, y:1}}, {aName:"piyomaru", aVal:20, bVal:{x:5, y:2}}, {aName:"piyoo", aVal:20, bVal:{x:4, y:5}}, {aName:"piyozo", aVal:10, bVal:{x:10, y:9}}}

set bList to sortRecListByLabel(aRecList, {"aVal", "bVal.x"}, {true, false}) of me
–> {{aName:"piyozo", aVal:10, bVal:{x:10, y:9}}, {aName:"piyoko", aVal:10, bVal:{x:3, y:1}}, {aName:"piyomaru", aVal:20, bVal:{x:5, y:2}}, {aName:"piyoo", aVal:20, bVal:{x:4, y:5}}}

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList as list, aLabelStr as list, ascendF as list)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
  
set aCount to length of aLabelStr
  
set sortDescArray to current application’s NSMutableArray’s new()
  
repeat with i from 1 to aCount
    set aLabel to (item i of aLabelStr)
    
set aKey to (item i of ascendF)
    
set sortDesc to (current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabel ascending:aKey)
    (
sortDescArray’s addObject:sortDesc)
  end repeat
  
  
return (aArray’s sortedArrayUsingDescriptors:sortDescArray) as list
end sortRecListByLabel

★Click Here to Open This Script 

Posted in list Record Sort | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSMutableArray NSSortDescriptor | Leave a comment

Keynote上で選択中のオブジェクトのRectangleを合成

Posted on 4月 17, 2019 by Takaaki Naganoya

Keynoteでオープン中の書類の現在表示中の(選択中の)スライド(ページ)上のshapeオブジェクトの矩形領域をすべて合成したRectangleのshapeオブジェクトを作成するAppleScriptです。

本来はほかの動作を行うプログラムの試作品なのですが、いまのところNSRectの合成を行うのが目的になっています。

PlaneなAppleScriptとCocoaの機能の両方を組み合わせないと実現できない機能でもあり、もうひと押しですごい処理ができそうな気がしないでもありません。

Keynote v9.xであらたにAppleScript用語辞書に記載された「selection」はまだfront documentやcurrent slideのレベルでしか動作しておらず、slide上で選択中のiWork itemや各Object中のobject textの選択部分を取得できたりはしないので注意が必要です。


▲実行前


▲実行後

AppleScript名:Keynote上で選択中のオブジェクトのRectangleを合成
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/17
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property totalRect : missing value

tell application "Keynote"
  tell front document
    tell current slide
      –SelectionがまだKeynoteでうまく働いていないので、そのかわり
      
set aaList to every iWork item
      
set aList to {}
      
repeat with i in aaList
        if (class of i) is in {shape} then
          set the end of aList to contents of i
        end if
      end repeat
      
      
–最初のアイテムを取り出す
      
set aFirst to contents of first item of aList
      
set {x1Pos, y1Pos} to position of aFirst
      
set aHeight to height of aFirst
      
set aWidth to width of aFirst
      
set my totalRect to {origin:{x:x1Pos, y:y1Pos}, |size|:{|width|:aWidth, |height|:aHeight}}
      
      
–残りのアイテムをNSRectに変換しつつ加算      
      
set aList to rest of aList
      
      
repeat with i in aList
        set aProp to properties of i
        
set aHeight to height of aProp
        
set aWidth to width of aProp
        
set anArea to aHeight * aWidth
        
set {x2Pos, y2Pos} to position of i
        
        
set tmpRect to {origin:{x:x2Pos, y:y2Pos}, |size|:{|width|:aWidth, |height|:aHeight}}
        
calcUnionRect(tmpRect) of me –Rectangleの加算を行う        
      end repeat
      
      
–Rectangleを合成した大きさと位置でshapeを新規作成
      
set tRect to (totalRect as record)
      
set newProp to {position:{(x of origin of tRect), (y of origin of tRect)}, width:(|width| of |size| of tRect), height:(|height| of |size| of tRect)}
      
set newShape to make new shape with properties newProp
      
set opacity of newShape to 30
    end tell
    
  end tell
end tell

on calcUnionRect(addRect)
  set totalRect to current application’s NSUnionRect(totalRect, addRect)
end calcUnionRect

★Click Here to Open This Script 

Posted in list Record | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote NSRect | Leave a comment

指定フォルダ内のファイルのうち、指定UTIに該当するものをすべて取得してフルパスを返す

Posted on 4月 13, 2019 by Takaaki Naganoya

指定フォルダ内のファイルのうち、指定のUTIに該当するものをすべて取得してフルパス(file/POSIX)で返すAppleScriptです。

指定フォルダの直下のみを走査し、サブフォルダ内は走査しません。調べてみるとUTIでファイルを絞り込む機能は存在していないようなので(見落としているだけ?)、すべてファイルを取得してからループでUTIを調べつつ該当するかどうかチェックしています。

書けば書くほど「それってSpotlightでよくね?」という気がしますが、確実に取得したい(Spotlightインデックスが破損していたり、サーバー上のファイルではSpotlightが効かない場合もある)場合に使うとよいでしょうか。

AppleScript名:指定フォルダ内のファイルのうち、指定UTIに該当するものをすべて取得してフルパスを返す
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/13
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSPredicate : a reference to current application’s NSPredicate
property NSFileManager : a reference to current application’s NSFileManager
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles

set aUTI to "com.adobe.pdf"
set libPath to ((path to documents folder) as string)
set posixLibPath to POSIX path of libPath

set f1List to getFilepathListByUTI(posixLibPath, aUTI, "file") of me
–> {file "Cherry:Users:me:Documents:0718kenpo.pdf", file "Cherry:Users:me:Documents:2013-09Rekihaku.pdf", file "Cherry:Users:maro:Documents:airserver.pdf"}

set f2List to getFilepathListByUTI(posixLibPath, aUTI, "POSIX") of me
–> {"/Users/me/Documents/0718kenpo.pdf", "/Users/me/Documents/2013-09Rekihaku.pdf", "/Users/me/Documents/airserver.pdf"}

on getFilepathListByUTI(aFolPOSIX, aUTI as string, aFileType as string)
  script spdFile
    property urlList : {}
  end script
  
  
if aFileType is not in {"file", "POSIX"} then return {}
  
  
set aFM to NSFileManager’s defaultManager()
  
set aFolExt to (aFM’s fileExistsAtPath:aFolPOSIX isDirectory:true) as boolean
  
if aFolExt = false then return {} –フォルダ自体が存在しなければヌルリストを返す
  
  
set aURL to |NSURL|’s fileURLWithPath:aFolPOSIX
  
set theOptions to ((current application’s NSDirectoryEnumerationSkipsPackageDescendants) as integer) + ((current application’s NSDirectoryEnumerationSkipsHiddenFiles) as integer)
  
set urlArray to (aFM’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:theOptions |error|:(missing value))
  
if urlArray = missing value then return {}
  
  
set (urlList of spdFile) to urlArray as list
  
set newList to {}
  
  
repeat with i in (urlList of spdFile)
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, aUTI)
    
    
if utiRes is not equal to {} then
      if aFileType = "POSIX" then
        set the end of newList to j
      else if aFileType = "file" then
        set the end of newList to POSIX file j
      end if
    end if
    
  end repeat
  
  
return newList
end getFilepathListByUTI

–指定のPOSIX pathのファイルのUTIを求める
on retUTIfromPath(aPOSIXPath)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath
  
set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value)
  
  
if theResult = true then
    return theValue as string
  else
    return theResult
  end if
end retUTIfromPath

–UTIリストが指定UTIに含まれているかどうか演算を行う
on filterUTIList(aUTIList, aUTIstr)
  set anArray to NSArray’s arrayWithArray:aUTIList
  
set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
  
return bRes
end filterUTIList

★Click Here to Open This Script 

Posted in file File path list UTI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSDirectoryEnumerationSkipsHiddenFiles NSFileManager NSPredicate NSURL NSURLTypeIdentifierKey | 3 Comments

指定フォルダ内のファイルのうち、指定拡張子リストに入っているものをすべて取得してフルパスを返す

Posted on 4月 12, 2019 by Takaaki Naganoya

指定フォルダに入っているファイルのうち、指定拡張子リストに該当するものをフルパスで返すAppleScriptです。

macOS 10.6以降の64ビット化されたFinderは動作が遅いため、大量のファイル情報を取得するなどの用途には不向きです。このため、「(ファイル選択を取得する以外の)ファイル処理にはFinderを使わない」のが現在のAppleScriptのセオリーとなっています。

本Scriptでは、~/Library/Script Libraries/フォルダの存在確認と、その中に格納されている「scpt」「scptd」の拡張子を持つAppleScript書類ファイルのリストアップを高速に行います。

AppleScript名:指定フォルダ内のファイルのうち、指定拡張子リストに入っているものをすべて取得してフルパスを返す
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSPredicate : a reference to current application’s NSPredicate
property NSFileManager : a reference to current application’s NSFileManager
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles

set anExpList to {"scpt", "scptd"} — no dot
set libPath to (((path to library folder from user domain) as string) & "Script Libraries:")
set posixLibPath to POSIX path of libPath
set fList to getFilepathListByExt(posixLibPath, anExpList) of me

on getFilepathListByExt(aFol, aExtList as list)
  set aFM to NSFileManager’s defaultManager()
  
set aFolExt to (aFM’s fileExistsAtPath:aFol isDirectory:true) as boolean
  
if aFolExt = false then return {} –フォルダ自体が存在しなければヌルリストを返す
  
  
set aURL to |NSURL|’s fileURLWithPath:aFol
  
set theOptions to ((current application’s NSDirectoryEnumerationSkipsPackageDescendants) as integer) + ((current application’s NSDirectoryEnumerationSkipsHiddenFiles) as integer)
  
set urlArray to aFM’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:theOptions |error|:(missing value)
  
set thePred to NSPredicate’s predicateWithFormat_("pathExtension.lowercaseString IN %@", aExtList)
  
set anArray to (urlArray’s filteredArrayUsingPredicate:thePred)
  
return anArray as {missing value, list}
end getFilepathListByExt

★Click Here to Open This Script 

Posted in file list | Tagged 10.12savvy 10.13savvy 10.14savvy NSFileManager NSPredicate NSURL | Leave a comment

PDFのしおり(TOC)の内容を取得する v3

Posted on 4月 11, 2019 by Takaaki Naganoya

指定のTOCつきPDFからTOCをrecord in listで取得するAppleScriptです。各TOC項目のページ数、アウトラインレベル、ラベル(ページ名称)を順次取得して配列に出力します。

先日発売したBlogアーカイブ本のTOCを本Scriptで取得すると、以下のようになります(抜粋)。

{{pageIndex:1, outlineLevel:1, outLabel:"表紙"}, {pageIndex:2, outlineLevel:1, outLabel:"商標について"}, {pageIndex:3, outlineLevel:1, outLabel:"本書をご覧になるために"}, ... {pageIndex:34, outlineLevel:1, outLabel:"2011/1"}, {pageIndex:35, outlineLevel:2, outLabel:"リスト同士のdiffをとる"}, {pageIndex:40, outlineLevel:2, outLabel:"日本の月呼称を返す"}, {pageIndex:42, outlineLevel:2, outLabel:"指定の月を1月分リスト化"},...... {pageIndex:450, outlineLevel:1, outLabel:"奥付"}}

あれ? 「本書について」(2P)という記事が掲載もれしているのを、TOC出力から見つけてしまった、、、、、、、、

AppleScript名:PDFのしおり(TOC)の内容を取得する v3
— Created 2017-01-09 by Takaaki Naganoya
— Modified 2019-04-10 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "Quartz"

property |NSURL| : a reference to current application’s |NSURL|
property PDFDocument : a reference to current application’s PDFDocument
property titleList : {}

set my titleList to {}

set aFile to POSIX path of (choose file of type {"com.adobe.pdf"})

set fileURL to |NSURL|’s fileURLWithPath:aFile
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:fileURL

–TOCの読み込み
set parentOL to aPDFdoc’s outlineRoot() –あらかじめTOCが存在していないとmissing valueになる
if parentOL is equal to missing value then
  display dialog "本PDFにはTOCが添付されていないため、処理を終了します" with title "No TOC Error:"
  
return
end if

getChilds(parentOL) of me
return (my titleList)
–> {{pageIndex:1, outlineLevel:1, outLabel:"表紙"}, {pageIndex:2, outlineLevel:1, outLabel:"商標について"}, {pageIndex:3, outlineLevel:1, outLabel:"本書をご覧になるために"}, {pageIndex:5, outlineLevel:1, outLabel:"まえがき"},…… {pageIndex:33, outlineLevel:1, outLabel:"2011年"}, {pageIndex:34, outlineLevel:1, outLabel:"2011/1"}, {pageIndex:35, outlineLevel:2, outLabel:"リスト同士のdiffをとる"}, {pageIndex:40, outlineLevel:2, outLabel:"日本の月呼称を返す"},…….}

–PDFOutlineを再帰で取得する
on getChilds(parentOL)
  set outLineStr to parentOL’s label()
  
set outLineCount to (parentOL’s numberOfChildren()) as number
  
  
repeat with i from 0 to (outLineCount – 1)
    set anOut to (parentOL’s childAtIndex:i)
    
    
–Label (Page Title)
    
set tmpOut to (anOut’s label()) as string
    
    
–Page Indel Label
    
set tmpInd to (anOut’s destination()’s page()’s label()) as integer
    
    
–Outline Level
    
set outlevel to 0
    
copy anOut to aTmpOut
    
repeat
      set aTmpOut to aTmpOut’s |parent|()
      
if aTmpOut = missing value then exit repeat
      
set outlevel to outlevel + 1
    end repeat
    
    
set the end of my titleList to {pageIndex:tmpInd, outlineLevel:outlevel, outLabel:tmpOut}
    
    
set tmpChild to (anOut’s numberOfChildren()) as integer
    
    
if tmpChild is not equal to 0 then
      getChilds(anOut) of me
    end if
  end repeat
end getChilds

★Click Here to Open This Script 

Posted in list PDF Record recursive call | Tagged 10.12savvy 10.13savvy 10.14savvy NSURL PDFDocument | Leave a comment

Post navigation

  • Older posts
  • Newer posts

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

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 15, Sequoia
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • Numbersで選択範囲のセルの前後の空白を削除
  • メキシカンハットの描画
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AppleScriptによる並列処理
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • macOS 15でも変化したText to Speech環境
  • AppleScript入門③AppleScriptを使った「自動化」とは?
  • デフォルトインストールされたフォント名を取得するAppleScript
  • macOS 15 リモートApple Eventsにバグ?
  • 【続報】macOS 15.5で特定ファイル名パターンのfileをaliasにcastすると100%クラッシュするバグ
  • AppleScript入門① AppleScriptってなんだろう?
  • Script Debuggerの開発と販売が2025年に終了
  • macOS 14で変更になったOSバージョン取得APIの返り値
  • NSObjectのクラス名を取得 v2.1
  • 有害ではなくなっていたSpaces
  • macOS 15:スクリプトエディタのAppleScript用語辞書を確認できない
  • Xcode上のAppleScriptObjCのプログラムから、Xcodeのログ欄へのメッセージ出力を実行

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (212) 13.0savvy (194) 14.0savvy (147) 15.0savvy (135) CotEditor (66) Finder (51) iTunes (19) Keynote (119) 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 (76) Pages (55) 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
  • date
  • 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
  • process
  • 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年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 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