Archive for the 'PDFDocument' Category

2017/10/21 macOS 10.13でPDFViewのcurrentPageにバグ

macOS 10.13上のPDFViewのcurrentPageメソッドにバグを見つけたものの、Appleに報告しても直しもしなさそうなので困っているという話です。

PDF表示部品であるPDFViewというクラスがあり、非常に便利に使っています。

pdfv1.png

PDFViewには、

pdfv2.png

currentPageというメソッドがあり、これを通じて「現在表示中のPDFの現在位置のページのオブジェクト(PDFPage)」を返してくれるようになっている

pdfv3.png

pdfv5.png

はずなんですが!!!(^ー^;;;

macOS 10.13でAppleScriptでcurrentPageを取得すると、PDFPageオブジェクトではなく謎の数値が返ってきます(ーー;;;

■macOS 10.12.6
2017-10-21 16:58:20.255660+0900 PDFViewTest[45351:95940914] <pdfpage : 0×600000414120>

■macOS 10.13.1(Build 17B35a)
2017-10-21 16:57:00.664314+0900 PDFViewTest[6109:764273] 105827998483136

前からそうですが、macOS 10.13あたりから露骨に、Appleにバグを直す気がないというか品質管理に関心がないという雰囲気なので、レポートしたところで直る見込みがあるんだかないんだか不明な今日このごろです。

このバグがAppleScriptから呼び出すとバグを発生するのか、Objective-CやSwiftでも同様なのか、問題の切り分けをCocoa勉強会で呼びかけて話をしていますが、どんなもんなんでしょうか。
→ Swiftで確認していただきました。Swiftでは問題ないとのこと。ScriptingBridgeなのか、、、、今回問題多いな、、、(ーー;;;

とりあえず、currentPageで現在表示中のページを取得して管理する方式ではなく、アプリケーション側で現在表示中のページを管理する方式に変更すれば、このバグをAppleが放置しても回避できるだろうか、といったところです。

スクリプト名:pdfviewtest.html

– AppDelegate.applescript
– PDFViewTest

– Created by 長野谷 隆昌 on 2017/10/20.
– Copyright © 2017年 Piyomaru Software. All rights reserved.

script AppDelegate
  
property parent : class “NSObject”
  
  
– IBOutlets
  
property theWindow : missing value
  
property tf1 : missing value–NSTextField
  
property leftPDF : missing value–PDFView
  
  
  
on applicationWillFinishLaunching:aNotification
    

  
end applicationWillFinishLaunching:
  
  
  
on applicationShouldTerminate_(sender)
    
return current application’s NSTerminateNow
  
end applicationShouldTerminate:
  
  
  
– click event handler
  
on clicked:aSender
    
set aTag to (tag of aSender) as integer
    
if aTag = 100 then
      
set aPOSIX to POSIX path of (choose file)
      
      
set aURL to current application’s |NSURL|’s fileURLWithPath:aPOSIX
      
      
set newPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL
      
log newPDFdoc
      
–> –10.12.6
      
      
set leftTotalPage to newPDFdoc’s pageCount()
      
      leftPDF’s setDocument:newPDFdoc
      leftPDF’s setAutoScales:
true
      leftPDF’s setDisplaysPageBreaks:
true
      leftPDF’s goToFirstPage:(
missing value)
      
      
set curPage to (leftPDF’s currentPage())—–This method “currentPage”
      
log curPage
      
–> –10.12.6
      
      
set firstPage to (newPDFdoc’s pageAtIndex:0)’s label as string
      
log firstPage
      
    
end if
    
  
end clicked:
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2017/09/29 macOS 10.13で変更されたPDFアノテーションの作成

macOS 10.13, High Sierraで変更になった、PDF書類へのアノテーション作成を行うAppleScriptです。

とくにサンプルプログラムが見当たらなかったのですが、「まあこんなもんだろー」とあたりをつけて書いてみたら動きました。Objective-CのコードもSwiftのコードも見当たらず、いまのところPDFアノテーション作成コードはこのAppleScriptしか見当たらない状態、、、、、、

選択したPDFに対してアノテーションを追加します。自分は動作検証用に作っためもり入りの「方眼紙PDF」に対してアノテーションを追加してみました(掲載スクリーンショット)。PDFの座標系は左下が原点です。

AppleがmacOS 10.13に作ったScripting BridgeのNSRectの変換ミス(?)のバグに対処してあります。恥かしいレベルのバグだし、まいどまいど腹がたつのでさっさと修正してほしいのですが、いつごろ修正されるものやら。予想以上に今回のバグの被害範囲が広いので、さっさと修正してほしいものです(指定写真の顔の部分をエリア検出してフィルタをかけるといった処理が途中でエラーに。ものすごく腹立たしい)。

circle_annotation_resized.png

従来の書き方でもまだ動くので、今日明日ですぐに切り替えが必要になるわけではなさそうです。

新しい書き方のほうが単純で、さまざまなアノテーションでもだいたい同様に記述できるので、個人的にはこちらのほうがいい感じがします。

→ 指定PDFの最初のページに大量のスクウェアアノテーションを添付する

→ 指定PDFの最初のページにアノテーションを追加する(テキストアノテーション)

AppleScript名:指定PDFの最初のページにサークルアノテーションを追加する(High Sierra)
– Created 2017-09-27 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.7″ –macOS 10.13 or later
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “AppKit”
–http://piyocast.com/as/archives/4855

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

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

–macOS 10.13以降で指定する形式のAnnotation
set keyList to {current application’s PDFAnnotationKeyColor, current application’s PDFAnnotationKeyInteriorColor}
set valList to {current application’s NSColor’s blackColor(), current application’s NSColor’s grayColor()}
set propDict to current application’s NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList

–macOS 10.13のバグ対策。NSRectはwidth–>heightの順にパラメータを並べる
set anAnnotation to current application’s PDFAnnotation’s alloc()’s initWithBounds:{origin:{x:100, y:100}, |size|:{width:600, height:600}} forType:(current application’s PDFAnnotationSubtypeCircle) withProperties:propDict

firstPage’s addAnnotation:anAnnotation

aPDFdoc’s writeToFile:aPOSIX

★Click Here to Open This Script 

square_annotation_resized.png

AppleScript名:指定PDFの最初のページにスクウェアアノテーションを追加する(High Sierra)
– Created 2017-09-27 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.7″ –macOS 10.13 or later
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “AppKit”
–http://piyocast.com/as/archives/4855

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

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

–macOS 10.13以降で指定する形式のAnnotation
set keyList to {current application’s PDFAnnotationKeyColor, current application’s PDFAnnotationKeyInteriorColor}
set valList to {current application’s NSColor’s blackColor(), current application’s NSColor’s grayColor()}
set propDict to current application’s NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList

–macOS 10.13のバグ対策。NSRectはwidth–>heightの順にパラメータを並べる
set anAnnotation to current application’s PDFAnnotation’s alloc()’s initWithBounds:{origin:{x:100, y:100}, |size|:{width:500, height:500}} forType:(current application’s PDFAnnotationSubtypeSquare) withProperties:propDict

firstPage’s addAnnotation:anAnnotation

aPDFdoc’s writeToFile:aPOSIX

★Click Here to Open This Script 

text_annotation_resized.png

AppleScript名:指定PDFの最初のページにテキストアノテーションを追加する(High Sierra)
– Created 2017-09-27 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.7″ –macOS 10.13 or later
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “AppKit”
–http://piyocast.com/as/archives/4855

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

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

–macOS 10.13以降で指定する形式のAnnotation
set keyList to {current application’s PDFAnnotationKeyInteriorColor, current application’s PDFAnnotationKeyContents}
set valList to {current application’s NSColor’s yellowColor(), “Piyomaru Software” & return & “ぴよまるソフトウェア”}
set propDict to current application’s NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList

–macOS 10.13のバグ対策。NSRectはwidth–>heightの順にパラメータを並べる
set anAnnotation to current application’s PDFAnnotation’s alloc()’s initWithBounds:{origin:{x:100, y:100}, |size|:{width:200, height:50}} forType:(current application’s PDFAnnotationSubtypeFreeText) withProperties:propDict

firstPage’s addAnnotation:anAnnotation

aPDFdoc’s writeToFile:aPOSIX

★Click Here to Open This Script 

line_annotation_resized.png

AppleScript名:指定PDFの最初のページにラインアノテーションを追加する(High Sierra)
– Created 2017-09-27 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.7″ –macOS 10.13 or later
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “AppKit”
–http://piyocast.com/as/archives/4855

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

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

–macOS 10.13以降で指定する形式のAnnotation
set keyList to {current application’s PDFAnnotationKeyColor}
set valList to {current application’s NSColor’s blackColor()}
set propDict to current application’s NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList

–macOS 10.13のバグ対策。NSRectはwidth–>heightの順にパラメータを並べる
set anAnnotation to current application’s PDFAnnotation’s alloc()’s initWithBounds:{origin:{x:100, y:100}, |size|:{width:600, height:600}} forType:(current application’s PDFAnnotationSubtypeLine) withProperties:propDict

firstPage’s addAnnotation:anAnnotation

aPDFdoc’s writeToFile:aPOSIX

★Click Here to Open This Script 

2017/09/06 ツイ4のページで新規連載マンガの画像を取得してPDF化(新規連載のPDF化)v3

Safariで表示中のWebマンガサイト「ツイ4」(更新情報をTwitterに投稿)のマンガを全エピソードダウンロードしてPDFにまとめるAppleScriptです。

実行にあたってはShane StanleyのAppleScript Libraries「BridgePlus」のインストールを必要とします(~/ibrary/Script Librariesフォルダに入れるだけ)。

実行開始時にはSafariでツイ4の特定のマンガのページをオープンしている必要があります。

tui4.png

Safariの最前面のウィンドウからURLやTitle、リンクされている画像の詳細情報を取得し、条件チェックなどを行なったのちに詳細なデータの抽出を行います。

次に、PDFの保存先を選択するダイアログを表示。このさい、デフォルトの保存先を「ピクチャ」フォルダ、ファイル名をマンガのタイトルに指定。

ページにリンクされていた画像(ツイではファイル名はシーケンシャル番号)から番号の情報だけを抽出して最大値、最小値を計算。この範囲で画像のダウンロード、PDFへの追記を行います。ただし、実運用してみたところ、Safariからすべての画像を取得できないようで(非同期表示しているようなので)、とりあえず1〜9999までの番号の画像を順次ダウンロードし、画像が存在しなければ処理を終了しています。

画像をダウンロードするたびにPDFに追記していますが、このあたりは途中でエラーが出て停止してもそれまでの処理内容が保存されることを意図してのことです。SSD搭載機では問題のない処理ですが、HDD搭載機では若干遅く感じるかもしれません(もはやHDD搭載機が身の回りにないので不明)。

これまでは、マンガの新規連載がはじまるとcurlコマンドで画像をダウンロードしてPDFに連結する作業を手で行なっていたのですが(誰も頼んでねえよ)、新規連載が増えたので自動化してみました。それでもありあわせの部品を組み合わせただけなので、それほど手間はかかっていません。

本Scriptとは別に更新された差分をPDFに連結するAppleScriptを作って日々実行し、大きな画面でブラウズするのに役立てています。割とこういう、ごくごく私的なScriptで野心的な処理を先行してテストしているものです。

AppleScript名:ツイ4のページで新規連載マンガの画像を取得してPDF化(新規連載のPDF化)v3
– Created 2016-09-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “QuartzCore”
use BridgePlus : script “BridgePlus”
–http://piyocast.com/as/archives/4808

property SMSForder : a reference to current application’s SMSForder
property |NSURL| : a reference to current application’s |NSURL|
property NSURLRequest : a reference to current application’s NSURLRequest
property NSURLConnection : a reference to current application’s NSURLConnection
property NSArray : a reference to current application’s NSArray
property NSFileManager : a reference to current application’s NSFileManager
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
property NSPredicate : a reference to current application’s NSPredicate
property PDFPage : a reference to current application’s PDFPage
property PDFDocument : a reference to current application’s PDFDocument
property NSURLRequestUseProtocolCachePolicy : a reference to current application’s NSURLRequestUseProtocolCachePolicy
property NSNumberFormatterPadBeforePrefix : a reference to current application’s NSNumberFormatterPadBeforePrefix
property NSImage : a reference to current application’s NSImage
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSNumber : a reference to current application’s NSNumber
property NSRegularExpressionDotMatchesLineSeparators : a reference to current application’s NSRegularExpressionDotMatchesLineSeparators
property NSRegularExpressionAnchorsMatchLines : a reference to current application’s NSRegularExpressionAnchorsMatchLines
property NSRegularExpression : a reference to current application’s NSRegularExpression
property NSString : a reference to current application’s NSString

property theTargetSite : “http://sai-zen-sen.jp/”

tell application “Safari”
  if (count every document) = 0 then
    display notification “Safari does not open web page”
    
return
  end if
  
  
set docTitle to (do JavaScript “document.title” in front document) –Title
  
  
tell front document –URL
    set aURL to URL
  end tell
end tell

if aURL does not start with theTargetSite then
  display notification “This site is not the target”
  
return
end if

–Safariの最前面のウィンドウから画像リンクをすべて取得(Height, Width, URL)
set aList to getImageSizeAndURLOfFrontSafariDocument() of me

–取得した画像情報の2D Listをサイズで降順ソート
load framework –Force loading BridgePlus framework
set sortIndexes to {0, 1} –Key Item id: begin from 0
set sortOrders to {false, false}
set sortTypes to {“compare:”, “compare:”}
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:sortIndexes ascending:sortOrders sortTypes:sortTypes |error|:(missing value))

–画像が取得できなかったら処理終了
if (resList as list) = {} then
  display notification “There is no images on this page”
  
return –No Result
end if

–最大サイズの画像情報を取得する(おそらくマンガ)
set {maxHeight, maxWidth, maxURL} to contents of first item of (resList as list)

set aNSURL to |NSURL|’s URLWithString:maxURL
set aNSURLfilename to (aNSURL’s lastPathComponent())
set aNSURLpure to aNSURL’s URLByDeletingLastPathComponent()
set aNSURLextension to aNSURLfilename’s pathExtension() as string
set aNSURLfilenameLen to (aNSURLfilename’s stringByDeletingPathExtension())’s |length|() as integer –画像ファイル名から拡張子を除去した部分の文字列長

–画像情報リストを画像サイズで抽出
set maxHeightStr to (maxHeight as integer) as string
set maxWidthStr to (maxWidth as integer) as string
set thePred to NSPredicate’s predicateWithFormat:(“(self[0] == “ & maxHeightStr & “) AND (self[1] == “ & maxWidthStr & “)”)
set bArray to (resList’s filteredArrayUsingPredicate:thePred) as list

–URLからファイル名の数値部分のみ抽出
set imageArray to current application’s NSMutableArray’s new()
repeat with i in bArray
  set j to contents of last item of i –(Image URL)
  
set aTmpURL to (|NSURL|’s URLWithString:j)
  
set aTmpfilename to (aTmpURL’s lastPathComponent()) as string
  
set numStr to first item of (my findPattern:(“^\\d{1,” & (aNSURLfilenameLen as string) & “}”) inString:aTmpfilename)
  
set jj2 to (SMSForder’s transformedFrom:numStr ICUTransform:“Fullwidth-Halfwidth” inverse:false) as integer
  (
imageArray’s addObject:jj2)
end repeat

–ファイル名から抽出した数値の最小値と最大値を求める。ただ、実運用したらWeb側から画像をすべて取得されない(非同期読み込みを行なっているらしい)ケースがあったため、ここの値は参考値程度にしか使えなかった
set maxRes to (imageArray’s valueForKeyPath:“@max.self”)’s intValue() –最大値
set minRes to (imageArray’s valueForKeyPath:“@min.self”)’s intValue() –最小値
log {minRes, maxRes}

–PDFのファイル名と場所をユーザーに確認
set pdfFile to (choose file name with prompt “Select PDF Name & Location” default location (path to pictures folder) default name (docTitle & “.pdf”))
set pdfFilePOSIX to POSIX path of pdfFile
set newFilePath to current application’s NSString’s stringWithString:pdfFilePOSIX

–Make Blank PDF
set aPDFdoc to PDFDocument’s alloc()’s init()

–Download each image and append to blank PDF
set insCount to 1 –画像ダウンロード用のページ数(Loop Counter)とPDF連結用のページ番号(insCount)を分離

–repeat with i from minRes as integer to maxRes as integer
repeat with i from 1 to 9999
  –URL部品の連結
  
set aFILENAME to numToZeroPaddingStr(i, aNSURLfilenameLen, “0″) of me
  
set aFULLURL to (aNSURLpure’s absoluteString() as string) & (aFILENAME as string) & “.” & (aNSURLextension as string)
  
set aURL to (|NSURL|’s URLWithString:aFULLURL)
  
  
–URL(画像)をダウンロード
  
set {uRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me
  
  
if uRes = true then
    display notification “Episode “ & (i as string) & ” exists…”
    
set bImage to (NSImage’s alloc()’s initWithData:aData)
    (
aPDFdoc’s insertPage:(PDFPage’s alloc()’s initWithImage:bImage) atIndex:(insCount - 1))
    (
aPDFdoc’s writeToFile:newFilePath) –1Page更新するたびにファイル保存
    
set changedF to true –PDFにページが追記されたことを検出
  else
    display notification “No more new episode….”
    
exit repeat
  end if
  
  
set insCount to insCount + 1
end repeat

–FinderコメントにURLを記入
tell application “Finder”
  set comment of (pdfFile as alias) to (aNSURLpure’s absoluteString() as string)
end tell

–生成したPDFをオープン。ビューワー経由ではなくFinder経由でopen命令を送って表示
tell application “Finder”
  open (pdfFile as alias)
end tell
–ここで処理終了

—————

on getImageSizeAndURLOfFrontSafariDocument()
  set aList to {}
  
  
tell application “Safari”
    if its running then
      if (count every document) = 0 then return {}
      
set aRes to (do JavaScript “document.images.length” in front document)
      
      
repeat with i from 0 to (aRes - 1)
        set aHeight to do JavaScript ((“document.images[” & i as string) & “].height”) in front document
        
set aWidth to do JavaScript ((“document.images[” & i as string) & “].width”) in front document
        
set aSRC to do JavaScript ((“document.images[” & i as string) & “].src”) in front document
        
set the end of aList to {aHeight, aWidth, aSRC}
      end repeat
    end if
  end tell
  
  
return aList
end getImageSizeAndURLOfFrontSafariDocument

on findPattern:thePattern inString:theString
  set theOptions to ((NSRegularExpressionDotMatchesLineSeparators) as integer) + ((NSRegularExpressionAnchorsMatchLines) as integer)
  
set theRegEx to NSRegularExpression’s regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
  
set theFinds to theRegEx’s matchesInString:theString options:0 range:{location:0, |length|:length of theString}
  
set theFinds to theFinds as list
  
set theResult to {}
  
set theNSString to NSString’s stringWithString:theString
  
  
repeat with i in theFinds
    set theRange to (contents of i)’s range()
    
set end of theResult to (theNSString’s substringWithRange:theRange) as string
  end repeat
  
return theResult
end findPattern:inString:

–1D List(文字)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DList:theList ascOrder:aBool
  set aDdesc to NSSortDescriptor’s sortDescriptorWithKey:“self” ascending:aBool selector:“localizedCaseInsensitiveCompare:”
  
set theArray to NSArray’s arrayWithArray:theList
  
return (theArray’s sortedArrayUsingDescriptors:{aDdesc}) as list
end sort1DList:ascOrder:

–整数の値に指定桁数ゼロパディングして文字列で返す
on numToZeroPaddingStr(aNum as integer, aDigit as integer, paddingChar as text)
  set aNumForm to NSNumberFormatter’s alloc()’s init()
  
aNumForm’s setPaddingPosition:(NSNumberFormatterPadBeforePrefix)
  
aNumForm’s setPaddingCharacter:paddingChar
  
aNumForm’s setMinimumIntegerDigits:aDigit
  
  
set bNum to NSNumber’s numberWithInt:aNum
  
set aStr to aNumForm’s stringFromNumber:bNum
  
  
return aStr as text
end numToZeroPaddingStr

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (NSURLRequest’s requestWithURL:aURL cachePolicy:(NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to 404
  end if
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

–指定PDFのページ数をかぞえる(10.9対応。普通にPDFpageから取得)
–返り値: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

★Click Here to Open This Script 

2017/08/19 PDFの指定ページを削除 v4(複数ページ一括指定)

指定PDF書類のうちの指定ページをまとめて削除するAppleScriptです。

ページ指定にプラスの数値を指定すると絶対ページ数、マイナスの数値を指定するとページ末尾からの相対ページ数として解釈されます。ページ削除前に削除対象のページ数をすべて絶対ページに変換しつつ、重複分を削除し、削除対象ページを降順ソートします。

常識的な範囲内では、PDFからの指定ページ削除は行えるはずです。

ただ、この程度の実装だとすべてのPDFを対象にできないので困ります。Mac App Storeで販売中のアプリ「Double PDF」ではこのあたりの問題を解決したPDF処理ルーチンを仕込んであります。

AppleScript名:PDFの指定ページを削除 v4(複数ページ一括指定)
– Modified 2017-08-19 by Takaaki Naganoya
–Original By Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4784

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

set inFile to (choose file of type {“pdf”} with prompt “Choose your PDF files:”)
set targPageList to {1, 3, 5, 7, -1, -2}

set pRes to removeSpecificPagesFromPDF(inFile, targPageList) of me

–指定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 my uniquify1DList(newList, true)
  
set t2List to my sort1DNumList:t1List ascOrder:false
  
  
return t2List
end relativeToAbsNumList

on absNum(q)
  if q is less than 0 then set q to -q
  
return q
end absNum

–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 sort1DNumList:theList ascOrder:aBool
  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 sort1DNumList:ascOrder:

★Click Here to Open This Script 

2017/08/19 PDFの指定ページを削除 v3(PDFDocument経由でアクセス)

指定PDF書類のうちの指定ページを削除するAppleScriptです。

以前、PDFKit中の機能のうち指定ページ(PDFPage)を削除するものがPDFPageに見つからなかったので、新規PDFDocumentを作成して元PDFの削除対象「以外の」ページをコピーして上書き保存することで擬似的にページ削除を実現していました

ページ削除機能がないのはおかしいと考え、しつこく調べていたところ….PDFPageではなくPDFDocumetにページ削除の機能が存在することに気づきました。そのため、PDFPage経由で指定のページを削除してみたものです。

skim1.png
▲実行前

skim2.png
▲実行後(7ページ目を削除した)

AppleScript名:PDFの指定ページを削除 v3(PDFDocument経由でアクセス)
– Modified 2017-08-19 by Takaaki Naganoya
–Original By Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4781

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

set inFile to (choose file of type {“pdf”} with prompt “Choose your PDF files:”)
set targPage to 7

set pRes to removeSpecificPageInPDF(inFile, targPage) of me

on removeSpecificPageInPDF(inFileAlias, targPageNum)
  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()
  
if absNum(targPageNum) of me > pRes or targPageNum = 0 then
    error “PDF Page Range error. This PDF document has “ & (pRes as string) & ” pages. But you pointed “ & (targPageNum as string) & ” page from your script. “ & return & ” (available abs range :1…” & (pRes as string) & “, relative range: -1…-” & (pRes as string) & “)”
  end if
  
  
–Allow Relative Page Num ( -1 = the last page)
  
if targPageNum 0 then
    set targPageNum to pRes + targPageNum + 1
  end if
  
theDoc’s removePageAtIndex:(targPageNum - 1)
  
  
–Overwrite Exsiting PDF
  
set aRes to (theDoc’s writeToURL:inNSURL) as boolean
  
  
return aRes
end removeSpecificPageInPDF

on absNum(q)
  if q is less than 0 then set q to -q
  
return q
end absNum

★Click Here to Open This Script 

2017/06/18 PDFから本文テキストを抽出して配列にストアして文字列検索

指定PDFで指定キーワードを検索して、キーワードが存在するページのノンブル(数値)のリストを返すAppleScriptの改良強化版です。

最初にPDFからページ単位でテキストを抽出し、テキスト検索キャッシュを作成。このテキスト検索キャッシュに対して検索を実行し、存在しなかったらPDFに対してテキスト検索を行うようにしてみました。

最初からPDFに対してテキスト検索するよりも、テキスト抽出後に検索するほうが、複数キーワードの検索ではスピードが有利になるものと期待しています。

これで不満が出るようなら、AppleScriptで並列処理を行なって処理速度をかせぐしかないでしょう。

AppleScript名:PDFから本文テキストを抽出して配列にストアして文字列検索
– Created 2017-06-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4691

property textCache : missing value
property aList : {}

–検索対象の語群
set sList to {“notification”, “Cocoa”} –considering case

set thePath to POSIX path of (choose file of type {“com.adobe.pdf”})

–PDFのテキスト内容をあらかじめページごとに読み取って、検索用のテキストキャッシュを作成
set anNSURL to (current application’s |NSURL|’s fileURLWithPath:thePath)
set theDoc to current application’s PDFDocument’s alloc()’s initWithURL:anNSURL
set theCount to theDoc’s pageCount() as integer

set textCache to current application’s NSMutableArray’s new()

repeat with i from 0 to (theCount - 1)
  set aPage to (theDoc’s pageAtIndex:i)
  
set tmpStr to (aPage’s |string|())
  (
textCache’s addObject:{pageIndex:i + 1, pageString:tmpStr})
end repeat

–主にテキストキャッシュを対象にキーワード検索
repeat with s in sList
  
  
–❶部分一致で抽出
  
set bRes to ((my filterRecListByLabel1(textCache, “pageString contains ’” & s & “’”))’s pageIndex) as list
  
  
–❷、❶のページ単位のテキスト検索で見つからなかった場合(ページ間でまたがっている場合など)
  
if bRes = {} then
    set bRes to {}
    
set theSels to (theDoc’s findString:s withOptions:0)
    
repeat with aSel in theSels
      set thePage to (aSel’s pages()’s objectAtIndex:0)’s label()
      
set curPage to (thePage as integer)
      
if curPage is not in bRes then
        set the end of bRes to curPage
      end if
    end repeat
  end if
  
  
set the end of aList to bRes
  
end repeat

return aList

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel1(aRecList as list, aPredicate as string)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
return filteredArray
end filterRecListByLabel1

★Click Here to Open This Script 

2017/06/17 PDFでテキスト検索してキーワードの存在ページをリストで返す

指定PDFで指定キーワードを検索して、キーワードが存在するページのノンブル(数値)のリストを返すAppleScriptです。

自分の書いた本のPDFファイル(483ページ)で検索を行なってみたところ、数秒程度はかかりました。

この手の処理では、同じScriptを実行しても2回目以降もとくにスピードアップしないので、ページごとに個別にテキスト抽出しておいて、配列に対してテキスト検索するほうが高速処理できると思われます。

配列変数上でページごとに分けておいたテキストに対して検索を行い、見つからなかった場合には仕方なく本ルーチンのような処理でPDFに対してテキスト検索を行うといったところでしょうか。

AppleScript名:PDFでテキスト検索してキーワードの存在ページをリストで返す
– Created 2016-01-05 10:17:51 by Shane Stanley
– Modified 2017-06-17 by Takaaki Naganoya
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4690

set aPath to POSIX path of (choose file of type {“com.adobe.pdf”})
set aSearchKeyword to “数値のインクリメント/デクリメント”
set guardPage to 15 –検索対象から外すページ(冒頭からこのページまでを除外)
set pRes to searchPDFforString(aPath, aString, guardPage) of me
–>  {67, 78}

–指定のPDFの指定のキーワードを検索してキーワードが存在するページのリストを返す
on searchPDFforString(posixPath, aSearchKeyword, guardPage)
  set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath
  
set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL
  
  
set theSels to (thePDF’s findString:searchString withOptions:0)
  
set aList to {}
  
  
repeat with aSel in theSels
    set thePage to (aSel’s pages()’s objectAtIndex:0)’s label()
    
set curPage to (thePage as integer)
    
if curPage > guardPage then
      if curPage is not in aList then
        set the end of aList to curPage
      end if
    end if
  end repeat
  
  
return aList
end searchPDFforString

★Click Here to Open This Script 

2017/06/16 指定PDFの最初のページに大量のスクウェアアノテーションを添付する

指定PDFの最初のページに大量のスクウェアアノテーションを添付するAppleScriptです。

他のGUIアプリケーションを併用せずQuartz Frameworkの機能を利用して、PDFに対するアノテーションの添付を行います。

square_anno1.png

PDFのアノテーションまわりはmacOS 10.13で大幅に変更されているため、本Scriptがそのまま10.13上でも動作することは期待していません。

AppleScript名:指定PDFの最初のページに大量のスクウェアアノテーションを添付する
– Created 2017-06-16 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “AppKit”
–http://piyocast.com/as/archives/4688

set aHFSPath to (choose file of type {“com.adobe.pdf”} with prompt “Select PDF”)
set aPOSIX to POSIX path of aHFSPath
set aURL to (current application’s |NSURL|’s fileURLWithPath:aPOSIX)

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

set firstPage to (aPDFdoc’s pageAtIndex:0)

–Remove Annotation
my removeAnnotationFromPage:firstPage –Call by Reference

–Get PDF size by Point
set aBounds to aPage’s boundsForBox:(current application’s kPDFDisplayBoxMediaBox)
set aSize to |size| of aBounds

–Add Annotation
repeat with xNum from 30 to ((width of aSize) - 30) by 50
  repeat with yNum from 30 to ((height of aSize) - 30) by 50
    set squAnn to (current application’s PDFAnnotationSquare’s alloc()’s initWithBounds:{origin:{x:xNum, y:yNum}, |size|:{width:40, height:40}})
    (
squAnn’s setValue:(current application’s NSColor’s blueColor()) forAnnotationKey:(current application’s kPDFAnnotationKey_Color))
    (
squAnn’s setValue:(current application’s NSColor’s clearColor()) forAnnotationKey:(current application’s kPDFAnnotationKey_InteriorColor))
    (
firstPage’s addAnnotation:squAnn)
  end repeat
end repeat

–Save It
aPDFdoc’s writeToFile:aPOSIX

–Remove All Annotation from a Page. Call by Reference
on removeAnnotationFromPage:aPage
  set anoList to (aPage’s annotations()) as list
  
repeat with i in anoList
    (aPage’s removeAnnotation:i)
  end repeat
end removeAnnotationFromPage:

★Click Here to Open This Script 

2017/06/13 指定PDFの最初のページにアノテーションを追加する(テキストアノテーション)

指定のPDFの最初のページにテキストのアノテーションを追加するAppleScriptです。

だいたい想定していたとおりの処理はできているはずなんですが、Preview.app上で確認してみると想定していたのとは違う(クリックするとテキストが展開される)ので、まだいろいろ試してみないとダメっぽい感じです。

▼処理したPDFをPreview.appでオープンしたところ
pdf_ano1_resized.png

▼本AppleScriptで添付したアノテーションをクリックしたところ
pdf_ano2_resized.png

PDFのアノテーションまわりはmacOS 10.13で大幅に手が加わって変更されるので、このAppleScriptは単なるmacOS 10.10.x〜10.12.x上でのアノテーション追加実験ということになります。

AppleScript名:指定PDFの最初のページにアノテーションを追加する(テキストアノテーション)
– Created 2017-06-13 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “QuartzCore”
use framework “AppKit”
–http://piyocast.com/as/archives/4685

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

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

set textAnnotation to current application’s PDFAnnotationText’s alloc()’s initWithBounds:{origin:{x:10, y:400}, |size|:{width:200, height:100}}
textAnnotation’s setType:(current application’s PDFAnnotationTextWidget)
textAnnotation’s setValue:“/FreeText” forAnnotationKey:(current application’s kPDFAnnotationKey_Subtype)
textAnnotation’s setValue:“Hello PDF” forAnnotationKey:(current application’s kPDFAnnotationKey_Contents)
textAnnotation’s setValue:(current application’s NSColor’s yellowColor()) forAnnotationKey:(current application’s kPDFAnnotationKey_Color)

firstPage’s addAnnotation:textAnnotation

aPDFdoc’s writeToFile:aPOSIX

★Click Here to Open This Script 

2017/06/12 PDFでテキスト検索してURLリンクのアノテーションを追加する

指定のPDFで指定のテキスト(list)を検索して、URLリンク(list)のアノテーションを追加するAppleScriptです。

PDFにアノテーションを追加するAppleScriptで、他のアプリケーションを併用せずにQuartz Frameworkの機能を利用するタイプのものを探してみたら、Shane StanleyがMacScripter.netに投稿したものだけが見つかりました。一応、読みやすく清書して一部変更したのと、日本語環境で日本語を含んだPDFに対して処理検証を行なったものを掲載しています。

ただ、Objective-Cで記述したサンプルについてもほとんど見つからないので、なかなか探すのに苦労させられています。むしろ、サードパーティのフレームワーク「PSPDFkit」あたりのほうがサンプルが充実しているので、用途によってはこちらも選択肢に入ってくることでしょう。

macOS 10.13, High SierraでPDFkitに大幅に手が入るようなので、そちらの登場を待てるようであれば、10.13のPDFkitを使ってもよいでしょう。

AppleScript名:PDFでテキスト検索してURLリンクのアノテーションを追加する
– Created 2016-01-05 10:17:51 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4682

set aPath to POSIX path of (choose file of type {“com.adobe.pdf”})
set pRes to my makeLinksInPDF:aPath forStrings:{“日本語 WordNet”, “日本語WordNet”} linkURLs:{“http://compling.hss.ntu.edu.sg/wnja/”, “http://compling.hss.ntu.edu.sg/wnja/”}

–指定のPDFの指定のキーワード群に対してURL群でリンクのアノテーションを追加する
on makeLinksInPDF:posixPath forStrings:listOfSearchStrings linkURLs:listOfLinkURLStrings
  set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath
  
set thePDF to current application’s PDFDocument’s alloc()’s initWithURL:theURL
  
  
repeat with i from 1 to count of listOfSearchStrings
    
    
set searchString to item i of listOfSearchStrings
    
set linkURLString to item i of listOfLinkURLStrings
    
    
– get list of matches as PDFSelections
    
set theSels to (thePDF’s findString:searchString withOptions:0)
    
    
repeat with aSel in theSels
      set thePage to (aSel’s pages()’s objectAtIndex:0)
      
set theBounds to (aSel’s boundsForPage:thePage)
      
      
set theLink to (current application’s PDFAnnotationLink’s alloc()’s initWithBounds:theBounds) – make link with those bounds
      
set theAction to (current application’s PDFActionURL’s alloc()’s initWithURL:(current application’s |NSURL|’s URLWithString:linkURLString))
      
      (
theLink’s setMouseUpAction:theAction)
      
      
– set link’s appearance
      (
theLink’s setColor:(current application’s NSColor’s blueColor()))
      
set linkBorder to current application’s PDFBorder’s alloc()’s init()
      (
linkBorder’s setLineWidth:1.0)
      (
linkBorder’s setStyle:0)
      (
theLink’s setBorder:(linkBorder))
      (
theLink’s setShouldDisplay:true)
      
      
– add it to the page
      (
thePage’s addAnnotation:theLink)
    end repeat
  end repeat
  
  
– save the modified PDF
  
set oldName to theURL’s lastPathComponent()’s stringByDeletingPathExtension()
  
set newURL to (theURL’s URLByDeletingLastPathComponent()’s URLByAppendingPathComponent:(oldName’s stringByAppendingString:“-new”))’s URLByAppendingPathExtension:“pdf”
  
thePDF’s writeToURL:newURL
  
end makeLinksInPDF:forStrings:linkURLs:

★Click Here to Open This Script 

2017/06/09 指定PDFの最初のページからアノテーションを削除する

指定PDFの最初のページに添付されたアノテーション(Preview.app上ではマークアップと呼ばれる)を削除するAppleScriptです。

■実行前(Before)
pdf_annotation1_resized.png

■実行後(After)
pdf_annotation2_resized.png

とりあえず、指定PDFの指定ページ上のアノテーションを取得して削除できるようになりました。このあたり、もはやプログラミングではなく単なる調査です(汗)。

アノテーションを検出するScriptにも記載してあるとおり、Skimで添付したアノテーションは処理できません。Preview.appで添付したアノテーションを処理対象にしています。Preview.appで添付したアノテーションはSkimでもAdobe Acrobatでも表示が可能です。

AppleScript名:指定PDFの最初のページからアノテーションを削除する
– Created 2017-06-09 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4681

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

set aPDFdoc to current application’s 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

repeat with i in anoList
  (firstPage’s removeAnnotation:i)
end repeat

aPDFdoc’s writeToFile:aPOSIX

★Click Here to Open This Script 

2017/06/08 指定PDFの最初のページからアノテーションを取得する

指定PDFの最初のページに添付されたアノテーション(Preview.app上ではマークアップと呼ばれる)を取得するAppleScriptです。

pdf_annotation1_resized.png

とりあえず、指定PDFの指定ページ上のアノテーションを取得して種類や大きさを取得できるようになりました。

日常的に利用しているPDFビューワーとしてはオープンソースのSkimがあり、むしろPreview.appよりもこちらの方を主に利用していますが、Skimで添付したアノテーションについては保存形式が異なる(外部保存?)ようで、本Scriptでは検知できませんでした。テストにはPreview.app上で編集して任意のアノテーション(マークアップ)を追加したPDFを用意する必要があります。

PDF上の指定ページ上のアノテーションを取得することはできるようになりましたが、取得することが目的ではなく、Script側からアノテーションを作成してPDFに添付することが最終目的です。アノテーションの作成についてはあまり情報が見つからず、ちょっと苦労させられています。

他のアプリケーションに依存しないでPDFの各種処理が行えることが望ましく(とくに、Adobe Acrobatが入っていない環境でも処理できることが望ましい)、アノテーションの添付はAppleScriptでCocoaの機能を利用して行うPDF処理としては「最後の難関」として残っています。ほかはひととおり他のアプリケーションなしでできています。

AppleScript名:指定PDFの最初のページからアノテーションを取得する
– Created 2017-06-08 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4679

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

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

set firstPage to (aPDFdoc’s pageAtIndex:0)
–>  (PDFPage) PDFPage, label 1

set anoList to (firstPage’s annotations()) as list
(*
{(PDFAnnotationMarkup) Type: ’Highlight’, Bounds: (81, 624) [434, 53]
, (PDFAnnotationSquare) Type: ’Square’, Bounds: (50, 419) [212, 162]
, (PDFAnnotationSquare) Type: ’Square’, Bounds: (301, 107) [244, 484]
}
*)

repeat with i in anoList
  set aBounds to i’s |bounds|()
  
  
log aBounds
  
(* {origin:{x:80.79, y:624.4106}, size:{width:433.6944, height:52.8918}} *)
  
(* {origin:{x:50.05553, y:419.1671}, size:{width:212.27807, height:162.3308}} *)
  
(* {origin:{x:300.6213, y:106.8405}, size:{width:244.0961, height:484.4566}} *)
  
end repeat

★Click Here to Open This Script 

2017/01/09 PDFのしおり(TOC)の内容を取得するじっけん v2

指定のPDFにしおり(TOC: Table Of Contents)がついていたら、その内容を読み取るじっけんです。再帰処理でTOCの階層を追いかけるようにしてみました。

2階層までのTOCのPDFを処理するScriptと処理結果を照合して、同じであることを確認していますが、3階層以上の深さを持つTOCでテストは行っていません。

AppleScript名:PDFのしおり(TOC)の内容を取得するじっけん v2
– Created 2017-01-09 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4383

property titleList : {}

set my titleList to {}

set aFile to POSIX path of (choose file of type {“com.adobe.pdf”})
tell current application
  set fileURL to my (|NSURL|’s fileURLWithPath:aFile)
  
set aPDFdoc to my (PDFDocument’s alloc()’s initWithURL:fileURL)
end tell

–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

–再帰処理してみた
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)
    
set tmpOut to (anOut’s label()) as string
    
set the end of my titleList to 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 

2017/01/09 PDFのしおり(TOC)の内容を取得するじっけん

指定のPDFにしおり(TOC: Table Of Contents)がついていたら、その内容を読み取るじっけんです。

Cocoa経由でも意外とたいした情報が取得できないところが驚きです。TOCの階層が2階層になっているものを処理の前提条件にしているので、本Scriptの仕様では3階層以上潜っていけません。

単なる実験なので、もう少し何か気の利いた処理ができるとよいでしょう。再帰処理とか。

AppleScript名:PDFのしおり(TOC)の内容を取得するテスト
– Created 2017-01-09 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4382

set aFile to POSIX path of (choose file of type {“com.adobe.pdf”})
tell current application
  set fileURL to my (|NSURL|’s fileURLWithPath:aFile)
  
set aPDFdoc to my (PDFDocument’s alloc()’s initWithURL:fileURL)
end tell

–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

set outLineStr to parentOL’s label() –numberOfChildren()
set outLineCount to (parentOL’s numberOfChildren()) as number
set titleList to {}

–本当は再帰処理したいが…
repeat with i from 0 to (outLineCount - 1)
  
  
set anOut to (parentOL’s childAtIndex:i)
  
set tmpOut to (anOut’s label()) as string
  
set the end of titleList to {0, tmpOut}
  
set tmpChild to (anOut’s numberOfChildren()) as integer
  
  
if tmpChild is not equal to 0 then
    repeat with ii from 0 to (tmpChild - 1)
      set anOut2 to (anOut’s childAtIndex:ii)
      
set tmpOut2 to (anOut2’s label()) as string
      
set the end of titleList to {1, tmpOut2}
    end repeat
  end if
  
end repeat

return titleList
–>  {{0, “表紙”}, {0, “目次”}, {0, “まえがき”}, {0, “この書籍について”}, {0, “#1 アプリケーションメニュー”}, {1, “アプリケーションメニュー”}, {1, “アプリケーション名称の取得”}, {1, “バージョン情報の取得”}, {1, “アップデートを確認”},….}

★Click Here to Open This Script 

2016/09/20 連番JPEGファイルを読み込んで連結したPDFを作成(新規作成)

連番JPEG画像を番号順にソートして、順次連結したPDFを新規作成するAppleScriptです。

jpeg_catfiles.jpg

このような連番画像を連結して任意のファイル名のPDFに合成します。出来上がるPDFは、元のJPEGファイルの圧縮度に応じて大きくなります。

新規作成よりも、すでに存在しているPDFにJPEGファイルを連結するほうが実用的だと思います。

AppleScript名:連番JPEGファイルを読み込んで連結したPDFを作成(新規作成)
– Created 2016-09-20 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “QuartzCore”
use framework “Quartz”
use framework “AppKit”

set aExt to “.jpg”
set aFol to choose folder
set fList to getFilePathList(aFol, aExt) of me
set f2List to my sort1DList:fList ascOrder:true –sort by ascending

set newFile to POSIX path of (choose file name with prompt “新規PDFファイルの名称を選択”)
set newFilePath to current application’s NSString’s stringWithString:newFile

–Make Blank PDF
set aPDFdoc to current application’s PDFDocument’s alloc()’s init()

set pageNum to 0

repeat with i in f2List
  set j to contents of i
  
set aURL to (current application’s |NSURL|’s fileURLWithPath:j)
  
set bImg to (current application’s NSImage’s alloc()’s initWithContentsOfURL:aURL)
  (
aPDFdoc’s insertPage:(current application’s PDFPage’s alloc()’s initWithImage:bImg) atIndex:pageNum)
  
set pageNum to pageNum + 1
end repeat

aPDFdoc’s writeToFile:newFilePath

–ASOCで指定フォルダのファイルパス一覧取得(拡張子指定つき)
on getFilePathList(aFol, aExt)
  set aPath to current application’s NSString’s stringWithString:(POSIX path of aFol)
  
set aFM to current application’s NSFileManager’s defaultManager()
  
set nameList to (aFM’s contentsOfDirectoryAtPath:aPath |error|:(missing value)) as list
  
set anArray to current application’s NSMutableArray’s alloc()’s init()
  
  
repeat with i in nameList
    set j to i as text
    
if (j ends with aExt) and (j does not start with “.”) then –exclude invisible files
      set newPath to (aPath’s stringByAppendingString:j)
      (
anArray’s addObject:newPath)
    end if
  end repeat
  
  
return anArray as list
end getFilePathList

–1D List(文字)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DList:theList ascOrder:aBool
  set aDdesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:“self” ascending:aBool selector:“localizedCaseInsensitiveCompare:”
  
set theArray to current application’s NSArray’s arrayWithArray:theList
  
return (theArray’s sortedArrayUsingDescriptors:{aDdesc}) as list
end sort1DList:ascOrder:

★Click Here to Open This Script 

2016/09/07 PDFのしおりを追加

Edama2さんからの投稿Scriptです(ありがとうございますー)。以下、その内容です。

(投稿ここから)
内容は、指定したPDFにしおりを追加します。変更したPDFは同じフォルダに別名保存します。サンプルScript中のしおりデータは、book2_2.0.pdf(最新事情がわかるAppleScript 10大最新技術)用です。

しおりがあると今度は、章だけではなく大見出しも欲しくなり作ってみました。

preview1.png
▲処理前のPDF(Adobe Acrobat Professionalで表示)

pdfindex3.png
▲処理前のPDFのしおり部分(AppleScriptで処理すると一旦削除)

pdfindex4.png
▲処理後のPDF。新規作成したしおり部分。階層構造を持っている

階層表示の一階層しか対応していませんが、もっと深い階層も作れるようにしたかったが、…時間がなくてできませんでした。再帰処理で出来そうな気はするんですが…。

実用的にはもう一階層分あったほうがうれしいです。この辺は好みもあるので自分でもDTPする時に悩みます。

#1 他人のマシン上でも動くAppleScriptを書く
  他人のマシン上でも動くAppleScriptを書く
    準備しよう!
      他人のユーザーアカウント上で動かすための最低条件
      OSAXを極力使わない

メインの処理をrunハンドラでなく、別ハンドラにしているのは、「Objective-Cポインタは保存できません」エラーに対応するためです。

→ AppleScriptのダウンロード(20KB)

リファレンスv2は、ページ数の多さもあり気になった項目から読んでいるので、まだ全部読み終えてませんが主に文法編をよく活用しています。(投稿ここまで)

「AppleScript最新リファレンス」については、書いた本人でも、「あれ、こんなの書いたっけ?」と、自分で読んで発見があります(汗)

プログラムの内容について、自分もひととおり美味しそうなPDF関連のCocoaの機能は試した気になっていたのですが、しおりは試していませんでした。

自分がいつも使っている「AppleScriptのプログラムを書式つきのHTMLに変換」するAppleScriptでお送りいただいたScriptを変換したところ、WordPress側でエラー発生。やむなくダウンロードしていただく形式にしました(なんでだ?!)。

書籍の話に戻りますが……PDFが出来上がったあとでゴニョゴニョを後処理を行うよりも制作フローそのものを見直すべきだとは自分も思っています(MarkdownからPDFを書き出すだけというのは無茶すぎ、、、)。その割に、世間に転がっている情報のウラをとって(実際に確認して)みると、Pandocも割と役立たずで、MarkdownをIDMLに変換できるとかいいつつ、いざInDesignに読ませてみると「互換性がない」エラーに遭遇するやらで、実に「自分で何か作らないとダメ」な雰囲気です。

2016/07/27 PDFをページごとに分解してJPEGで保存する v2

PDFをページごとに分解してJPEG画像で保存するAppleScriptのアップデート版です。

実際に連番画像に変換して、ePub書類に変換させてみたらページの順序が狂ってしまいました。連番を振るときにゼロパディングしなかったためだとすぐにわかったので、ゼロパディングの処理を追加したものです。

ただし、実際にはこれだと解像度が不足しており、2倍の解像度で出力するように改良して実戦投入(Retina Display環境に配慮しつつ)しました。

AppleScript名:ASOCでPDFをページごとに分解してJPEGで保存する v2
– Created 2014-12-26 by Takaaki Naganoya
– Modified 2015-09-26 by Takaaki Naganoya
– Modified 2015-10-01 by Takaaki Naganoya
– Modified 2016-07-27 by Takaaki Naganoya–save each PDF page as jpeg
– Modified 2016-07-27 by Takaaki Naganoya–added zero padding function
– 2016 Piyomaru Software
# http://piyocast.com/as/archives/4176

use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “QuartzCore”
use framework “AppKit”

set aHFSPath to (choose file of type {“com.adobe.pdf”} with prompt “ページごとに分解するPDFを指定してください”)
set aPOSIX to POSIX path of aHFSPath
set aURL to (current application’s |NSURL|’s fileURLWithPath:aPOSIX)

set aPOSIXpath to POSIX path of aHFSPath —書き出し先パスをPOSIX pathで用意しておく(あとで加工)

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

set compFactor to 1.0 – 0.0 = max jpeg compression, 1.0 = none

–PDFをページごとに分割してJPEGでファイル書き出し
repeat with i from 0 to (pCount - 1)
  set thisPage to (aPDFdoc’s pageAtIndex:(i))
  
set thisDoc to (current application’s NSImage’s alloc()’s initWithData:(thisPage’s dataRepresentation()))
  
if thisDoc = missing value then error “Error in getting imagerep from PDF in page:” & (i as string)
  
  
set theData to thisDoc’s TIFFRepresentation()
  
set newRep to (current application’s NSBitmapImageRep’s imageRepWithData:theData)
  
set targData to (newRep’s representationUsingType:(current application’s NSJPEGFileType) |properties|:{NSImageCompressionFactor:compFactor, NSImageProgressive:false})
  
set zText to retZeroPaddingText((i + 1), 4) of me
  
set outPath to addString_beforeExtensionIn_addingExtension_(“_” & zText, aPOSIXpath, “jpg”)
  
  (
targData’s writeToFile:outPath atomically:true) –書き出し
end repeat

–ファイルパス(POSIX path)に対して、文字列(枝番)を追加。任意の拡張子を追加
on addString:extraString beforeExtensionIn:aPath addingExtension:aExt
  set pathString to current application’s 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 as integer, aDigitNum as integer)
  if aNum > (((10 ^ aDigitNum) as integer) - 1) then return “” –Range Check
  
set aFormatter to current application’s NSNumberFormatter’s alloc()’s init()
  
aFormatter’s setUsesGroupingSeparator:false
  
aFormatter’s setAllowsFloats:false
  
aFormatter’s setMaximumIntegerDigits:aDigitNum
  
aFormatter’s setMinimumIntegerDigits:aDigitNum
  
aFormatter’s setPaddingCharacter:“0″
  
set aStr to aFormatter’s stringFromNumber:(current application’s NSNumber’s numberWithFloat:aNum)
  
return aStr as string
end retZeroPaddingText

★Click Here to Open This Script 

2016/07/27 PDFをページごとに分解してJPEGで保存する

指定したPDFをページごとに分解してJPEG画像として保存するAppleScriptです。

書籍のPDFからePubを作ろうとして、さまざまなツールを試して撃沈。日本語のフォントが通らなかったり、オリジナルからかけ離れたレイアウトになったりと散々でした。

ePub版を作るのにそれほど労力を割きたくなかったので、「画像からePub作ろう」と割り切り、PDFをページごとにJPEGに分解することにしました。これを手作業で行っていたのでは日が暮れます。

splittedjpegs.png

そこで、本AppleScriptを作成。ありものを組み合わせたぐらいの作業で完成。さくっとPDFをページごとのJPEG画像に分解できました。

AppleScript名:ASOCでPDFをページごとに分解してJPEGで保存する
– Created 2014-12-26 by Takaaki Naganoya
– Modified 2015-09-26 by Takaaki Naganoya
– Modified 2015-10-01 by Takaaki Naganoya
– Modified 2016-07-27 by Takaaki Naganoya–save each PDF page as jpeg
– 2016 Piyomaru Software
# http://piyocast.com/as/archives/4174

use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “QuartzCore”
use framework “AppKit”

set aHFSPath to (choose file of type {“com.adobe.pdf”} with prompt “ページごとに分解するPDFを指定してください”)
set aPOSIX to POSIX path of aHFSPath
set aURL to (current application’s |NSURL|’s fileURLWithPath:aPOSIX)

set aPOSIXpath to POSIX path of aHFSPath —書き出し先パスをPOSIX pathで用意しておく(あとで加工)

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

set compFactor to 1.0 – 0.0 = max jpeg compression, 1.0 = none

–PDFをページごとに分割してJPEGでファイル書き出し
repeat with i from 0 to (pCount - 1)
  set thisPage to (aPDFdoc’s pageAtIndex:(i))
  
set thisDoc to (current application’s NSImage’s alloc()’s initWithData:(thisPage’s dataRepresentation()))
  
if thisDoc = missing value then error “Error in getting imagerep from PDF in page:” & (i as string)
  
  
set theData to thisDoc’s TIFFRepresentation()
  
set newRep to (current application’s NSBitmapImageRep’s imageRepWithData:theData)
  
set targData to (newRep’s representationUsingType:(current application’s NSJPEGFileType) |properties|:{NSImageCompressionFactor:compFactor, NSImageProgressive:false})
  
  
set outPath to addString_beforeExtensionIn_addingExtension_(“_” & (i + 1) as string, aPOSIXpath, “jpg”)
  
  (
targData’s writeToFile:outPath atomically:true) –書き出し
end repeat

–ファイルパス(POSIX path)に対して、文字列(枝番)を追加。任意の拡張子を追加
on addString:extraString beforeExtensionIn:aPath addingExtension:aExt
  set pathString to current application’s 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:

★Click Here to Open This Script 

2016/07/20 PDFを回転させて新規保存 v2

PDFを時計周りに任意の角度で回転させて新規保存するAppleScriptです。角度は90度単位で指定可能です。

AppleScript名:ASOCでPDFを回転させて新規保存 v2
– Created 2015-10-20 by Takaaki Naganoya
– Modified 2016-07-01 by Takaaki Naganoya–複数回PDFに回転処理を行った場合の挙動を改善
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “QuartzCore”

set aPath to POSIX path of (choose file of type {“com.adobe.pdf”} with prompt “Select PDF”)
set newFile to POSIX path of (choose file name)

set pdfRes to rotatePDFandSaveAt(aPath, newFile, 90) of me

–oldPath and newPath have to be a POSIX path, aDegree have to be in {0, 90, 180, 270, 360}
on rotatePDFandSaveAt(oldPath as string, newPath as string, aDegree as integer)
  
  
–Error Check
  
if aDegree is not in {0, 90, 180, 270, 360} then error “Wrong Degree”
  
  
set aURL to current application’s |NSURL|’s fileURLWithPath:oldPath
  
set aPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL
  
  
set pCount to aPDFdoc’s pageCount() –count pages
  
  
–Make Blank PDF
  
set newPDFdoc to current application’s PDFDocument’s alloc()’s init()
  
  
–Rotate Each Page
  
repeat with i from 0 to (pCount - 1)
    set aPage to (aPDFdoc’s pageAtIndex:i)
    
    
–Set Degree
    
set curDegree to aPage’s |rotation|() –Get Current Degree
    (
aPage’s setRotation:(aDegree + curDegree)) –Set New Degree
    
    (
newPDFdoc’s insertPage:aPage atIndex:i)
  end repeat
  
  
set aRes to newPDFdoc’s writeToFile:newPath
  
return aRes as boolean
  
end rotatePDFandSaveAt

★Click Here to Open This Script 

2016/07/18 PDFの指定ページを削除

指定PDF中の指定ページを削除するAppleScriptです。

CocoaのAPIをひととおり調べて、PDFのページ削除を行うメソッドなどが存在していないことがよくわかりました。

存在しない=できない、ということではないのでAppleScriptで組んでみました。動作確認した範囲ではちゃんと機能しています。

pdfremove.png

削除機能を削除機能として考えただけでは実現できませんが、これを「新規PDFへのページコピー」と考えれば不可能ではありません。つまり、削除を「新規PDFにコピーしない」ことと定義し直してみました。

 /卦PDFに指定ページ以外のページをコピー
 ▲リジナルのPDFを削除
 新規PDFをオリジナルのPDF名で保存

と処理すれば、指定ページを削除したのと同じことです。

このルーチンを用いて、「複数ファイルのPDFを連結、末尾が空白ページだったら削除しつつ連結」という動作を行うAppleScriptを簡単に書くことができました。

ただ、この処理方法がSandbox環境で(Xcode上で作成するCocoa-AppleScript Applet内で)許可されるものなのかは、試してみないといけないでしょう。

AppleScript名:PDFの指定ページを削除
– Modified 2016-07-18 by Takaaki Naganoya
–Original By Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “QuartzCore”

set inFile to (choose file of type {“pdf”} with prompt “Choose your PDF files:”)
set targPage to 2
set maxPage to pdfPageCount(inFile) of me
if 0 < targPage and targPage maxPage then
  –Skip
else
  display dialog “Page Number Range Error”
  
return
end if

removeSpecificPageInPDF(inFile, targPage) of me

on removeSpecificPageInPDF(inFile, targPageNum)
  – make URL of the first PDF
  
set inNSURL to current application’s |NSURL|’s fileURLWithPath:(POSIX path of inFile)
  
set theDoc to current application’s PDFDocument’s alloc()’s initWithURL:inNSURL
  
  set oldDocCount to ((theDoc’s pageCount()) - 1)
  
  –Make Blank PDF (deleted PDF)
  
set newPDFdoc to current application’s PDFDocument’s alloc()’s init()
  
  set newDocCount to 0
  
  repeat with i from 0 to oldDocCount
    if i is equal to (targPageNum - 1) then
      log {“skip page at:”, i}
    else
      log {i}
      
set thePDFPage to (theDoc’s pageAtIndex:i) – zero-based indexes
      (
newPDFdoc’s insertPage:thePDFPage atIndex:newDocCount)
      
set newDocCount to newDocCount + 1
    end if
  end repeat
  
  –元ファイルを削除して問題がなければ、指定ページを削除したPDFを同名で新規保存
  
set aRes to deleteFile(inFile) of me
  
if aRes = true then
    set aRes to (newPDFdoc’s writeToURL:inNSURL)
  end if
  
  return aRes
  
end removeSpecificPageInPDF

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

–指定ファイルの削除
on deleteFile(aFile)
  set aPath to POSIX path of aFile
  
set filePath to current application’s NSString’s stringWithString:aPath
  
set fileManager to current application’s NSFileManager’s defaultManager()
  
set aRes to fileManager’s removeItemAtPath:filePath |error|:(reference)
  
–>  {true, missing value}
  
–>  {false, (NSError) Error}
  
copy aRes to {aFlag, aReason}
  
return aFlag
end deleteFile

★Click Here to Open This Script 

2016/07/17 PDFの最終ページのみ切り出して空白かどうかチェック

指定のPDFの最終ページのみチェックして、空白であるかどうかを返すAppleScriptです。

ASOCが使えるようになって、AppleScriptだけでたいていのPDF処理ができるようになりました。ページ数のカウント、複数ドキュメントの連結、ページごとの分割、回転、パスワードの設定や解除、テキスト抽出、などなど。

pdf_blank_page.png

しかし、いまだにできていなかった処理が「指定ページが空白かどうかのチェック」でした。指定ページからテキスト抽出しただけではダメで、画像だけでテキストが存在しないケースに対応する必要があります。

最初にAppleScriptでコレを実装したときには、割と力技でやってしまいました。Photoshopでオープンしてラスタライズし、ヒストグラムを取得してページ上に文字や画像が存在しているかどうかを検出していました。白くないピクセルが存在していたら、何らかのオブジェクトが存在しているだろう、という判断方法です。

ただ、Photoshopが存在しないと処理できないため、ASOCだけでなんとかできないかと試行錯誤。結論からいえば、現時点ではちょっと無理な感じがします。ただ、Photoshopを使わないことがそもそものテーマなので、フリーのMuPDFをみつけてHomebrew経由でインストール。これを呼び出すようにしてみました。指定ページの画像オブジェクトと埋め込みフォント情報を取得して、画像やテキストが存在しないかどうかを確認します。

そもそもなんでこれが必要になったかといえば、書籍の多くのページをMarkdownで記述しており、PDF書き出し時に意図しない空白ページが生成されるケースが割とあるので、制御不可能なMarkdownと格闘するよりも、書き出したPDFに対して末尾ページの空白チェックを行って削除したほうがいいと判断したからです。

AppleScript名:PDFの最終ページのみ切り出して空白かどうかチェック
– Created 2016-07-17 by Takaaki Naganoya
– 2016 Piyomaru Software
– At first, install mutool via homebrew by “brew install mupdf-tools” from Terminal.app
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “QuartzCore”

set aHFSPath to (choose file of type {“pdf”} with prompt “Choose your PDF file:”)
set aRes to detectTheLastPageIsEmpty(aHFSPath) of me
–> true

–指定PDFの最終ページが空白かどうか検出する
on detectTheLastPageIsEmpty(aHFSPath)
  set aPOSIX to POSIX path of aHFSPath
  
set aURL to (current application’s |NSURL|’s fileURLWithPath:aPOSIX)
  
copy aPOSIX to aPOSIXpath —出力用に複製
  
  
set aPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL
  
set pCount to aPDFdoc’s pageCount()
  
  
–PDFの最終ページを分割してファイル書き出し
  
set thisPage to (aPDFdoc’s pageAtIndex:(pCount - 1))
  
set thisDoc to (current application’s PDFDocument’s alloc()’s initWithData:(thisPage’s dataRepresentation()))
  
set outPath to addString_beforeExtensionIn_(“_lastpage”, aPOSIXpath)
  (
thisDoc’s writeToFile:outPath) –書き出し
  
  
–最終ページ内の画像ファイル、埋め込みフォントの情報を取得
  
try
    set aRes to do shell script “/usr/local/bin/mutool extract “ & quoted form of outPath
  on error erM
    copy erM to aRes
  end try
  
  
–切り出したPDFの削除はかならず行っておく
  
try
    do shell script “rm -f “ & quoted form of outPath
  end try
  
  
if aRes“” then
    return false –Not Empty
  else
    return true –Empty
  end if
end detectTheLastPageIsEmpty

–ファイルパス(POSIX path)に対して、文字列(枝番)を追加。拡張子はそのまま
on addString:extraString beforeExtensionIn:aPath
  set pathString to current application’s 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:theExtension
  
return newPath as string
end addString:beforeExtensionIn:

★Click Here to Open This Script 

2016/04/19 Multi Page Tiffを読み込んで、PDFに変換する

Multipage Tiffを読み込んで、PDFに書き出すAppleScriptです。

意外とサンプルもなく、さまざまなObjective-Cのサンプルの断片をかき集めて、ようやくできました。着手してから1年ぐらい放置してあったぐらいです。

Multipage Tiffのサンプルをここから入手し、試行錯誤してようやく変換できました。

multipage1.png

大昔から存在しているものの、ずーーっとマイナーな存在だったMultipage Tiffなので、こんなもん書いて有用性がどーのとかいうことは一切ないわけですが、1年間放置しておいた未解決の問題を解決できてスッキリしました。

AppleScript名:multi page tiffを読み込んで、PDFにする
– Created 2015-01-01 by Takaaki Naganoya
– Modified 2016-04-18 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “QuartzCore”
use framework “Quartz”
use framework “AppKit”

set a to choose file of type {“public.tiff”} with prompt “Select Multi-page tiff file” –tiff

–Make Output Path
set b to POSIX path of a
set bb to changeExtensionInPath(“pdf”, b) –OutPath

–Read Multi-Page TIFF
set aURL to current application’s |NSURL|’s fileURLWithPath:b
set aImage to current application’s NSImage’s alloc()’s initWithContentsOfURL:aURL
set aRawimg to aImage’s TIFFRepresentation()
set eachTiffPages to (current application’s NSBitmapImageRep’s imageRepsWithData:aRawimg) as list

–Make Blank PDF
set aPDFdoc to current application’s PDFDocument’s alloc()’s init()

set pageNum to 0

repeat with curPage in eachTiffPages
  set thisImage to contents of curPage
  
set aImg to (current application’s NSImage’s alloc()’s initWithSize:(thisImage’s |size|()))
  (
aImg’s addRepresentation:thisImage)
  (
aPDFdoc’s insertPage:(current application’s PDFPage’s alloc()’s initWithImage:aImg) atIndex:pageNum)
  
set pageNum to pageNum + 1
end repeat

aPDFdoc’s writeToFile:bb

–ファイルパス(POSIX path)に対して、拡張子のみ付け替える
on changeExtensionInPath(extStr as string, aPath as string)
  set pathString to current application’s NSString’s stringWithString:aPath
  
set theExtension to pathString’s pathExtension()
  
set thePathNoExt to pathString’s stringByDeletingPathExtension()
  
set newPath to thePathNoExt’s stringByAppendingPathExtension:extStr
  
return newPath as string
end changeExtensionInPath

★Click Here to Open This Script 

2015/10/20 PDFの各種情報を取得する

Cocoaの機能を用いて、PDFの各種情報を取得するAppleScriptです。

PDFのParse自体はAppleScriptだけでは行えませんが、こうした情報の取得や、PDFの暗号化/復号化ぐらいであればAppleScriptだけで(他のアプリケーションを併用せずに)実行可能です。

AppleScript名:ASOCでPDFの各種情報を取得する
– Created 2015-10-20 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “QuartzCore”

set aPath to POSIX path of (choose file of type {“com.adobe.pdf”} with prompt “Select PDF”)
set aURL to current application’s |NSURL|’s fileURLWithPath:aPath
set aPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL

set pCount to aPDFdoc’s pageCount() –ページ数
–>  1

set aMajorVersion to aPDFdoc’s majorVersion() –バージョン(メジャーバージョン)
–> 1

set aMinorVersion to aPDFdoc’s minorVersion() –バージョン(マイナーバージョン)
–> 3

set aRoot to aPDFdoc’s outlineRoot()
–>  missing value

set anAttr to (aPDFdoc’s documentAttributes()) as record
–> (NSDictionary) {Creator:”Pages”, Producer:”Mac OS X 10.11.1 Quartz PDFContext”, ModDate:(NSDate) 2015-10-20 07:45:55 +0000, Title:”testPDF”, CreationDate:(NSDate) 2015-10-20 07:45:55 +0000}

set aCreator to anAttr’s Creator()
–>  ”Pages”

set aProducer to anAttr’s Producer()
–>  ”Mac OS X 10.11.1 Quartz PDFContext”

set aTitle to anAttr’s Title()
–>  ”testPDF”

set aCreationDate to anAttr’s CreationDate() –PDF作成年月日
–>  date “2015年10月20日火曜日 16:45:55″

set aModDate to anAttr’s ModDate() –PDF変更年月日
–>  date “2015年10月20日火曜日 16:45:55″

set anEncF to aPDFdoc’s isEncrypted() –暗号化されている(パスワードが設定されている)か?
–>  false

set anLockF to aPDFdoc’s isLocked() –ロックされているか?
–>  false

set aCopyF to aPDFdoc’s allowsCopying() –テキストのコピーを許可されているか?
–>  true

set aPrintF to aPDFdoc’s allowsPrinting() –印刷を許可されているか?
–>  true

–PDFのサイズを取得する(単位:Point)
set aPage to aPDFdoc’s pageAtIndex:0
set aBounds to aPage’s boundsForBox:(current application’s kPDFDisplayBoxMediaBox)
set aSize to |size| of aBounds
–>  {width:595.28, height:841.89}

★Click Here to Open This Script 

2015/10/18 PDFメディアサイズの取得(単位:Point)

選択したPDF書類のページのサイズをPointで取得するAppleScriptです。

ページの取得方式にいろいろあるので、ひととおり調べてみたところ(実験には、Shane Stanleyの「Everyday AppleScriptObjC」を使用)・・・すべて同じ結果が返ってきました。それぞれどのように取得しているか、調べておきたいところです(図になっていないものか)。

OS X 10.11上で確認および10.11の機能(Enumのbridge)を使っていますが、OS X 10.10上では「current application’s kPDFDisplayBoxMediaBox」などと書いてあるものを0(数値)に書き換えれば動きます。

AppleScript名:PDFメディアサイズの取得(単位:Point)
– Created 2015-10-18 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “QuartzCore”

–PDFを選択
set aFile to choose file of type {“com.adobe.pdf”}

set aFile to POSIX path of aFile
set theURL to current application’s |NSURL|’s fileURLWithPath:aFile
set aPDFdoc to current application’s PDFDocument’s alloc()’s initWithURL:theURL
set aPage to aPDFdoc’s pageAtIndex:0

–PDFのサイズを取得する(単位:Point)
set aBounds to aPage’s boundsForBox:(current application’s kPDFDisplayBoxMediaBox) –0
set aSize to |size| of aBounds
–>  {width:612.0, height:792.0}

set aBounds to aPage’s boundsForBox:(current application’s kPDFDisplayBoxCropBox) –1
set aSize to |size| of aBounds
–>  {width:612.0, height:792.0}

set aBounds to aPage’s boundsForBox:(current application’s kPDFDisplayBoxBleedBox) –2
set aSize to |size| of aBounds
–>  {width:612.0, height:792.0}

set aBounds to aPage’s boundsForBox:(current application’s kPDFDisplayBoxTrimBox) –3
set aSize to |size| of aBounds
–>  {width:612.0, height:792.0}

set aBounds to aPage’s boundsForBox:(current application’s kPDFDisplayBoxArtBox) –4
set aSize to |size| of aBounds
–>  {width:612.0, height:792.0}

★Click Here to Open This Script 

2015/08/24 ASOCでPDFを印刷するテスト

Cocoaの機能を用いてPDFをAppleScriptだけでアプリケーションに依存しないで印刷するscriptです。

pdfprint1.png
▲Script Editor上でCommand-Control-「R」でforeground実行すると、PDFを選択し、印刷ダイアログを表示します(Window非表示)

pdfprint2.png
▲プリンタも選択可能

AppleScript名:ASOCでPDFを印刷するテスト
– Created 2015-08-24 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “AppKit”

–Check If this script runs in foreground
if not (current application’s NSThread’s isMainThread()) as boolean then
  display alert “This script must be run from the main thread (Command-Control-R in Script Editor).” buttons {“Cancel”} as critical
  
error number -128
end if

–Choose a PDF to print
set aDoc to POSIX path of (choose file of type {“com.adobe.pdf”})
set aDocPath to current application’s NSString’s stringWithString:aDoc
set aPDF to current application’s PDFDocument’s alloc()’s initWithURL:(current application’s |NSURL|’s fileURLWithPath:aDocPath)

–Make PDFView
set aPDFView to current application’s PDFView’s alloc()’s init()
aPDFView’s setDocument:aPDF
aPDFView’s setAutoScales:true
aPDFView’s setDisplaysPageBreaks:false

–Make Window
set aWin to current application’s NSWindow’s alloc()’s init()
aWin’s setContentSize:(aPDFView’s frame()’s |size|())
aWin’s setContentView:aPDFView
aWin’s |center|()

–Print PDF
set sharedPrintInfo to current application’s NSPrintInfo’s sharedPrintInfo()
aPDFView’s printWithInfo:sharedPrintInfo autoRotate:true

★Click Here to Open This Script 

2014/12/27 PDFをページごとに分解する

指定したPDFファイルをページごとに分解して保存するAppleScriptです。

非常によくあるScript(PDFpenやSkimなどを使って分割)ですが、他のアプリを必要としません。

MacBook Pro Retina 2012(Core i7 2.66GHz)で277ページのPDFをページごとに分解するのに12秒でした。

AppleScript名:PDFをページごとに分解する
– Created 2014-12-26 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “QuartzCore”

property PDFDocument : class “PDFDocument”

set aHFSPath to (choose file of type {“com.adobe.pdf”} with prompt “ページごとに分解するPDFを指定してください”) as string
set aURL to (current application’s SMSFord’s URLFrom:aHFSPath)

set aPOSIXpath to POSIX path of aHFSPath —書き出し先パスをPOSIX pathで用意しておく(あとで加工)

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

–PDFをページごとに分割してファイル書き出し
repeat with i from 0 to (pCount - 1)
  
  
set thisPage to (aPDFdoc’s pageAtIndex:(i))
  
set thisDoc to (PDFDocument’s alloc()’s initWithData:(thisPage’s dataRepresentation()))
  
set outPath to addString_beforeExtensionIn_(“_” & (i + 1) as string, aPOSIXpath)
  
  (
thisDoc’s writeToFile:outPath) –書き出し
  
end repeat

–ファイルパス(POSIX path)に対して、文字列(枝番)を追加。拡張子はそのまま
on addString:extraString beforeExtensionIn:aPath
  set pathString to current application’s 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:theExtension
  
return newPath as string
end addString:beforeExtensionIn:

★Click Here to Open This Script 

2013/12/16 OS X 10.9で指定PDFのページ数をかぞえる(AppleScriptObjC版)

OS X 10.9, Mavericks上で指定のPDFのページ数をかぞえるAppleScriptのAppleScriptObjC版(要Xcode)です。

PDFのページ数をかぞえる処理は、ひじょーに重要で応用範囲が広いものなので、先日あわてて即興で1本書きました(迅速に対応できないとまずい案件があったので)。mdlsコマンドで間接的にPDFのページ数を取得するというものでしたが、常識的な範囲内ではとくに問題なく動きました。

ただ……あれやこれやと「常識的な範囲内」についての条件説明が必要なため、まっとうな方法(AppleScriptObjCでCocoaを叩く)=「直接機能にアクセスして情報を取得」する方法で作っておく必要がありました。

そこで、仕事の合間を見て試作品を作成。ウィンドウのボタンをクリックすると、PDF選択ダイアログが表示されるため、PDFを選択するとページ数をダイアログで返します。

pdfc1.png

pdfc2.png

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– countPDFtest

– Created by Takaaki Naganoya on 2013/12/12.
– Copyright (c) 2013年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
  property nsurl : class “NSURL”
  
property PDFDocument : class “PDFDocument”
  
  
  on applicationWillFinishLaunching:aNotification
    
  end applicationWillFinishLaunching:
  
  
  on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
  on clicked:sender
    
    tell current application
      set aFile to choose file of type {“com.adobe.pdf”}
    end tell
    
    set aRes to pdfPageCount_(aFile as string)
    
    tell current application
      display dialog aRes as string
    end tell
    
  end clicked:
  
  
  
  –指定PDFのページ数をかぞえる(10.9対応。普通にPDFpageから取得)
  
–パラメータ:PDFファイルのHFS path(string)
  
–返り値:PDFファイルのページ数(整数値)
  
on pdfPageCount:aFile
    
    tell application “Finder”
      set aFileURL to (URL of file aFile)
    end tell
    
    set aFileURL to aFileURL as Unicode text
    
set theURL to nsurl’s URLWithString:aFileURL
    
    set aPDFdoc to PDFDocument’s alloc()’s initWithURL:theURL
    
set aRes to aPDFdoc’s pageCount()
    
    return aRes as integer
    
  end pdfPageCount:
  
  
  
  –指定PDFのページ数をかぞえる(10.9対応。普通にPDFpageから取得)
  
–パラメータ:PDFファイルのPOSIX path(quoteされていない)
  
–返り値:PDFファイルのページ数(整数値)
  
on pdfCountPOSIXpath:aPDFPosixPath
    
    set aFile to (aPDFPosixPath as POSIX file) –POSIX pathからPOSIX fileにcast
    
    tell application “Finder”
      set aFileURL to (URL of (aFile as alias)) –aliasからでないとURLが取得できない
    end tell
    
    set aFileURL to aFileURL as Unicode text
    
set theURL to nsurl’s URLWithString:aFileURL
    
    set aPDFdoc to PDFDocument’s alloc()’s initWithURL:theURL
    
set aRes to aPDFdoc’s pageCount()
    
    return aRes as integer
    
  end pdfCountPOSIXpath:
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/04/16 AppleScriptObjCでPDFViewを使ってPDFをプレビュー(4)

AppleScriptObjCでPDFをプレビューするテストプログラムをその後進展させたものです。

ようやく、現在表示中のPDFの選択中のページのインデックス番号(0からはじまる通し番号)を取得できるようになりました。

→ Xcodeプロジェクトのダウンロード

PDF Kit Programming Guideの「PDF Kit Tasks」を参照し、そのとおりにAppleScriptObjCで書いても動かず、延々とデバッグを行い…………………………「document」を「|document|」と修正したところ、何の問題もなく動作しました。

このあたりは、Xcode上でチェックしたり対策してくれないと、なかなか気付きません。

AppleScriptObjC Explorer2を外部からAppleScriptでコントロールして、自動でチェックするようにしたほうがよいかもしれません(XcodeのAppleScript用語辞書の実装はあいかわらずタコなままなので、Xcodeをこづき回しても得るものが少ない。また、AppleScriptの構文色分けを反映しなくなったのは納得できません)。

本サンプルは、選択したPDFをPhotoshopでレンダリングして画像にするための「プレビュー」を目的としており、対象ファイル、対象ページ、レンダリング解像度などを取得してPhotoshopでレンダリングするフローの中で使用する部品として想定しています。実際にはこの部品は(間に合わなかったので)使用せず、もっと簡易な仕様の部品を使いましたが……次回はこの部品の改良版を投入したいところです。

pdf1.png

pdf2.png

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– pdftest2

– Created by Takaaki Naganoya on 2013/04/16.
– Copyright (c) 2012年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
property nsurl : class “NSURL”
  
property PDFDocument : class “PDFDocument”
  
  
  property pdfPreviewWin : missing value
  
property pdfView : missing value
  
property pdfThumb : missing value
  
  property pdfPageText : missing value
  
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    pdfView’s setAllowsDragging_(false)
    
pdfView’s setDelegate_(me)
    
    
    pdfThumb’s setMaximumNumberOfColumns_(2)
    
pdfThumb’s setAllowsMultipleSelection_(false)
    
    –書類が変更になった(オープンされた場合)Notificationの処理先ハンドラを登録
    
set noter1 to current application’s NSNotificationCenter’s defaultCenter()
    
noter1’s addObserver_selector_name_object_(me, “pdfChange:”, current application’s PDFViewDocumentChangedNotification, pdfView)
    
    –ページが変更になったNotificationの処理先ハンドラを登録
    
noter1’s addObserver_selector_name_object_(me, “pdfPageChange:”, current application’s PDFViewPageChangedNotification, pdfView)
    
    
    
    –ファイルを選択
    
set aFile to choose file of type “com.adobe.pdf”
    
set aFileString to aFile as Unicode text
    
dispPDFWithHFSpath_(aFileString)
    
    
  end applicationWillFinishLaunching_
  
  
  
  –プレビューウィンドウをセンタリング(見た目以外にとくに意味なし)
  
on applicationDidFinishLaunching_(aNotification)
    
    pdfPreviewWin’s |center|()
    
  end applicationDidFinishLaunching_
  
  
  
  –HFSパスの文字列を渡すとPDFViewに表示する
  
on dispPDFWithHFSpath_(aFileString)
    
    set aFileString to aFileString as Unicode text
    
    tell application “Finder”
      set aFileURL to (URL of file aFileString)
    end tell
    
    set aFileURL to aFileURL as Unicode text
    
set theURL to nsurl’s URLWithString_(aFileURL)
    
    set aPDFdoc to PDFDocument’s alloc()’s initWithURL_(theURL) –allocわすれてた、、、
    
pdfView’s setDocument_(aPDFdoc)
    
  end dispPDFWithHFSpath_
  
  
  on applicationShouldTerminate_(sender)
    return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  
  –表示ページが変更になった場合にnotificationでこちらを呼び出している
  
on pdfPageChange_(notification)
    
    dispPDFPageNumber()
    
  end pdfPageChange_
  
  
  –ファイルの新規オープン、および表示ページが変更になった場合にnotificationでこちらを呼び出している
  
on pdfChange_(notification)
    
    dispPDFPageNumber()
    
  end pdfChange_
  
  
  –PDFページ数を表示する
  
on dispPDFPageNumber()
    
    set curDoc to pdfView’s |document| –ここが問題の箇所!!!
    
set curPage to pdfView’s currentPage
    
set curPageNumber to curDoc’s indexForPage_(curPage)
    
    pdfPageText’s setStringValue_((curPageNumber + 1) as string)
    
  end dispPDFPageNumber
  
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/09 AppleScriptObjCでPDFViewを使ってPDFをプレビュー(3)

AppleScriptObjCでPDFをプレビューするテストプログラムをその後進展させたものです。

1作目で、PDFのプレビューができるようになり
2作目で、表示中のPDFの選択中のページ(label)が取得できるようになり
この3作目では、PDFに設定されているリンクのクリックを無視するようになりました。

結局、PDFViewのオンラインマニュアルを端から端まで探しても、リンクの無効化などの機能は存在していないようだったので、上位クラスであるNSViewのオンラインマニュアルを探してみました。すると、

nsview1.png

のように、hitTest:でnill(false)を返せばViewへのクリックを無視できることがわかったので、以下のようにPDFViewを継承したクラスを宣言し、Interface Builder上でPDFViewのクラスをこの「clicThPDFView」に変更してみました。

→ Xcodeプロジェクトのダウンロード

AppleScriptObjCファイル名:clickThroughPDFView.applescript
script clicThPDFView
  
  property parent : class “PDFView”
  
  on hitTest_(aPoint)
    
    return false
    
  end hitTest_
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

pdfv1.png

すると……

pdfv2.png

このような、目次から各章へのリンクが張られまくっているPDFをオープンして、PDFViewで目次をクリックしても……

pdfv3.png

リンク先には飛ばなくなりました!!! PDFViewへのマウスクリックを無効化することで、PDF内のリンクが反応することを防げるようになったわけです。

ただし、以前心配していたとおり、ページ数の取得にPage(0からはじまるページ数)ではなくlabelを取得しているために、目次ページなどPDFドキュメント制作時にアラビア数字ではないページ数が割り振られている箇所では、そのようなページ数が表示されることが判明。

PDF上のリンクが反応しないようにはできたものの、ページ数の取得については依然として問題を抱えていることがわかりました。PDFのプレビューとページ数設定のUser Interfaceとして利用するためにはあと一歩の改良が必要といったところです。

2013/02/06 AppleScriptObjCでPDFViewを使ってPDFをプレビュー(2)

AppleScriptObjCでPDFをプレビューするテストプログラムをその後進展させたものです。

本コードについては、PDFのファイルを選択した後で、プレビューしつつ対象ページを選ばせて他のアプリケーション(たぶんPhotoshop)に渡してレンダリングさせる……という目論見があったものの、プレビュー対象のページの取得方法が分らずに、時間がなかったのでその時には実戦投入することをあきらめました。

そして、時間のあるときに調べてみて、選択・プレビュー中のページをなんとか取得する方法にたどり着いたので、修正してみました。

pdfprev1.png

–> “Page 0; label = 1\n media (0.0, 0.0) [612.0, 792.0]\n crop (0.0, 0.0) [612.0, 792.0]\n rot 0\n ‘A Adobe\U00ae RGB (1998) Color Imag…’\n”

pdfprev2.png

–> “Page 1; label = 2\n media (0.0, 0.0) [612.0, 792.0]\n crop (0.0, 0.0) [612.0, 792.0]\n rot 0\n ‘A Adobe RGB (1998) Color Image…’\n”

まだ、実用上は問題があります。PDFViewに表示されたPDF上のリンクが生きており、PDF書類内のリンクや外部のWebサイトに張られたリンクが反応してしまうからです。これらをDisableにしてはじめて、プレビュー/処理対象ページ選択用のUIとして使えるのですが…………。

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– pdftest2

– Created by Takaaki Naganoya on 2012/10/23.
– Copyright (c) 2012年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
property nsurl : class “NSURL”
  
property PDFDocument : class “PDFDocument”
  
  
  property pdfPreviewWin : missing value
  
property pdfView : missing value
  
property pdfThumb : missing value
  
  property pdfPageText : missing value
  
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    pdfView’s setAllowsDragging_(false)
    
pdfView’s setDelegate_(me)
    
    
    pdfThumb’s setMaximumNumberOfColumns_(2)
    
pdfThumb’s setAllowsMultipleSelection_(false)
    
    –書類が変更になった(オープンされた場合)
    
set noter1 to current application’s NSNotificationCenter’s defaultCenter()
    
noter1’s addObserver_selector_name_object_(me, “pdfChange:”, current application’s PDFViewDocumentChangedNotification, missing value)
    
    –ページが変更になった
    
set noter2 to current application’s NSNotificationCenter’s defaultCenter()
    
noter2’s addObserver_selector_name_object_(me, “pdfChange:”, current application’s PDFViewPageChangedNotification, missing value)
    
    
    –ファイルを選択
    
set aFile to choose file of type “com.adobe.pdf”
    
set aFileString to aFile as Unicode text
    
dispPDFWithHFSpath_(aFileString)
    
    
  end applicationWillFinishLaunching_
  
  
  
  –プレビューウィンドウをセンタリング(見た目以外にとくに意味なし)
  
on applicationDidFinishLaunching_(aNotification)
    
    pdfPreviewWin’s |center|()
    
  end applicationDidFinishLaunching_
  
  
  
  –HFSパスの文字列を渡すとPDFViewに表示する
  
on dispPDFWithHFSpath_(aFileString)
    
    set aFileString to aFileString as Unicode text
    
    tell application “Finder”
      set aFileURL to (URL of file aFileString)
    end tell
    
    set aFileURL to aFileURL as Unicode text
    
set theURL to nsurl’s URLWithString_(aFileURL)
    
    set aPDFdoc to PDFDocument’s alloc()’s initWithURL_(theURL) –allocわすれてた、、、
    
pdfView’s setDocument_(aPDFdoc)
    
  end dispPDFWithHFSpath_
  
  
  on applicationShouldTerminate_(sender)
    return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  (*
–PDF内のURLなどのリンクをクリックした場合の動作??? これを無視させたかったのだが、、、、
on PDFViewOpenPDF_forRemoteGoToAction_(sender)

return false

end PDFViewOpenPDF_forRemoteGoToAction_
*)

  
  –ファイルの新規オープン、および表示ページが変更になった場合にnotificationでこちらを呼び出している
  
–ここで、選択中のページのノンブルを取得したい(まだできていない)
  
on pdfChange_(sender)
    set curPage to pdfView’s currentPage
    
–set curPageNum to curPage’s indexForPage
    
    set curPage2 to pdfThumb’s selectedPages
    
    set anItem to first item of curPage2
    
    log {anItem}
    
–> “Page 0; label = 1\n media (0.0, 0.0) [612.0, 792.0]\n crop (0.0, 0.0) [612.0, 792.0]\n rot 0\n ‘A Adobe\U00ae RGB (1998) Color Imag…’\n”
    
    set bItem to label of anItem –本当はPage(0からはじまるIndex)を取得したかったのだが、できなかった。なんでだろうねぇ
    
    pdfPageText’s setStringValue_(bItem as string)
    
  end pdfChange_
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に