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

カテゴリー: PDF

Skimで現在表示中のPDFで、現在表示中のページ以降を削除

Posted on 7月 2 by Takaaki Naganoya

Skimでオープン中のPDFに対して、現在表示中のページ以降をすべて削除するAppleScriptです。

もともとは、macOS 10.13以前のバージョンのmacOSで、BridgePlusを呼び出すようにしてあったものですが、スクリプトメニューからBridgePlusを呼び出せなくなって、BridgePlus呼び出し部分を別のサブルーチンに置き換えてみたものです。

# 一応、Script Debuggerから拡張アプレットで書き出せば、スクリプトメニューに入れたScript(アプレット?)からBridgePlusの呼び出し自体は行えます。

もともと、SkimにはPDFのページ削除の機能が存在していないので、情報取得後にPDFをいったんクローズ、AppleScriptだけでPDFKitの機能を呼び出して削除処理を行い、再度Skimでオープンするという処理を行なっています。

現在表示中のページから前を削除するScriptも書いて使っていますが、余計に処理に時間がかかります。

SkimのScript本を提案したこともあったのですが、開発チームのとくに誰が許可を出すというわけでもなく、そのまま時間が流れてしまいました。Skimの機能範囲だけだと実現できることに制限がありますが、AppleScriptからPDFKitの機能を呼び出すと、Skim自体で持っていない機能も実装できて便利です。

そういうものを目指していたのですが、いまひとつテンションが上がらずそのまま放置状態に。

AppleScript名:現在表示中のページ以降を削除.scptd
— Created 2018-06-30 by Takaaki Naganoya
— Modified 2024-07-01 by Takaaki Naganoya
— 2018–2024 Piyomaru Software
use AppleScript version "2.8"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "PDFKit"

property NSSet : a reference to current application’s NSSet
property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property PDFDocument : a reference to current application’s PDFDocument
property NSSortDescriptor : a reference to current application’s NSSortDescriptor

tell application "Skim"
  set docCount to count every document
  
if docCount = 0 then return
  
  
tell front document
    set curInd to index of current page
    
set docFile to file of it
    
close without saving
  end tell
end tell

set aPOSIX to POSIX path of docFile
set aURL to (|NSURL|’s fileURLWithPath:aPOSIX)

set aPDFdoc to PDFDocument’s alloc()’s initWithURL:aURL
set pCount to aPDFdoc’s pageCount()

set pRes to removePDFPageAfter(docFile, curInd) of me

tell application "Skim"
  open docFile
  
tell front document
    go to last page
  end tell
end tell

–指定パスのPDFの指定ページ以降(指定ページも含む)をすべて削除
on removePDFPageAfter(inFile, sPage)
  set pCount to pdfPageCount(inFile) of me
  
set eCount to pCount – sPage + 1
  
  
set targPageList to makeSuccessfulNumArray(sPage, pCount) of me
  
set rList to reverse of targPageList
  
return removeSpecificPagesFromPDF(inFile, rList) of me
end removePDFPageAfter

–指定PDF書類の複数ページの一括削除
on removeSpecificPagesFromPDF(inFileAlias, targPageNumList as list)
  set inNSURL to |NSURL|’s fileURLWithPath:(POSIX path of inFileAlias)
  
set theDoc to PDFDocument’s alloc()’s initWithURL:inNSURL
  
  
–削除対象ページリストをユニーク化して降順ソート(後方から削除)
  
set pRes to theDoc’s pageCount()
  
set t3List to relativeToAbsNumList(targPageNumList, pRes) of me
  
  
repeat with i in t3List
    copy i to targPageNum
    (
theDoc’s removePageAtIndex:(targPageNum – 1))
  end repeat
  
  
–Overwrite Exsiting PDF
  
set aRes to (theDoc’s writeToURL:inNSURL) as boolean
  
  
return aRes
end removeSpecificPagesFromPDF

–絶対ページと相対ページが混在した削除対象ページリストを絶対ページに変換して重複削除して降順ソート
on relativeToAbsNumList(aList, aMax)
  set newList to {}
  
  
repeat with i in aList
    set j to contents of i
    
if i < 0 then
      set j to aMax + j
    end if
    
    
if (j ≤ aMax) and (j is not equal to 0) then
      set the end of newList to j
    end if
  end repeat
  
  
set t1List to uniquify1DList(newList, true) of me
  
set t2List to sort1DNumListWithOrder(t1List, false) of me
  
  
return t2List
end relativeToAbsNumList

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

–Sort 1-Dimension List(String Number List)
on sort1DNumListWithOrder(theList as list, aBool as boolean)
  tell NSSet to set theSet to setWithArray_(theList)
  
tell NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_("floatValue", aBool)
  
set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor}
  
return (sortedList) as list
end sort1DNumListWithOrder

–指定PDFのページ数をかぞえる
on pdfPageCount(aFile)
  set aFile to POSIX path of aFile
  
set theURL to |NSURL|’s fileURLWithPath:aFile
  
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:theURL
  
set aRes to aPDFdoc’s pageCount()
  
return aRes as integer
end pdfPageCount

–連番1D Listを作成
on makeSuccessfulNumArray(sNum, eNum)
  script spd
    property aList : {}
  end script
  
  
if sNum ≥ eNum then return {}
  
  
set (aList of spd) to {}
  
  
repeat with i from sNum to eNum
    set the end of (aList of spd) to i
  end repeat
  
  
return (aList of spd)
end makeSuccessfulNumArray

★Click Here to Open This Script 

Posted in PDF | Tagged 12.0savvy 13.0savvy 14.0savvy Skim | Leave a comment

指定のWordファイルをPDFに書き出す

Posted on 5月 4 by Takaaki Naganoya

ほとんど書き捨てレベルのAppleScriptですが、Microsoft Office用のAppleScriptの動作状況(ランタイム環境を変更すると動かなくなるなど)に興味があったので、書いてみました。

初回実行時にWord書類が入っているフォルダへのアクセス許可を求めるダイアログが出ますが、2回目以降はとくに聞かれません。

また、PowerPoint用のAppleScriptで、スクリプトメニューから実行すると実行がブロックされるという「Microsoft、正気か?」という仕様になっていましたが、いまMicrosoft Word用の本AppleScriptをスクリプトメニューに入れて呼び出しても実行できることを確認しています(macOS 13.6.7+Word バージョン 16.84 (24041420))。

AppleScript名:指定のWordファイルをPDFに書き出す.scpt
set aFile to choose file
automatorRun({aFile}, missing value) of me

on automatorRun(input, parameters)
  repeat with i in input
    set ipath to i as text
    
    
tell application "System Events"
      set o to name of i
    end tell
    
    
set o to repChars(ipath, ".docx", ".pdf") of me
    
    
tell application "Microsoft Word"
      close every document without saving
      
open i
      
save as document 1 file name o file format (format PDF)
      
close every document without saving
    end tell
  end repeat
  
  
return ""
end automatorRun

on repChars(origText as string, targStr as string, repStr as string)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChars

★Click Here to Open This Script 

本Scriptを書くことになったreddit上の投稿への回答となるScriptはこちら。

AppleScript名:指定のWordファイルをPDFに書き出す(For Automator Action).scpt

on run {input, parameters}
  repeat with i in input
    set ipath to i as text
    
    
tell application "System Events"
      set o to name of i
    end tell
    
    
set o to repChars(ipath, ".docx", ".pdf") of me
    
    
tell application "Microsoft Word"
      close every document without saving
      
open i
      
save as document 1 file name o file format (format PDF)
      
close every document without saving
    end tell
  end repeat
  
  
return ""
end run

on repChars(origText as string, targStr as string, repStr as string)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChars

★Click Here to Open This Script 

Posted in Object control PDF | Tagged 12.0savvy 13.0savvy 14.0savvy Word | Leave a comment

Adobe AcrobatをAppleScriptから操作してPDF圧縮

Posted on 2月 23 by Takaaki Naganoya

Adobe Acrobatは、一応AppleScript用語辞書がついてはいるものの、ほぼ「使えないアプリ」「役に立たない用語辞書」の名をほしいままにしてきました。AppleScript界における「がっかり遺産」のような存在です。

登場以来、一番期待されるPDF本文テキスト抽出の用途にまったく役に立たない(文字化けした謎テキストを出力)うえに、TOCやBookmarkへのアクセスもさっぱりです。

Classic MacOS時代にAdobe AcrobatのAppleScript用語辞書への深い失望があって、そこからフリーの「Skim PDF Viewer」の登場とか、のちにCocoaを直接呼べるようになって、十分なPDFへのアクセスが行えるようになりました。もはや、「もっといいもの」がいろいろ存在しているため、PDFを操作したいとか情報を抽出したいという需要は別のものによって満たされている状態です。

いまや、Adobe AcrobatのAppleScript用語辞書の存在感は「歴史上、そんなものがあったと語りつがれさえもしない」という「Air」のようなレベルです。事実、それに見出せる価値は何もありません。

そうした歴史認識と前提となる話がありつつも、それでも1つだけAdobe Acrobatには価値ある機能が存在します。本当に1つだけ。

それが、PDFの圧縮機能です。

最近は、macOS上のQuartzFilterのPDF圧縮もまったく機能しておらず、逆に呼び出すとファイルサイズが大きくなるとかいう笑えない冗談みたいな状態。PDFの圧縮ソリューションについてはAdobe Acrobatないしはactobat.adobe.comのWebアプリぐらいしか、手軽に使えるものが存在していない状態です。

とはいうものの、Adobe AcrobatのPDF圧縮機能は、AppleScript用語辞書に呼び出し用のコマンド用語が用意されてはいません。強引にGUIを操作するしかないようです。

Adobe AcrobatのAppleScript用語辞書の中にも「execute」コマンドが用意されており、任意のメニュー項目を操作できるような雰囲気が漂っていますが、いくら指定しても操作できません。

というわけで、とても嫌ではあるもののGUI Scripting経由で機能にアクセス。ちなみに、こういう時のために用意しておいた「dynamicMenuClicker」ライブラリは、Adobe Acrobat向けにはうまく動作しません。アプリケーション名、プロセス名、表示プロセス名などでAdobe Acrobatは不具合を持つ「特異点」であるため、Acrobatを操作する場合にのみ別の対処ルーチンを組み込んでおく必要があることでしょう。

AppleScript名:GUI Scripting経由でオープン中のPDFのファイルサイズを縮小.scpt
tell application "Adobe Acrobat"
  tell front document
    set aCount to count every document
    
if aCount = 0 then return
  end tell
end tell

activate application "Adobe Acrobat"
tell application "System Events"
  tell process "Acrobat"
    –ファイル>その他の形式で保存>サイズが縮小されたPDF…
    
click menu item 1 of menu 1 of menu item 9 of menu 1 of menu bar item 3 of menu bar 1
    
    
delay 0.5
    
    
–ダイアログ上のボタン「OK」をクリック
    
tell window 1
      click button "OK"
    end tell
    
    
delay 0.5
    
    
–保存ダイアログ(名前を付けて保存)
    
tell window 1
      click button "保存" –Localized
      
      
delay 0.5
      
      
set sList to every sheet
      
      
if length of sList is not equal to 0 then
        tell sheet 1
          click button "置き換え" –Localized
        end tell
      end if
    end tell
    
    
  end tell
end tell

★Click Here to Open This Script 

下記Scriptは、動作しません。

AppleScript名:本来はこう書けば動くはずだったメニュー操作.scpt
use dynC : script "dynamicClicker"

set appName to "AdobeAcrobat" –Application Name
set aList to {"ファイル", "その他の形式で保存", "サイズが縮小されたPDF…"} –Localized Menu Titles

set aRes to clickSpecifiedMenuElement(appName, aList) of dynC

★Click Here to Open This Script 

Posted in Object control PDF | Tagged 13.0savvy Adobe Acrobat | Leave a comment

Finder上で選択中のPDFのページ数を加算

Posted on 9月 14, 2023 by Takaaki Naganoya

Finder上で選択中のPDFのページ数を合計してダイアログ表示するAppleScriptです。ずいぶん前に作っておいたScriptのアップデート版です。

以前に作っておいたものは、BridgePlus Script Libraryを必要としていたために、ランタイム環境がScript DebuggerもしくはSDから書き出した拡張アプレットに限られていました。

これはこれで動作して便利なのですが、macOSが提供しているさまざまなランタイム環境およびサードパーティのソフトウェアが提供するランタイム環境では、このままでは動作しませんでした。BridgePlus依存部分を別のScriptに置き換えることで、より広範なランタイム環境で動作するようになるわけです。

今回置き換えたのは、指定パスのファイルからUTIを求める処理。割と、さまざまな機能を用いた部品を用意してあったので、入れ替えるだけで済みました。

本Scriptでは、Finderで選択中のファイルのUTIをすべて求め、指定のUTI(com.adobe.pdf)に該当するかどうかをチェックしています。今回のような処理では、拡張子のチェックだけで済みそうな話ですが、「画像全般」(public.image)を指定しておけば、PNGだろうがJPEGだろうが画像ならなんでもピックアップできるので、そうした処理のために用意しておいたものです。

本ScriptはPDFのページカウントなのでPDFKitの機能を利用していますが、メタデータにページ数が書いてある書類であれば、メタデータ経由で取得してもよいでしょう。最終的には、実際に書類をオープンして数えてもいいわけで。


▲Finder上でカウント対象のPDFを選択


▲macOS標準搭載のスクリプトメニューから実行


▲Finderで選択していたPDFのページ数合計を表示。コピペできるようにしてある

合計ページ数を計算したかったので素朴な表示を行なっていますが、表インタフェースでそれぞれのPDFのファイル名とページ数を一緒に表示してもいいかもしれません。

AppleScript名:Finder上で選択中のPDFのページ数を加算.scptd
— Created 2018-06-26 by Takaaki Naganoya
— Modified 2023-09-13 by Takaaki Naganoya
— 2018-2023 Piyomaru Software
use AppleScript version "2.8"
use scripting additions
use framework "Foundation"
use framework "PDFKit" –macOS 12 or later

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSPredicate : a reference to current application’s NSPredicate
property PDFDocument : a reference to current application’s PDFDocument
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey
property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch

–set inFiles to (choose file of type {"pdf"} with prompt "Choose your PDF files:" with multiple selections allowed)
tell application "Finder"
  set inFiles to selection as alias list
end tell

if inFiles = {} then
  display dialog "No PDF Selection on Finder…" with icon 1
  
return
end if

–指定のAlias listのうちPDFのみ抽出
set filRes1 to filterAliasListByUTI(inFiles, "com.adobe.pdf") of me

set totalP to 0

repeat with i in filRes1
  set tmpCount to pdfPageCount(contents of i) of me
  
if tmpCount > 0 then
    set totalP to totalP + tmpCount
  end if
end repeat

display dialog "Total Pages:" default answer (totalP as string) with icon 1

–指定PDFのページ数をかぞえる(10.9対応。普通にPDFpageから取得)
–返り値:PDFファイルのページ数(整数値)
on pdfPageCount(aFile)
  set theURL to |NSURL|’s fileURLWithPath:aFile
  
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:theURL
  
set aRes to aPDFdoc’s pageCount()
  
return aRes as integer
end pdfPageCount

–Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す
on filterAliasListByUTI(aList, targUTI)
  set newList to {}
  
repeat with i in aList
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, targUTI)
    
if utiRes is not equal to {} then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterAliasListByUTI

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

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList as list, aLabelStr as string, ascendF as boolean)
  set aArray to NSArray’s arrayWithArray:aRecList
  
set sortDesc to NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF
  
–set sortDescArray to current application’s NSArray’s arrayWithObjects:sortDesc–macOS 11でクラッシュ
  
set sortedArray to aArray’s sortedArrayUsingDescriptors:{sortDesc}
  
return sortedArray
end sortRecListByLabel

★Click Here to Open This Script 

Posted in file PDF | Tagged 12.0savvy 13.0savvy | Leave a comment

Skim Notesのじっけん

Posted on 8月 18, 2023 by Takaaki Naganoya

目下、「Cocoa Scripting Course #6 PDFKit」の仕上げ作業中ですが、懸案事項がありました。

PDFに対してコメント、注釈的なもの(PDFAnnotation)をつけられるようになっていますが、各アプリケーションで管理方法が微妙に異なっており、互換性がありません。

Adobe Acrobatが付けたアノテーション → Skimで表示できない、プレビュー.appで表示できる
Skimが付けたアノテーション → Adobe Acrobat、プレビュー.appで表示できない
プレビュー.appが付けたアノテーション → Adobe Acrobat、Skimで表示できる


▲Skim上でPDFに対して各種アノテーションを付加した状態


▲Skim上でPDFに各種アノテーションを付加したものをPreview.appで表示。何も表示されない


▲Skim上でPDFに各種アノテーションを付加したものをAdobe Acrobatで表示。こちらも何も表示されない

SkimとAcrobatのアノテーションの互換性がナニでアレでありますが、一応プレビュー.appとSkimがあればなんとかなる感じです。

さて、Skimでアノテーションを付けるとSkim同士でしかアノテーションを表示できない状態になってしまい、かつ、AppleScriptからPDFKitを操作しても読めないので困っていました(SkimのGUIアプリケーション経由で取得できないこともなさそう)。

Skimのアノテーションを読むために、Skim本体とは別にSkimNotes.frameworkとSkimNotesBase.frameworkが提供されています。Skim.appとは別にインストールする必要があります。インストール先は~/Library/Frameworksです。

コード署名されていないので、Script Debugger上でこれらのFrameworkの機能を呼び出そうとすると、署名されていない旨の警告が表示されますが、システム設定.app>セキュリティとプライバシーで認証できます。これら2つのFramrworkの両方とも認証しておく必要があります。

テストデータとして、Skim.app上でノートアノテーションをPDFに追記して保存。これに対して、AppleScriptからアクセスできるか試してみました。

結論からいえば、AppleScriptからアクセスできるわけですが、互換性を持たせるような何かがあってもいいような気がするところです。Adobe Acrobatでアノテーションを記載したPDFを、Skimで見られるように修正するとか。Skimで記入したアノテーションを他のアプリケーションでも見られるように変換するとか。

AppleScript名:Skim Notesのじっけん.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2023/08/17
—
–  Copyright © 2023 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.8"
use framework "Foundation"
use framework "PDFKit"
use framework "SkimNotes"
use framework "SkimNotesBase"
use scripting additions

set aPOSIX to POSIX path of (choose file of type {"com.adobe.pdf"})
set aURL to (current application’s |NSURL|’s fileURLWithPath:aPOSIX)

set aPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL readSkimNotes:true
set pCount to aPDFdoc’s pageCount()

repeat with ii from 0 to (pCount – 1)
  log ii –Page Count
  
  
set firstPage to (aPDFdoc’s pageAtIndex:ii)
  
–>  (PDFPage) PDFPage, label 1
  
  
set anoList to (firstPage’s annotations()) as list
  
if anoList is not equal to {} then
    repeat with i in anoList
      set j to contents of i
      
log j
      
(*(SKNPDFAnnotationNote) Type: ’/Text’, Bounds: (320, 737) [16, 16]\n*)
      
      
set aType to (j’s type()) as string
      
log aType
      
(*Note*)
      
      
if aType = "Note" then
        set cVal to j’s |contents|() as string
        
log cVal
        
(*Skim Noteのタイトルだよ Skim Noteの本文だよ\n\n*)
        
        
set cVal to j’s iconType()
        
log cVal
        
(*0*)
        
        
set dVal to j’s isSkimNote() as boolean
        
log dVal
        
(*true*)
        
        
if dVal = true then
          set eVal to j’s |string|()
          
log eVal
          
(*(NSString) "Skim Noteのタイトルだよ"*)
          
          
set fVal to j’s SkimNoteProperties()
          
(*(NSDictionary) {bounds:"{{308, 732}, {16, 16}}", color:(NSColorSpaceColor) sRGB IEC61966-2.1 colorspace 1 1 0.5 1, userName:"Takaaki Naganoya2", modificationDate:(NSDate) "2023-08-17 14:38:39 +0000", image:<NSImage 0x6000067d32a0 Size={1920, 1200} RepProvider=<NSImageArrayRepProvider: 0x6000015034a0, reps:(\n "NSBitmapImageRep 0x600003eb85b0 Size={1920, 1200} ColorSpace=(not yet loaded) BPS=8 BPP=(not yet loaded) Pixels=1920×1200 Alpha=YES Planar=NO Format=(not yet loaded) CurrentBacking=nil (faulting) CGImageSource=0x600001089360"\n)>>, contents:"Skim Noteのタイトルだよ", text:(NSConcreteAttributedString) Skim Note{\n NSFont = ""Helvetica 12.00 pt. P [] (0x11f597610) fobj=0x139642430, spc=3.33"";\n NSParagraphStyle = "Alignment 0, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n 28L,\n 56L,\n 84L,\n 112L,\n 140L,\n 168L,\n 196L,\n 224L,\n 252L,\n 280L,\n 308L,\n 336L\n), DefaultTabInterval 0, Blocks (null), Lists (\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ’(null)’";\n}の本文だよ\n\n{\n NSFont = ""HiraginoSans-W3 12.00 pt. P [] (0x11f597610) fobj=0x11f5277a0, spc=4.00"";\n NSParagraphStyle = "Alignment 0, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n 28L,\n 56L,\n 84L,\n 112L,\n 140L,\n 168L,\n 196L,\n 224L,\n 252L,\n 280L,\n 308L,\n 336L\n), DefaultTabInterval 0, Blocks (null), Lists (\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ’(null)’";\n}, type:"Note", pageIndex:0, iconType:0}*)
          
          
set anImage to fVal’s image
          
log anImage
          
(*<NSImage 0x6000067cf700 Size={1920, 1200} RepProvider=<NSImageArrayRepProvider: 0x6000015182c0, reps:(\n "NSBitmapImageRep 0x600003effb10 Size={1920, 1200} ColorSpace=(not yet loaded) BPS=8 BPP=(not yet loaded) Pixels=1920×1200 Alpha=YES Planar=NO Format=(not yet loaded) CurrentBacking=nil (faulting) CGImageSource=0x60000105fa20"\n)>>*)
          
          
set colRes to fVal’s |color|
          
log colRes
          
(*(NSColorSpaceColor) sRGB IEC61966-2.1 colorspace 1 1 0.5 1*)
          
          
set tRes to fVal’s |text|
          
log tRes
          
(*(NSConcreteAttributedString) Skim Note{\n NSFont = ""Helvetica 12.00 pt. P [] (0x1296dd6e0) fobj=0x139642430, spc=3.33"";\n NSParagraphStyle = "Alignment 0, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n 28L,\n 56L,\n 84L,\n 112L,\n 140L,\n 168L,\n 196L,\n 224L,\n 252L,\n 280L,\n 308L,\n 336L\n), DefaultTabInterval 0, Blocks (null), Lists (\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ’(null)’";\n}の本文だよ\n\n{\n NSFont = ""HiraginoSans-W3 12.00 pt. P [] (0x1296dd6e0) fobj=0x11f5277a0, spc=4.00"";\n NSParagraphStyle = "Alignment 0, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 0, Tabs (\n 28L,\n 56L,\n 84L,\n 112L,\n 140L,\n 168L,\n 196L,\n 224L,\n 252L,\n 280L,\n 308L,\n 336L\n), DefaultTabInterval 0, Blocks (null), Lists (\n), BaseWritingDirection -1, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ’(null)’";\n}*)
          
          
set sBounds to fVal’s |bounds|
          
log sBounds
          
(*(NSString) "{{308, 732}, {16, 16}}"*)
          
          
set uName to fVal’s userName
          
log uName
          
(*(NSString) "Takaaki Naganoya2"*)
          
          
set modRes to fVal’s modificationDate
          
log modRes
          
(*(NSDate) "2023-08-17 14:38:39 +0000"*)
          
        end if
      end if
    end repeat
  end if
  
end repeat

★Click Here to Open This Script 

Posted in PDF | Tagged 13.0savvy Skim | Leave a comment

PowerPointで最前面の書類をPDF書き出し

Posted on 7月 29, 2023 by Takaaki Naganoya

よくある、Microsoft PowerPointで、オープン中の最前面の書類を指定のパスにPDFで書き出すAppleScriptです。M1 Mac mini+macOS 13.5上で動作するMicrosoft PowerPointバージョン16.75で確認しています。

スクリプトエディタ上で動かしてみましたが、デスクトップ上にファイルを書き込もうとしたときに、初回のみPowerPointがデスクトップフォルダにアクセスしてよいか、OSが確認ダイアログを表示してきました。こういう動作はScriptからのコントロール時には困ります。自動処理を行う前にクリアしておきたい(あらかじめダイアログ表示+認証を済ませておきたい)ところです。


▲PowerPointから書き出したPDF

Microsoft PowerPointのAppleScript用語辞書を確認してみたところ、「export」コマンドが存在しません。情報をいろいろ調べてみたところ「save as PDF」で指定パスにPDFを保存するようです。

さらに、こうした場合にsaveコマンドで指定するファイルパスは、fileオブジェクトで指し示しますが、PowerPointでは少々事情が異なるようでした。fileを指定すると、書き出されません。HFS形式のパスをテキストで指定する必要がありました。どうもこのあたり、ところどころバグめいた実装が散見されます。

Excelへの画像貼り込みScriptのように、POSIX pathでPDF書き出し先を指定してみましたが、こちらはPOSIX pathで指定しても書き出せませんでした。

AppleScript名:最前面の書類をPDF書き出し.scpt
set theOutputPath to ((path to desktop folder) as string) & (do shell script "uuidgen") & ".pdf"

tell application "Microsoft PowerPoint"
  tell active presentation
    save in theOutputPath as save as PDF
    
–保存先のファイルパスを文字列で指定する必要がある
    
–fileオブジェクトで指定すると書き出されない(バグのような挙動)
  end tell
end tell

★Click Here to Open This Script 

Posted in file File path PDF | Tagged 13.0savvy PowerPoint | Leave a comment

macOS 13の複合的な不具合。とくにPDF書き出しについて

Posted on 2月 24, 2023 by Takaaki Naganoya

いろいろ不具合が多すぎて、本当にこれがリリース版なのか理解に苦しむmacOS 13。リリース当初から、AppleScript経由でPagesの(大量の)書類に順次PDF書き出しを行わせると、PDF書き出しされない書類が発生することがわかっていました。

同じバージョンのPages 12.2.1でも、macOS 12.x上では問題が発生していなかったため、明確にmacOS 13.xが理由ではあるのですが、不具合の発生源がよくわかりません。

(1)Pages書類オープン後に時間待ちが必要?

macOS 13移行当初、Pages種類をオープンした後に一定の時間(1秒程度)待機を行って、内部の状態が安定するのを待ってPDF書き出しを行うようにしました。数十程度のPages書類であれば、これで問題は起こりませんでした。

(2)数百個のPages書類を順次オープン→PDF書き出しするとミスを行う

その後、百以上のPages書類を順次オープンして、時間待ちして、PDF書き出し処理を行ってみたところ、明確にPDF書き出しできない書類が複数出てきました。何回実行しても書き出されません。また、そのPages書類単独でPDF書き出しを行わせると問題なく書き出しが行えます。

このPDF書き出しミスを行う書類の動作を観察していると、指定した時間待ちが正しく行われません。delayコマンドに問題があるのかと考え、shellのsleepコマンドを試したりもしていますが、正しく時間待ちが行われません。

さらに、普通にPages書類からPDF書き出しできていたとしても、それを数回繰り返すとPDF書き出しされなくなる(何か、一定の回数書き出すと問題が発生するらしい)ため、macOS 13自体の再起動かログアウト→再ログインが必要でした。

そもそもmacOS 13の出来がよくない、いろいろ問題がありすぎるということ自体が問題なわけですが、、、「複数回実行しないと再現しない」「原因の所在がどこにあるのかよくわからない」といった状況で、レポート自体を行いにくいというのが現状です。

ほかにも、Finder上で選択したファイルをCommand-Oでオープンさせるとオープンできない場合があったりと(なんだこれ?)、何がやりたいのかよくわからないOSバージョンです。セキュリティ強化はもちろん重要ですが、まともに動かないOSをリリースされても、、、、さらに、Beta段階では許可されていた外付けSSDからの前バージョンのOSの起動がmacOS 13リリース以後は封じられており、そういうのは「まともなOS」をリリースできるようになってからやってほしい気持ちでいっぱいです。

もう、macOS 13自体、やり直してほしい気持ちでいっぱいです。macOS 10.13、macOS 10.15と同じかそれ以上にダメなバージョンにしか見えません。

Posted in Bug PDF | Tagged 13.0savvy Pages | Leave a comment

Keynoteでオープン中の書類をすべてデスクトップにPDF書き出しして最初のページをJPEG画像化

Posted on 10月 15, 2022 by Takaaki Naganoya

Keynoteでオープン中の書類すべてをPDF書き出しして、各PDFの最初のページをJPEG画像に書き出すAppleScriptです。書き出し先はデスクトップフォルダです。Keynote v12.1+macOS 12.6.1で動作確認しています。

それぞれ、PDF書き出しするScriptと、PDFをJPEGに変換するAppleScriptは個別に書いて使っていたのですが、処理数が増えるといちいち複数のScriptをかわるがわる実行するのも面倒に。

そこで、PDF書き出し→JPEG変換を行うものを作ってみました。作ったみたといっても、部品はすでに存在していたので繋ぎ合わせただけです。

AppleScript名:すべてデスクトップ上にPDF出力し、最初のページをJPEG出力.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/10/14
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—

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

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

set outPathList to {}

tell application "Keynote"
  set allDocs to every document
  
if allDocs = {} then return
  
  
repeat with i in allDocs
    set j to contents of i
    
set dRes to exportKeynoteDocToPDF(j) of me
    
set pdfPath to (POSIX path of dRes)
    
set pdfPath to chkExistPOSIXpathAndIncrementChildNumberFull(pdfPath) of me
    
set jRes to (my jpegFromPath:(pdfPath) compressFactor:1.0)
    
set the end of outPathList to jRes
  end repeat
end tell

return outPathList

–Keynote書類からPDF書き出し
on exportKeynoteDocToPDF(targKeynoteDoc)
  
  
tell application "Keynote"
    set dCount to count every document
    
if dCount = 0 then
      –オープン中のKeynote書類がない場合はリターン
      
return false
    end if
    
    
set aPath to file of targKeynoteDoc
  end tell
  
  
set tmpPath to (path to desktop) as string
  
set curPath to (NSString’s stringWithString:(POSIX path of aPath))’s lastPathComponent()’s stringByDeletingPathExtension()’s stringByAppendingString:".pdf"
  
set outPath to (tmpPath & curPath)
  
set outPath to chkExistPOSIXpathAndIncrementChildNumberFull(outPath) of me
  
–do shell script "touch " & quoted form of POSIX path of outPath –Error 6を回避するための記述
  
  
tell application "Keynote"
    –set anOpt to {class:export options, export style:IndividualSlides, all stages:false, skipped slides:true, PDF image quality:Good}
    
–set anOpt to {class:export options, export style:IndividualSlides, all stages:false, skipped slides:true, PDF image quality:Better}
    
set anOpt to {class:export options, export style:IndividualSlides, all stages:false, skipped slides:true, PDF image quality:Best}
    
export targKeynoteDoc to POSIX file outPath as PDF with properties anOpt
  end tell
  
  
return ((POSIX file outPath) as alias)
end exportKeynoteDocToPDF

on jpegFromPath:imagePath compressFactor:compFactor — 0.0 = max compression, 1.0 = none
  — build destination path
  
set pathNSString to current application’s NSString’s stringWithString:imagePath
  
set destPath to pathNSString’s stringByDeletingPathExtension()’s stringByAppendingPathExtension:"jpg"
  
  
— load the file as an NSImage
  
set theImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:imagePath
  
if theImage = missing value then return false
  
  
set theData to theImage’s TIFFRepresentation()
  
set newRep to current application’s NSBitmapImageRep’s imageRepWithData:theData
  
set theData to (newRep’s representationUsingType:(current application’s NSJPEGFileType) |properties|:{NSImageCompressionFactor:compFactor, NSImageProgressive:false})
  
  
set theResult to (theData’s writeToFile:destPath atomically:true) as boolean
  
return destPath as string
end jpegFromPath:compressFactor:

–POSIX path stringを与えると、ファイル名の重複を検出して、ファイル名の名称回避を行って、ファイル名のみを返す
on chkExistPOSIXpathAndIncrementChildNumberFull(a)
  set aa to POSIX path of a
  
set aStr to NSString’s stringWithString:aa
  
set bStr to aStr’s lastPathComponent()
  
  
set cStr to (bStr’s pathExtension()) as string
  
set dStr to (bStr’s stringByDeletingPathExtension()) as string
  
set eStr to (aStr’s stringByDeletingLastPathComponent()) as string
  
  
set aManager to NSFileManager’s defaultManager()
  
set aRes to (aManager’s fileExistsAtPath:aStr) as boolean
  
if aRes = false then return aa
  
  
set hitF to false
  
repeat with i from 1 to 65535
    
    
set tmpPath to (eStr & "/" & dStr & "_" & (i as string) & "." & cStr)
    
set tmpStr to (NSString’s stringWithString:tmpPath)
    
set aRes to (aManager’s fileExistsAtPath:tmpStr) as boolean
    
set bRes to ((tmpStr’s caseInsensitiveCompare:eStr) is not equal to (NSOrderedSame)) as boolean
    
    
if {aRes, bRes} = {false, true} then
      set hitF to true
      
exit repeat
    end if
    
  end repeat
  
  
if hitF = false then return false
  
  
–ファイルパス(フルパス)を返す
  
return (tmpStr as string)
end chkExistPOSIXpathAndIncrementChildNumberFull

★Click Here to Open This Script 

Posted in Image PDF | Tagged 12.0savvy Keynote | Leave a comment

指定のPDFの本文テキストの文字数をカウント

Posted on 3月 9, 2022 by Takaaki Naganoya

指定のPDFの本文テキストを取り出し、文字数をカウントするAppleScriptです。


▲「AppleScriptによるWebブラウザ自動操縦ガイド」の文字数をカウントしようとした

300ページを超える、わりと大きな本のPDFデータから文字を取り出したので、それなりの文字数になりました。つまり、Cocoaの有効活用を考えないとデータサイズ的につらそうなデータ量になることが予想されました。

当初、(文字処理については)Cocoaの機能をあまり活用しないv2を作ったものの、処理にM1 Mac miniで30秒ほどかかりました。すべてNSStringのまま(AppleScriptのstringに型変換せずに)処理してみたら、案の定、大幅に処理が高速化され6秒あまりで完了。

ただし、両者でカウントした文字数が1万文字ぐらい違っていたので、(PDFから取得した文字の)Unicode文字のNormalize方式を変更したところ、両者で同じ結果になりました。また、処理速度に改変前から大幅な変化はありませんでした。

文字数を数えるという処理だとさすがにデータ数が膨大になるため、NSStringで処理したほうがメリットが大きいようです。

# あれ? 5文字ぐらい違う、、、、絵文字の部分か?

AppleScript名:指定のPDFの本文テキストの文字数を数える v2
use AppleScript version "2.8" –macOS 12 or later
use framework "Foundation"
use framework "PDFKit" –Comment Out under macOS 11
–use framework "Quartz"–Uncomment under macOS 11
use scripting additions

script spd
  property cRes : ""
  
property cList : {}
end script

set (cRes of spd) to ""
set (cList of spd) to {}

set (cRes of spd) to getTextFromPDF(POSIX path of (choose file of type {"pdf"})) of me
set (cList of spd) to current application’s NSArray’s arrayWithArray:(characters of (cRes of spd))
set cLen to (cList of spd)’s |count|()
return cLen
–> 256137 (24.763sec)

on getTextFromPDF(posixPath)
  set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath
  
set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL
  
return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping()) as text
end getTextFromPDF

★Click Here to Open This Script 

AppleScript名:指定のPDFの本文テキストの文字数を数える v3
use AppleScript version "2.8" –macOS 12 or later
use framework "Foundation"
use framework "PDFKit" –Comment Out under macOS 11
–use framework "Quartz"–Uncomment under macOS 11
use scripting additions

script spd
  property cRes : ""
  
property cList : {}
end script

set (cRes of spd) to ""
set (cList of spd) to {}

set (cRes of spd) to getTextFromPDF(POSIX path of (choose file of type {"pdf"})) of me
set cLen to (cRes of spd)’s |length|
return cLen as anything
–> 256142 (6.28 sec)

on getTextFromPDF(posixPath)
  set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath
  
set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL
  
return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping())
end getTextFromPDF

★Click Here to Open This Script 

わずかとはいえ、違いが出ていることは確かなので、1つのPDFに対して2つの処理方法でテキストを取り出して、それを配列に入れて集合演算して差分をとってみました。M1でも処理に1分少々かかりました。こういう処理は、M1 MaxでもM1 Ultraでも所要時間は変わらないことでしょう(逆にM1の方が処理時間が短い可能性まである)。

どうやら改行コードの解釈で文字数カウント結果に違いが出たようです。

AppleScript名:テキストの抽出方法による文字数の相違チェック.scptd
use AppleScript version "2.8" –macOS 12 or later
use framework "Foundation"
use framework "PDFKit" –Comment Out under macOS 11
–use framework "Quartz"–Uncomment under macOS 11
use scripting additions

script spd
  property cRes : ""
  
property cList : {}
end script

set (cRes of spd) to ""
set (cList of spd) to {}

set docPath to POSIX path of (choose file of type {"pdf"})

set (cRes of spd) to getTextFromPDF1(docPath) of me
set (cList of spd) to characters of (cRes of spd)
set anArray to current application’s NSArray’s arrayWithArray:(cList of spd)

set bStr to getTextFromPDF2(docPath) of me
set bArray to current application’s NSMutableArray’s new()
set bLen to (bStr’s |length|) as anything
repeat with i from 0 to (bLen – 1)
  set tmpStr to (bStr’s substringWithRange:(current application’s NSMakeRange(i, 1)))
  (
bArray’s addObject:(tmpStr))
end repeat

set aRes to diffLists(anArray, bArray) of me
set bRes to diffLists(bArray, anArray) of me
return {aRes, bRes}

on getTextFromPDF1(posixPath)
  set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath
  
set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL
  
return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping()) as text
end getTextFromPDF1

on getTextFromPDF2(posixPath)
  set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath
  
set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL
  
return (thePDF’s |string|()’s precomposedStringWithCompatibilityMapping())
end getTextFromPDF2

–1D List同士のdiffを計算する
on diffLists(aList, bList)
  set aSet to current application’s NSMutableSet’s setWithArray:aList
  
set bSet to current application’s NSMutableSet’s setWithArray:bList
  
set aRes to calcSetDifference(aSet, bSet) of me
  
return aRes
end diffLists

–2つのNSMutableSetの補集合を求める
on calcSetDifference(aSet, bSet)
  aSet’s minusSet:bSet –補集合
  
set aRes to aSet’s allObjects() as list
  
return aRes
end calcSetDifference

★Click Here to Open This Script 

Posted in PDF Text | Tagged 12.0savvy NSURL PDFDocument | Leave a comment

Skimで現在表示中のページ(見開き2ページ、書籍モード)をJPEG画像で書き出す

Posted on 3月 2, 2022 by Takaaki Naganoya

SkimでPDFを、見開き2ページ、書籍モードで表示させた状態で、見開きごと2ページ分の画像をJPEG画像で書き出すAppleScriptです。

macOS 12.3 beta 5、Skim v1.6.8で動作を確認してあります。macOS 12に合わせてPDFKitを直接useコマンドで使用指定しています。


▲SkimでPDFをオープンした状態で実行。見開き2ページ、書籍モードを設定している状態


▲macOS標準搭載のスクリプトメニューから呼び出すことを前提に作ってあります


▲見開き2ページのうち、右ページを選択しているか、左ページを選択しているかの状態を検出して処理


▲出力結果。表示中のPDFと同じフォルダ内に作成される

AppleScript名:Skimで現在表示中のページ(見開き2ページ、書籍モード)をJPEG画像で書き出す
— Created 2022-03-02 by Takaaki Naganoya
— 2022 Piyomaru Software
use AppleScript version "2.7"
use scripting additions
use framework "Foundation"
use framework "Quartz"
use framework "PDFKit"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSNumber : a reference to current application’s NSNumber
property NSZeroPoint : a reference to current application’s NSZeroPoint
property PDFDocument : a reference to current application’s PDFDocument
property NSJPEGFileType : a reference to current application’s NSJPEGFileType
property NSCompositeCopy : a reference to current application’s NSCompositeCopy
property NSGraphicsContext : a reference to current application’s NSGraphicsContext
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
property NSImageInterpolationHigh : a reference to current application’s NSImageInterpolationHigh

tell application "Skim"
  set docCount to count every document
  
if docCount = 0 then return
  
  
tell front document
    set curViewSets to view settings
    
set curMode to display mode of curViewSets
    
    
if curMode is not in {two up, two up continuous} then
      display dialog "2ページ見開きモードでないため、処理を終了します。" with title "error" with icon 0
      
return
    end if
    
    
set bMode to displays as book of curViewSets
    
if bMode = false then
      display dialog "「書籍モード」でないため、処理を終了します。" with title "error" with icon 0
      
return
    end if
    
    
set curInd to index of current page
    
set docFile to file of it
  end tell
end tell

–PDFのファイルパスから実際のPDFを求める
set aPOSIX to POSIX path of docFile
set aURL to (|NSURL|’s fileURLWithPath:aPOSIX)
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:aURL

–PDFのページ数を求める
set pCount to aPDFdoc’s pageCount() –ページ数

if curInd = pCount then
  display dialog "このページはPDFの最終ページなので、見開き表示になっていない可能性があります。" with title "エラー"
  
return
end if

if curInd = 1 then
  display dialog "このページはPDFの最初のページなので、見開き表示になっていない可能性があります。" with title "エラー"
  
return
end if

–見開き中の選択ページが奇数(右ページ)だった場合の対処
if chkOddNum(curInd) = true then set curInd to curInd – 1

–Detect Retina Environment
set compFactor to 1.0 –1.0 — 0.0 = max jpeg compression, 1.0 = none

set retinaF to NSScreen’s mainScreen()’s backingScaleFactor()
if retinaF = 1.0 then
  set aScale to 2.0 –Non Retina Env
else
  set aScale to 1.0 –Retina Env
end if

–Pick Up a PDF page as an image (Left Side Page)
set thisPageL to (aPDFdoc’s pageAtIndex:(curInd – 1))
set imgL to (NSImage’s alloc()’s initWithData:(thisPageL’s dataRepresentation()))
set pageL to renderPDFPageToNSImage(imgL, (curInd – 1), aScale) of me

–Pick Up a PDF page as an image (Right Side Page)
set thisPageR to (aPDFdoc’s pageAtIndex:(curInd – 0))
set imgR to (NSImage’s alloc()’s initWithData:(thisPageR’s dataRepresentation()))
set pageR to renderPDFPageToNSImage(imgR, (curInd – 0), aScale) of me

–Calc 2 pages’ width and others
set origWidth to (pageR’s |size|()’s width)
set newWidth to origWidth * 2
set newHeight to pageR’s |size|()’s height

–Make 2 pages’ blank image
set aSize to current application’s NSMakeSize(newWidth, newHeight)
set newImage to NSImage’s alloc()’s initWithSize:aSize

–Compositte each Left and Right page image
overlayNSImageByLeftTopOrigin(newImage, pageL, {0, 0}) of me
overlayNSImageByLeftTopOrigin(newImage, pageR, {origWidth, 0}) of me

–Save Image as JPEG
set theData to newImage’s TIFFRepresentation()
set newRep to (NSBitmapImageRep’s imageRepWithData:theData)
set targData to (newRep’s representationUsingType:(NSJPEGFileType) |properties|:{NSImageCompressionFactor:compFactor, NSImageProgressive:false})
set zText to retZeroPaddingText((curInd + 1), 4) of me
set outPath to addString_beforeExtensionIn_addingExtension_("_" & zText, aPOSIX, "jpg")
(
targData’s writeToFile:outPath atomically:true) –書き出し

on renderPDFPageToNSImage(anImage, aPageNum, aScale)
  set pointSize to anImage’s |size|()
  
  
set newSize to current application’s NSMakeSize((pointSize’s width) * aScale, (pointSize’s height) * aScale)
  
set newImage to (NSImage’s alloc()’s initWithSize:newSize)
  
  
newImage’s lockFocus()
  (
anImage’s setSize:newSize)
  (
NSGraphicsContext’s currentContext()’s setImageInterpolation:(NSImageInterpolationHigh))
  (
anImage’s drawAtPoint:(NSZeroPoint) fromRect:(current application’s CGRectMake(0, 0, newSize’s width, newSize’s height)) operation:(NSCompositeCopy) fraction:2.0)
  
newImage’s unlockFocus()
  
return newImage
end renderPDFPageToNSImage

–ファイルパス(POSIX path)に対して、文字列(枝番)を追加。任意の拡張子を追加
on addString:extraString beforeExtensionIn:aPath addingExtension:aExt
  set pathString to NSString’s stringWithString:aPath
  
set theExtension to pathString’s pathExtension()
  
set thePathNoExt to pathString’s stringByDeletingPathExtension()
  
  
set newPath to (thePathNoExt’s stringByAppendingString:extraString)’s stringByAppendingPathExtension:aExt
  
return newPath as string
end addString:beforeExtensionIn:addingExtension:

on retZeroPaddingText(aNum, aLen)
  set tText to ("0000000000" & aNum as text)
  
set tCount to length of tText
  
set resText to text (tCount – aLen + 1) thru tCount of tText
  
return resText
end retZeroPaddingText

–2つのNSImageを重ね合わせ合成してNSImageで返す(x,yで配置座標を指定) –newImageを参照渡し
on overlayNSImageByLeftTopOrigin(newImage, composeImage, aTargPos as list)
  set backSize to newImage’s |size|()
  
set bHeight to (height of backSize)
  
  
set overlaySize to composeImage’s |size|()
  
copy aTargPos to {x1, tempy1}
  
set x2 to (width of overlaySize)
  
set y2 to (height of overlaySize)
  
set y1 to bHeight – y2 + tempy1
  
  
newImage’s lockFocus()
  
  
set bRect to {{x1, y1}, {x2, y2}} –macOS 10.13 or later
  
set newImageRect to {{0, 0}, (newImage’s |size|)}
  
newImage’s drawInRect:newImageRect
  
composeImage’s drawInRect:bRect
  
  
newImage’s unlockFocus()
end overlayNSImageByLeftTopOrigin

on retUUIDfilePath(aPath, aExt)
  set aUUIDstr to (NSUUID’s UUID()’s UUIDString()) as string
  
set aPath to ((NSString’s stringWithString:aPath)’s stringByDeletingLastPathComponent()’s stringByAppendingPathComponent:aUUIDstr)’s stringByAppendingPathExtension:aExt
  
return aPath
end retUUIDfilePath

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

–奇数かどうかチェック
on chkOddNum(aNum)
  set a to aNum mod 2
  
if a = 1 then
    return true
  else
    return false
  end if
end chkOddNum

–偶数かどうかチェック
on chkEvenNum(aNum)
  set a to aNum mod 2
  
if a = 0 then
    return true
  else
    return false
  end if
end chkEvenNum

★Click Here to Open This Script 

Posted in PDF | Tagged 12.0savvy | Leave a comment

Skim v1.6.5+macOS 12.0.1でPDFに埋め込んだapplescript://リンクの動作を確認

Posted on 10月 28, 2021 by Takaaki Naganoya

macOS 10.15で「PDFView上で発生した(カスタムURLスキームの)URLイベントを途中でブチ切る」という変更を、ユーザーに何の断りもなく行ったApple。

本Blog掲載のプログラムリスト末尾に入っている「applescript://」URLリンク。Webブラウザ(HTML)→スクリプトエディタの間では、このURLリンクは有効です。この仕様を引き継いで、AppleScript解説本のPDFでも同様のURLリンクを入れてあったのですが……これがmacOS 10.15で意図的にブロックされました。

URLリンクの長さが規定の文字数を超えるものは途中で切ったり、リンクをそもそも無効にしたりと、AppleはmacOS 10.15.x上でマイナーアップデートのたびに悪のかぎりを尽くしていました。90年代の傍若無人なマイクロソフトを想起させるような、強引すぎるやり方です。

こういうのはとてもよくないことだと思います。PDFの扱いがいいからmacOSを使っている、という部分は大きいわけですが、その基盤となるPDFの扱いをいろいろ無断で変更するというのは、感心しません。

macOS 10.15はβ段階から出来が悪く、「こんなのに付き合っていられるか!」と10.14を継続使用することを決め、10.15をガン無視することにしました。

macOS 10.15は「リリースしてはいけない」レベルのOSだと感じました。このあたり、ダメなものにストップをかけられないのは、Appleという会社の構造的な問題なんでしょう(イエスマンばっかりやがな)。

macOS 10.15を無視したことは個人の生産性を損なわなかったという意味では「いいこと」でしたが、macOS 10.5で発生していたさまざまな問題を自分が認識しなかった(そういうレベルまで付き合う気がしなかった)ために、問題の発覚が遅れたという副作用もありました(まさか、Cocoa Scriptingの実行速度が大幅に低下していたとは!>macOS 10.15)。

macOS 10.15におけるPDF埋め込みリンクについては、macOS標準添付のPreview.appであろうがサードパーティの(オープンソースの)Skim PDF Viewerだろうが、自分でXcode上で作ったお気軽PDFブラウザだろうが、PDFViewを使っている限りはこの制限が発生していました。

真剣にサードパーティのPDF関連Frameworkの利用も検討しましたが、価格面でなかなか折り合いが合わなかったのと、PDFViewに相当するクラスが提供されていなかったのでダメでした。

本件についてはAppleにレポートしていましたが、Apple側でガン無視状態(いろいろリクエストしても無視されるのがデフォルト状態)。サードパーティのPDFビューワまで影響が出るため、macOS 10.15を使わないという消極的な対策しかできない状況でした。

ちょうどこの時期に執筆していたMusic.appのScripting本が完全に頓挫するなど、少なからず打撃を受けた出来事だったのです(各種既刊本のアップデート計画も白紙撤回していました)。

その後、Piyomaru SoftwareのScripting本については「本誌掲載Scriptは別途Zipアーカイブを添付」という原始時代のやり方にたちかえることになります。

そんな中、ふとmacOS 12.0.1+Skim v1.6.5で冗談半分に「URLリンクが復活してたりして」と試してみたら……………「!!!!!』

なんと、Skim上では「applescript://」URLリンクが正常に動作して、内容が途切れることなくスクリプトエディタに転送されていました。さすがに、追加試験でPreview.app上で実行してみたらリンクをまるごとブロックされましたが、Skimについては大丈夫なようです。

こっそり禁止して、こっそり修正ということなんでしょうか。現状がこのまま維持されるのか、それとも将来にまた仕様が変更されるのか不明ですが、コソコソ仕様を変えられるのはとても不愉快です。

OSのRelease Notesをちゃんと出さないことは、不満です。

Posted in news PDF | Tagged 12.0savvy | Leave a comment

PDFにファイルサイズ縮小のQuartzフィルタをかけて出力

Posted on 4月 27, 2021 by Takaaki Naganoya

PDFに対して、Quartzフィルタをかけてファイルサイズを縮小する(はずの)AppleScriptです。

macOS標準搭載のPreview.appやColorSyncユーティリティを使うことで、PDFに対して各種Quartzフィルタを適用して加工できるようになっています。


▲/System/Library/Filtersに入っているQuartzフィルタ

フィルタする対象は「book20_Cocoa Scripting Course #03_v1.0_sampler.pdf」(16.7MB)です。

縮小した結果は22.2MB。オリジナルよりも大きくなってしまいました(実施前から分かっていたので、驚きはありません)。このテストはメインマシンのmacOS 10.14.6環境で実施しましたが、macOS 11.4betaの環境で実行してみたら22.1MB。オリジナルよりも大きくなるという意味では大差ありませんでした。

サンプルはKeynote書類から書き出したPDFで、AppleScriptによりTOCを添付してあるものです。Cocoa Scripting Course #3のリリース後も「もうちょっとPDF小さくなるんでは?」と試しています。Adobe Acrobatで縮小することでかなり小さくできることはわかっているものの、Acrobatとは縁を切りたい気持ちでいっぱいです。

色をいじくるフィルタについては問題なく動作しています。

AppleScript名:PDFにファイルサイズ縮小のQuartzフィルタをかけて出力.scptd
— Created 2014-12-26 by Takaaki Naganoya
— Modified 2021-04-27 by Takaaki Naganoya
— 2021 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "Quartz"
use framework "QuartzCore"

property QuartzFilter : a reference to current application’s QuartzFilter
property NSDictionary : a reference to current application’s NSDictionary
property PDFDocument : a reference to current application’s PDFDocument

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

set aHFSPath to (choose file of type {"com.adobe.pdf"} with prompt "フィルタするPDFを指定してください")
set aPOSIX to POSIX path of aHFSPath
set aURL to (|NSURL|’s fileURLWithPath:aPOSIX)

set bHFSPath to (choose file name with prompt "出力先を指定してください")
set bPOSIX to POSIX path of bHFSPath

set origPDFdoc to PDFDocument’s alloc()’s initWithURL:aURL

set aFilterURL to |NSURL|’s fileURLWithPath:"/System/Library/Filters/Reduce File Size.qfilter"
set aQFilter to QuartzFilter’s quartzFilterWithURL:aFilterURL

set aDict to NSDictionary’s dictionaryWithObjects:{aQFilter} forKeys:{"QuartzFilter"}

origPDFdoc’s writeToFile:(bPOSIX) withOptions:(aDict)

★Click Here to Open This Script 

Posted in PDF | Tagged 10.14savvy 10.15savvy 11.0savvy | Leave a comment

最前面のPDFで連続して同じページが存在するかチェック

Posted on 3月 13, 2021 by Takaaki Naganoya

昨日販売開始した「Cocoa Scripting Course #1」で同じページが連続している箇所をみつけてしまいました。近日中に修正しますが、これを自動でチェックするAppleScriptを書いておく必要性を感じ、作っておきました。

オープンソースのPDFビューワー「Skim」でオープン中のPDFの全ページのテキストを取得し、取得したあとで連続するページのテキスト同士を比較してチェックしています。

必要に応じて各ページを画像にレンダリングして比較する必要があるかと思っていたのですが、テキストだけでもけっこう検出できているのでこんな感じでしょうか。

このページは、AppleScriptにより実際のファイルを検出して表の内容を自動更新していたのですが、その作業バックアップのためにページそのものを複製して誤操作というか作業のやり直しに備えていたのですが、それを削除し忘れたかっこうです。

AppleScript名:最前面のPDFで連続して同じページが存在するかチェック.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/03/13
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—

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

script pdfStore
  property aList : {}
end script

set (aList of pdfStore) to {}

tell application "Skim"
  set dCount to count every document
  
if dCount = 0 then return
  
  
tell front document
    set myPath to path
    
set pCount to count every page
  end tell
end tell

set anNSURL to (current application’s |NSURL|’s fileURLWithPath:myPath)
set theDoc to current application’s PDFDocument’s alloc()’s initWithURL:anNSURL

repeat with i from 0 to (pCount – 1)
  set aPage to (theDoc’s pageAtIndex:i)
  
set tmpStr to (aPage’s |string|())
  
set the end of (aList of pdfStore) to (tmpStr as string)
end repeat

set resList to {}
repeat with i from 1 to (pCount – 1)
  set aText1 to contents of item i of (aList of pdfStore)
  
set aText2 to contents of item (i + 1) of (aList of pdfStore)
  
  
if aText1 = aText2 then
    set the end of resList to {i, i + 1}
  end if
end repeat

if resList is equal to {} then
  display notification "PDFに重複ページは見られませんでした。"
else
  set aText to listToText(resList) of me
  
set the clipboard to aText
  
display dialog "重複ページ:" default answer aText with icon 1 buttons {"OK"} default button 1
end if

on listToText(aList)
  set listText to {"{"}
  
set quotChar to ASCII character 34
  
set firstFlag to true
  
  
repeat with i in aList
    set j to contents of i
    
set aClass to class of i
    
if (aClass = integer) or (aClass = number) or (aClass = real) then
      set the end of listText to (getFirst(firstFlag) of me & j as text)
      
set firstFlag to false
    else if (aClass = string) or (aClass = text) or (aClass = Unicode text) then
      set the end of listText to ((getFirst(firstFlag) of me & quotChar & j as text) & quotChar)
      
set firstFlag to false
    else if aClass is list then
      set the end of listText to (getFirst(firstFlag) of me & listToText(j)) –ちょっと再帰処理
      
set firstFlag to false
    end if
  end repeat
  
  
set the end of listText to "}"
  
set listText to listText as text
  
  
return listText
end listToText

on getFirst(aFlag)
  if aFlag = true then return ""
  
if aFlag = false then return ","
end getFirst

★Click Here to Open This Script 

Posted in PDF | Tagged 10.14savvy 10.15savvy 11.0savvy Skim | Leave a comment

Mac App Storeで「White Pages」を販売開始

Posted on 9月 12, 2020 by Takaaki Naganoya

例によってAppleScriptで開発したアプリケーション「White Pages」のMac App Storeでの販売を開始しました。macOS 10.13以降に対応しています。

PDFの空白ページを削除・出力するアプリケーションです。空白ページの検出のため、全ページを画像にレンダリングして、空白判定。空白判定には速度と精度で定評のある空白画像検出ルーチンを使用しています。

決して、ページごとに文字の有無を判断するだけのソフト(Fredrik Method)ではありません。それだと、グラフィックだけのページを「空白」と判定してしまいますので。

アイコンは、macOS 11.0, Big Surに合わせた形状。手の色を赤くしているのは、何らかの特定の人種を想起させるような塗り色を避けたためです。

Posted in PDF PRODUCTS | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy | Leave a comment

PDFにパスワードが設定されている場合には、そのパーミッション情報を取得する

Posted on 8月 31, 2020 by Takaaki Naganoya

指定のPDFをチェックし、オープンするのにパスワードが設定されているとか、コピーが禁止されていないかといったパーミッションを調査するAppleScriptです。

API Lebel in this script Desc
(no api) openPermission document allows opening
allowsCopying copyPermission document allows copying of content to the Pasteboard
allowsPrinting printPermission document allows printing
allowsCommenting commentPermission document allows to create or modify document annotations, including form field entries
allowsContentAccessibility contentAccessPermission document allows to extract content from the document
allowsDocumentAssembly assemblyPermission document allows manage a document by inserting, deleting, and rotating pages
allowsDocumentChanges docchangePermission document allows modify the document contents except for document attributes
allowsFormFieldEntry formPermission document allows modify form field entries even if you can’t edit document annotations

PDFのオープン自体にパスワードロックがかかっている状態を検出するAPIがとくになかったので、いろいろ試行錯誤してOpenをロックしてある状態を検出してみました。

検出は、パスワード未指定でUnlockを試みるというもので、実際にパスワードを設定したPDFを相手に試行錯誤して求めてみました。

このUnlock操作に対してfalseが返ってくることでPDFオープンに対してパスワードが設定されているものと判断しています。

AppleScript名:PDFにパスワードが設定されている場合には、そのパーミッション情報を取得する
— Created 2015-11-02 13:48:32 +0900 by Takaaki Naganoya
— 2015 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "QuartzCore"

set aPath to (choose file of type {"com.adobe.pdf"} with prompt "Select PDF to check")

set aRes to my retProtectedPDFPermissions(aPath)
–>  missing value (パスワードは設定されていない)

–> {openPermission:false, copyPermission:true, printPermission:true, commentPermission:true, contentAccessPermission:true, assemblyPermission:true, docchangePermission:true, formPermission:true}–オープンするためにはパスワードが必要(openPermission)

–指定のPDFにパスワードが設定されているかどうかをチェック
on retProtectedPDFPermissions(aPath)
  set aURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of aPath)
  
set aPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL
  
set anEncF to aPDFdoc’s isEncrypted()
  
if anEncF = false then return missing value
  
  
set passLocked to aPDFdoc’s unlockWithPassword:""
  
  
set cpPerm to aPDFdoc’s allowsCopying() as boolean
  
set prPerm to aPDFdoc’s allowsPrinting() as boolean
  
set cmPerm to aPDFdoc’s allowsCommenting() as boolean
  
set caPerm to aPDFdoc’s allowsContentAccessibility() as boolean
  
set daPerm to aPDFdoc’s allowsDocumentAssembly() as boolean
  
set dcPerm to aPDFdoc’s allowsDocumentChanges() as boolean
  
set ffPerm to aPDFdoc’s allowsFormFieldEntry() as boolean
  
  
return {openPermission:passLocked, copyPermission:cpPerm, printPermission:prPerm, commentPermission:cmPerm, contentAccessPermission:caPerm, assemblyPermission:daPerm, docchangePermission:dcPerm, formPermission:ffPerm}
end retProtectedPDFPermissions

★Click Here to Open This Script 

Posted in file PDF | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy NSURL PDFDocument | Leave a comment

iWork Appがv10.1にアップデートし、Movie書き出しバグの修正とPDF書き出し属性を追加

Posted on 7月 10, 2020 by Takaaki Naganoya

iWorkアプリケーション(Keynote、Numbers、Pages)がアップデートされてv10.1になりました。対象はmacOS 10.14/10.15。

AppleScript系ではバグ修正1点と、機能追加が1点あります。

Keynoteのムービー書き出しオプション(native size)バグ修正

Keynote v10.0の際のアホなバグ(native size指定時にエラー)が修正されました。

AppleScript名:native sizeでムービー書き出し
set outFile to (path to desktop as string) & (do shell script "uuidgen") & ".m4v"

tell application "Keynote"
  tell front document
    export to file outFile as QuickTime movie with properties {class:export options, movie format:native size}
  end tell
end tell

★Click Here to Open This Script 

PDF書き出しオプション(include comments)を追加

また、3アプリケーション共通でPDF書き出し時に「include comments」オプションが指定できるようになりました。


▲include comments属性が追加された


▲Keynote書類に追加した「コメント」


▲KeynoteのGUI上で指定する「コメントを含める」チェックボックス


▲上がinclude comments:falseで書き出したPDF、下がinclude comments:trueで書き出したPDF

AppleScript名:Keynote書類からPDF書き出し v3(10.10対応)
— Created 2017-01-21 by Takaaki Naganoya
— Modified 2020-07-10 by Takaaki Naganoya
— 2017-2020 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set tmpPath to (path to desktop) as string
set aRes to exportKeynoteDocToPDF(tmpPath)

–Keynote書類からPDF書き出し
on exportKeynoteDocToPDF(targFolderPath as string)
  
  
tell application "Keynote"
    set dCount to count every document
    
if dCount = 0 then
      return false
    end if
    
set aPath to file of document 1
  end tell
  
  
set curPath to (current application’s NSString’s stringWithString:(POSIX path of aPath))’s lastPathComponent()’s stringByDeletingPathExtension()’s stringByAppendingString:".pdf"
  
set outPath to (targFolderPath & curPath)
  
  
tell application "Keynote"
    –v10.10で追加されたinclude comments属性の指定を追加してみた
    
set anOpt to {class:export options, export style:IndividualSlides, all stages:false, skipped slides:true, PDF image quality:Best, include comments:false}
    
export document 1 to file outPath as PDF with properties anOpt
  end tell
  
  
return (outPath as alias)
  
end exportKeynoteDocToPDF

★Click Here to Open This Script 

iWorkアプリケーションのAppleScript系機能に望むこと

・slide上の選択中のオブジェクトを扱えるようにしてほしい(selected itemといった予約語で)
・縦書きテキストの制御機能がほしい(強引に作ったけど)
・TOCつきPDFが直接書き出せるように(自分で作ったけど)
・Pagesをなんとかして。レイアウトをScriptから再現できない

Posted in Bug PDF | Tagged 10.14savvy 10.15savvy 11.0savvy Keynote | Leave a comment

指定のPDFからTOCを削除する

Posted on 6月 19, 2020 by Takaaki Naganoya

指定のPDFからTOCを削除して別名保存するAppleScriptです。

TOCを削除した新規ファイルは元ファイルと同じ場所に枝番つきで重複回避しつつ作成されます。

33MBで257ページほどあるPDFで、詳細に目次から記事へのリンクを手動で作成し、TOCを手動で作ったところ、Adobe Actobatが、

などというメッセージを出して保存ができなかったので、中途半端に1個だけエントリが残ったTOCを削除するために用意したものです(既存のScriptに機能があったので、削除機能だけ抽出)。

AppleScript名:指定のPDFからTOCを削除する.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/08/18
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "Quartz"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property PDFDocument : a reference to current application’s PDFDocument
property NSFileManager : a reference to current application’s NSFileManager

–PDFの指定
set aFile to choose file of type {"pdf"} with prompt (progress additional description)
set filePath to aFile’s POSIX path

set fileURL to |NSURL|’s fileURLWithPath:filePath
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:fileURL
set parentOL to aPDFdoc’s outlineRoot()

if parentOL is equal to missing value then
  display dialog "There is no TOC with this PDF"
  
return
end if

set outLineCount to parentOL’s numberOfChildren()
set outLineCount to outLineCount as number

–既存のTOCを削除
repeat with num from (outLineCount – 1) to 0 by -1
  (parentOL’s childAtIndex:num)’s removeFromParent()
end repeat

–保存
set progress description to "PDFを保存"
set progress additional description to "保存先の確認"
tell (NSString’s stringWithString:filePath)
  set parentPath to stringByDeletingLastPathComponent() –>親フォルダ
  
set longFileName to lastPathComponent() –>拡張子ありの名前
end tell
set newFilePath to my pathExists(parentPath, longFileName)

set progress additional description to "書き出し中: " & newFilePath
set newFileURL to |NSURL|’s fileURLWithPath:newFilePath
aPDFdoc’s writeToURL:newFileURL

–名前が重複していないか確認
on pathExists(currentPath as text, fileName as text)
  tell (NSString’s stringWithString:fileName)
    set shortFileName to stringByDeletingPathExtension() as text
    
set aSuffix to pathExtension() as text
  end tell
  
if aSuffix ≠ "" then set aSuffix to "." & aSuffix as text
  
  
set currentPath to NSString’s stringWithString:currentPath
  
set unkonwnPath to (currentPath’s stringByAppendingPathComponent:fileName)
  
  
set aSpace to space
  
set num to 0
  
  
repeat while ((NSFileManager’s defaultManager)’s fileExistsAtPath:unkonwnPath)
    set num to num + 1
    
set tmpName to shortFileName & aSpace & num & aSuffix as text
    
set unkonwnPath to (currentPath’s stringByAppendingPathComponent:tmpName)
  end repeat
  
  
return (unkonwnPath as text)
end pathExists

★Click Here to Open This Script 

Posted in file PDF | Tagged 10.13savvy 10.14savvy 10.15savvy NSFileManager NSString NSURL PDFDocument | Leave a comment

PDFにウォーターマーク画像を重ね合わせる2

Posted on 6月 4, 2020 by Takaaki Naganoya

指定のPDFにウォーターマークのPDFを重ね合わせるAppleScriptです。

これまでにもいろいろ試してきたのですが、不可能ではないものの、再配布が難しかったりアプリケーションに依存していたりで、決定版とはなっていませんでした。

macscripter.netにpeavine氏が投稿したScriptが元になっています。同氏のScriptではcpdfというコマンドラインツールが用いられており、これがなかなかいい感じです。実行時には、cpdfが/usr/local/binに入っている必要があります。Script Bundleの中に入れて呼び出してもよさそうです。

いい感じではあるものの、商用利用は許可されていないとのこと(要、購入)なので、商用利用時にはライセンスを購入すべきでしょう。再配布もできない雰囲気なので、自分のアプリケーション内に入れて呼び出すとかいうのは無理です。

ファイルの複数選択に、自分で作った「choosePathLib」を用いています。NSPathControlにドラッグ&ドロップできるファイル種別を限定できるように作っておけばよかった、と反省しまくりました。

Watermark画像をPDFに重ね合わせる処理については、こういう外部ツールを併用しないでAppleScriptだけで済めばベストですが、、、、


▲オリジナルPDF


▲WatermarkのPDF。背景色に透明を指定している


▲処理対象ファイル選択


▲処理後のPDF。Watermarkが各ページに重ね合わされていることがわかる


▲処理後のPDFにはPDF Creator情報にcpdfのCopyrightが記入される

AppleScript名:PDFにウォーターマーク画像を重ね合わせる2
—
–  Created by: peavine @macscripter.net
–  Created on: 2020/06/04
–  Modified by: Takaaki Naganoya @ Piyomaru Software
–  cpdf
–  https://community.coherentpdf.com

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use pLib : script "choosePathLib" –http://piyocast.com/as/asinyaye

set mesList to {"Logo PDF", "Source PDF"}
set defaultLocList to {"~/Movies", "~/Desktop"}

set cRes to choose multiple path main message "Drag & Drop to set target" sub message "" with titles mesList with default locations defaultLocList dialog width 800

set outFile to POSIX path of (choose file name with prompt "Select Output PDF File name")

copy cRes to {logoFile, sourceFile}

set logoFile to POSIX path of logoFile
set sourceFile to POSIX path of sourceFile

–check file extension = file type
if logoFile does not end with ".pdf" then error "Logo path is not pdf"
if sourceFile does not end with ".pdf" then error "Source file is not pdf"
if outFile does not end with ".pdf" then error "output path is not pdf"

try
  do shell script "/usr/local/bin/cpdf -stamp-on " & quoted form of logoFile & " -center " & quoted form of sourceFile & " -o " & quoted form of outFile
end try

★Click Here to Open This Script 

Posted in dialog file PDF | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

Previewで現在表示中のPDFのページ番号を抽出する

Posted on 4月 29, 2020 by Takaaki Naganoya

macOS標準搭載の画像/PDFビューワーの「Preview.app」で表示中のPDFの、現在表示中のページの番号を取得するAppleScriptです。

本来、Preview.appのような超低機能アプリケーションから強引に情報を(GUI Scriptingまで使って)取得する意味はありません。PDFビューワーとしてまっとうな機能を持っているSkimを使って表示中のページ番号を取得するのが筋です。

ただ、どうしてもPreviewでないといけないケースで、仕方なく作ったものですが、英語環境でも日本語環境でも同様に動くために作ってみたらこんな感じに。指定アプリケーション単体で言語環境を指定して起動できると、各言語環境における動作確認が手軽に行えてよいと思うものの、手段がありそうで見つかりません(Xcode上でそういう起動ができるので、不可能ではないと思うのですが)。


▲英語環境で実行したところ(macOS 10.14.6)


▲日本語環境で実行したところ(macOS 10.15.4)

仕方なくGUI Scripting経由でウィンドウのタイトルを取得して、ファイル名とページ情報を文字列処理で分離しています。このあたり、英語環境と日本語環境でセパレータ(括弧)が異なるので、分離したページ情報から数字判定を行なって取得しています。Preview.appのアプリケーションバンドル内にこうしたフォーマットのテキストが存在していれば、そちらを使うべきです(見つかっていないので現状こんな感じで)。

GUI Scripting内でプロセス名を指定する箇所で、ローカライズされたプロセス名をCocoaの機能を用いて取得しています。これで、英語環境と日本語環境については問題なく共通Scriptでカバーできています。

AppleScript名:Previewで現在表示中のPDFのページ番号を抽出する.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/04/29
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

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

set pNum to retPreviewDispPageNumber() of me

on retPreviewDispPageNumber()
  set aLocName to getLocalizedName("com.apple.Preview") of me
  
  
tell application "Preview"
    if (count every document) = 0 then return false
  end tell
  
  
tell application "System Events"
    tell process aLocName
      tell window 1
        set aTitle to title
      end tell
    end tell
  end tell
  
  
set aPageInfo to pickUpFromToStr(aTitle, "(", ")") of me –English env
  
if aPageInfo = false then
    set aPageInfo to pickUpFromToStr(aTitle, "(", ")") of me –double witdh parenthesis (Japanese env)
  end if
  
set pList to words of aPageInfo
  
set hitF to false
  
repeat with i in pList
    set nRes to chkNumeric(i) of me
    
if nRes = true then
      set hitF to true
      
exit repeat
    end if
  end repeat
  
  
if hitF = false then return
  
return i as integer
end retPreviewDispPageNumber

on getLocalizedName(aBundleID as string)
  set pRes to getProcessByBUndleID(aBundleID) of me
  
if pRes = false then return ""
  
set pName to pRes’s localizedName()
  
return pName as string
end getLocalizedName

–指定プロセスを取得する
on getProcessByBUndleID(aBundleID)
  set appArray to current application’s NSRunningApplication’s runningApplicationsWithBundleIdentifier:aBundleID
  
if appArray’s |count|() > 0 then
    set appItem to appArray’s objectAtIndex:0
    
return appItem
  else
    return false
  end if
end getProcessByBUndleID

on pickUpFromToStr(aStr as string, s1Str as string, s2Str 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
  
  
return cStr as string
end pickUpFromToStr

–数字のみかチェック
on chkNumeric(checkString)
  set digitCharSet to current application’s NSCharacterSet’s characterSetWithCharactersInString:"0123456789"
  
set ret to my chkCompareString:checkString baseString:digitCharSet
  
return ret as boolean
end chkNumeric

on chkCompareString:checkString baseString:baseString
  set aScanner to current application’s NSScanner’s localizedScannerWithString:checkString
  
aScanner’s setCharactersToBeSkipped:(missing value)
  
aScanner’s scanCharactersFromSet:baseString intoString:(missing value)
  
return (aScanner’s isAtEnd()) as boolean
end chkCompareString:baseString:

★Click Here to Open This Script 

Posted in GUI Scripting PDF Text | Tagged 10.13savvy 10.14savvy 10.15savvy NSCharacterSet NSRunningApplication NSScanner Preview | Leave a comment

PDFフォームに入力して別名保存 v2

Posted on 12月 7, 2019 by Takaaki Naganoya

入力フォームつきのPDFにデータ入力して別名保存するAppleScriptです。

他のGUIアプリを操作してフォーム入力するのではなく、直接PDFKitの機能を利用してフォームPDFへの記入を行なっています。

テキスト入力フォーム、チェックボックス、コンボボックスへの入力に対処してみましたが、リストボックスの項目選択はまだ行えていません。


▲Adobe AcrobatでPDFフォームサンプルをオープンしたところ


▲本ScriptでサンプルフォームPDFを処理したところ


▲Script Debugger上で表示したPDFフォーム上の各種プロパティ。フォーム欄のタイプを名前ではなく各種属性値で判定したいところ

AppleScript名:PDFフォームに入力して別名保存(テキストフィールド、チェックボックス、コンボボックス)
— Created 2019-12-05 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

set aHFSPath to (choose file of type {"com.adobe.pdf"} with prompt "Choose a PDF with Form")
set aPOSIX to POSIX path of aHFSPath
set aURL to (|NSURL|’s fileURLWithPath:aPOSIX)

set aPDFdoc to PDFDocument’s alloc()’s initWithURL:aURL
set pCount to aPDFdoc’s pageCount()
set firstPage to (aPDFdoc’s pageAtIndex:0)

set anoList to (firstPage’s annotations()) as list
if anoList is not equal to {missing value} then –指定PDF中にAnotationが存在する場合のみ処理
  repeat with i in anoList
    set aName to (i’s fieldName()) as string
    
    
set adicList to i’s annotationKeyValues
    
set aType to (adicList’s valueForKey:"/Type") as string
    
set aSubType to (adicList’s valueForKey:"/Subtype") as string
    
set aFormType to (adicList’s valueForKey:"/FT") as string
    
    
log {aType, aSubType, aFormType}
    
if aName ends with "Text Box" then –OK
      set aState to (i’s widgetStringValue()) as string
      
      
if aState = "" then
        (i’s setWidgetStringValue:"Piyomaru")
        
set bState to (i’s widgetStringValue()) as string
      end if
      
    else if aName ends with "Check Box" then –OK
      log {"Check Box"}
      
set aState to (i’s buttonWidgetState()) as boolean
      
if aState = false then
        (i’s setButtonWidgetState:true)
        
set bState to (i’s buttonWidgetState()) as boolean
      end if
      
    else if aName ends with "Combo Box" then
      log {"Combo Box"}
      
set tmpList to (i’s choices()) as list
      (
i’s setWidgetStringValue:(contents of some item of tmpList))
      
set cVal to (i’s widgetStringValue()) as string
      
log cVal
      
    else if aName ends with "List Box" then
      log {"List Box"}
      
set tmpList to (i’s choices()) as list
      
log {"tmpList", tmpList}
      
      
–(i’s setWidgetStringValue:(contents of some item of tmpList))
      
    end if
  end repeat
end if

–PDFの保存先のファイル名を入力させる(あらかじめパス文字列を作成しておいてもよい)
set newFileName to POSIX path of (choose file name with prompt "Input File name to save")
if newFileName does not end with ".pdf" then
  set newFileName to newFileName & ".pdf"
end if

–フォーム内容を変更したPDFを指定のパスに新規保存
set pdfRes to (aPDFdoc’s writeToFile:newFileName) as boolean

★Click Here to Open This Script 

Posted in file PDF | Tagged 10.13savvy 10.14savvy 10.15savvy NSURL PDFDocument | Leave a comment

Post navigation

  • Older posts

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

Google Search

Popular posts

  • macOS 14, Sonoma
  • macOS 13.6.5 AS系のバグ、一切直らず
  • PowerPoint書類の各スライドのタイトルを取得
  • Apple純正マウス、キーボードのバッテリー残量取得
  • 指定画像をbase64エンコード文字列に変換→デコード
  • CotEditorで2つの書類の行単位での差分検出
  • 出るか?「AppleScript最新リファレンス」のバージョン2.8対応版
  • macOS 14の変更がmacOS 13にも反映
  • Finder上で選択中のPDFのページ数を加算
  • Cocoa-AppleScript Appletランタイムが動かない?
  • macOS 13 TTS環境の変化について
  • 与えられた文字列の1D Listのすべての順列組み合わせパターン文字列を返す v3(ベンチマーク用)
  • 当分、macOS 14へのアップデートを見送ります
  • macOS 14、英語環境で12時間表記文字と時刻の間に不可視スペースを入れる仕様に
  • ディスプレイをスリープ状態にして処理続行
  • HammerspoonでLuaを実行
  • 新刊発売 AppleScript最新リファレンス v2.8対応
  • PowerPointで最前面の書類をPDF書き出し
  • macOS 14, Sonoma 9月27日にリリース
  • Adobe AcrobatをAppleScriptから操作してPDF圧縮

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1390) 10.14savvy (586) 10.15savvy (434) 11.0savvy (278) 12.0savvy (195) 13.0savvy (97) 14.0savvy (42) CotEditor (62) Finder (48) iTunes (19) Keynote (105) NSAlert (60) NSArray (51) NSBezierPath (18) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (51) NSDictionary (27) NSFileManager (23) NSFont (18) NSImage (41) NSJSONSerialization (21) NSMutableArray (62) NSMutableDictionary (21) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (117) NSURL (97) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (59) Pages (44) Safari (41) Script Editor (23) 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
  • Clipboard
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • diff
  • drive
  • 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
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • parallel processing
  • PDF
  • Peripheral
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • rectangle
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 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