目下、「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 |