クリップボードに入ったStyled Stringから、フォント名とサイズと文字内容の情報を取得するAppleScriptです。
Keynoteのテキストオブジェクトのフォント名(フォントファミリー)を置換するAppleScriptを作ったときに、Keynoteが「選択中のオブジェクト」を取得する機能がないために、テキストオブジェクトの中(object text)をコピーして、AppleScript側にその情報を引き渡す必要がありました。
▲年末にコンテスト応募のために久しぶりにFileMaker Proにまとまった時間さわったので、そのノウハウを整理してまとめた本を作成中
こんなKeynote書類があったときに、タイトル部分の書式情報に該当するText Objectのみフォントを一括変更する、という処理です。
KeynoteのAppleScript用語辞書に、選択中のオブジェクトに対してアクセスできるオブジェクト(「selected items」のような)が定義されていれば、クリップボード経由で情報を受け取るような野蛮な処理はしないで済むのですが、、、、、
AppleScript名:クリップボードに入ったStyled Stringからフォントとサイズと文字内容の情報を取得.scptd |
— Created 2021-01-03 by Takaaki Naganoya — 2021 Piyomaru Software use AppleScript version "2.5" use scripting additions use framework "Foundation" use framework "AppKit" property NSFont : a reference to current application’s NSFont property NSColor : a reference to current application’s NSColor property NSArray : a reference to current application’s NSArray property NSString : a reference to current application’s NSString property NSDictionary : a reference to current application’s NSDictionary property NSPasteboard : a reference to current application’s NSPasteboard property NSCountedSet : a reference to current application’s NSCountedSet property NSMutableArray : a reference to current application’s NSMutableArray property NSSortDescriptor : a reference to current application’s NSSortDescriptor property NSAttributedString : a reference to current application’s NSAttributedString property NSMutableDictionary : a reference to current application’s NSMutableDictionary property NSFontAttributeName : a reference to current application’s NSFontAttributeName property NSKernAttributeName : a reference to current application’s NSKernAttributeName property NSMutableParagraphStyle : a reference to current application’s NSMutableParagraphStyle property NSLigatureAttributeName : a reference to current application’s NSLigatureAttributeName property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString property NSUnderlineStyleAttributeName : a reference to current application’s NSUnderlineStyleAttributeName property NSParagraphStyleAttributeName : a reference to current application’s NSParagraphStyleAttributeName property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName –クリップボード内にスタイル付きテキストが入っているかチェック set cRes to clipboard info for «class RTF » if cRes = {} then return –クリップボードに入っているスタイル付きテキストから情報を取得 set {aFontName, aFontSZNum, aString} to getFontNameAndSizeFromClipboard() of me –> {"DINCondensed-Bold", 170.0, "FileMaker Pro Scripting Book"} –クリップボードの内容を書式つきテキストとして解釈 on getFontNameAndSizeFromClipboard() –クリップボードの内容を文字列として取得 using terms from scripting additions set aStr to (the clipboard) as string end using terms from if aStr = "" then display dialog "No Data in Clipboard" buttons {"OK"} default button 1 return end if –クリップボードの内容をStyled Stringで取得して最頻出フォントを取得 set clipboardAttrStr to getClipboardASStyledText() of me if clipboardAttrStr = missing value then display dialog "Can not get clipboard as Styled String" buttons {"OK"} default button 1 return end if set attrList to getAttributeRunsFromAttrString(clipboardAttrStr) of me set anArray to ((NSArray’s arrayWithArray:attrList)’s valueForKeyPath:"fontName") as {list, string} set aFontList to (countItemsByItsAppearance(anArray) of me) set aFontName to theName of first item of aFontList set fSizes to ((NSArray’s arrayWithArray:attrList)’s valueForKeyPath:"fontSize") as {list, real} set aFontSZList to (countItemsByItsAppearance(fSizes) of me) set aFontSZNum to theName of first item of aFontSZList set aString to ((NSArray’s arrayWithArray:attrList)’s valueForKeyPath:"stringVal") as string return {aFontName, aFontSZNum, aString} end getFontNameAndSizeFromClipboard –1D Listを文字列長でソート v2 on sort1DListByIndicatedStringLength(aList as list, aSortKey as string, sortOrder as boolean) set aArray to NSArray’s arrayWithArray:aList set descLabel1 to NSString’s stringWithString:(aSortKey & ".length") set descLabel2 to NSString’s stringWithString:aSortKey set desc1 to NSSortDescriptor’s sortDescriptorWithKey:descLabel1 ascending:sortOrder set desc2 to NSSortDescriptor’s sortDescriptorWithKey:descLabel2 ascending:true selector:"localizedCaseInsensitiveCompare:" set bArray to aArray’s sortedArrayUsingDescriptors:{desc1, desc2} return bArray as list end sort1DListByIndicatedStringLength –リストを指定デリミタをはさんでテキスト化 on retStrFromArrayWithDelimiter(aList as list, aDelim as string) set anArray to NSArray’s arrayWithArray:aList set aRes to anArray’s componentsJoinedByString:aDelim return aRes as text end retStrFromArrayWithDelimiter –書式つきテキストを組み立てる on makeRTFfromParameters(aStr as string, fontName as string, aFontSize as real, aKerning as real, aLineSpacing as real) set aVal1 to NSFont’s fontWithName:fontName |size|:aFontSize set aKey1 to (NSFontAttributeName) set aVal2 to NSColor’s blackColor() set aKey2 to (NSForegroundColorAttributeName) set aVal3 to aKerning set akey3 to (NSKernAttributeName) set aVal4 to 0 set akey4 to (NSUnderlineStyleAttributeName) set aVal5 to 2 –all ligature ON set akey5 to (NSLigatureAttributeName) set aParagraphStyle to NSMutableParagraphStyle’s alloc()’s init() aParagraphStyle’s setMinimumLineHeight:(aLineSpacing) aParagraphStyle’s setMaximumLineHeight:(aLineSpacing) set akey7 to (NSParagraphStyleAttributeName) set keyList to {aKey1, aKey2, akey3, akey4, akey5, akey7} set valList to {aVal1, aVal2, aVal3, aVal4, aVal5, aParagraphStyle} set attrsDictionary to NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList set attrStr to NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary return attrStr end makeRTFfromParameters — クリップボードの内容をNSAttributedStringとして取り出して返す on getClipboardASStyledText() set theNSPasteboard to NSPasteboard’s generalPasteboard() set theAttributedStringNSArray to theNSPasteboard’s readObjectsForClasses:({NSAttributedString}) options:(missing value) set theNSAttributedString to theAttributedStringNSArray’s objectAtIndex:0 return theNSAttributedString end getClipboardASStyledText –指定のNSAttributedStringから書式情報をlist of recordで取得 on getAttributeRunsFromAttrString(theStyledText) script aSpd property styleList : {} end script set (styleList of aSpd) to {} —for output set thePureString to theStyledText’s |string|() –pure string from theStyledText set theLength to theStyledText’s |length|() set startIndex to 0 repeat until (startIndex = theLength) set {theAtts, theRange} to theStyledText’s attributesAtIndex:startIndex longestEffectiveRange:(reference) inRange:{startIndex, theLength – startIndex} set aText to (thePureString’s substringWithRange:theRange) as string set aColor to (theAtts’s valueForKeyPath:"NSColor") if aColor is not equal to missing value then set aSpace to aColor’s colorSpace() set aRed to (aColor’s redComponent()) * 255 set aGreen to (aColor’s greenComponent()) * 255 set aBlue to (aColor’s blueComponent()) * 255 set colList to {aRed as integer, aGreen as integer, aBlue as integer} set colStrForFind to (aRed as integer as string) & " " & (aGreen as integer as string) & " " & (aBlue as integer as string) else set colList to {0, 0, 0} set colStrForFind to "0 0 0" end if set aFont to (theAtts’s valueForKeyPath:"NSFont") if aFont is not equal to missing value then set aDFontName to aFont’s fontName() set aDFontSize to aFont’s pointSize() end if set the end of (styleList of aSpd) to {stringVal:aText, colorStr:colStrForFind, colorVal:colList, fontName:aDFontName as string, fontSize:aDFontSize} set startIndex to current application’s NSMaxRange(theRange) end repeat return (styleList of aSpd) end getAttributeRunsFromAttrString –1D Listをアイテムの出現頻度順でソートして返す on countItemsByItsAppearance(aList as list) set aSet to NSCountedSet’s alloc()’s initWithArray:aList set bArray to NSMutableArray’s array() set theEnumerator to aSet’s objectEnumerator() repeat set aValue to theEnumerator’s nextObject() if aValue is missing value then exit repeat bArray’s addObject:(NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{"theName", "numberOfTimes"}) end repeat set theDesc to NSSortDescriptor’s sortDescriptorWithKey:"numberOfTimes" ascending:false bArray’s sortUsingDescriptors:{theDesc} return bArray as list end countItemsByItsAppearance |