You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Ghostscript检测PDF中的/OpenAction并修改默认打开页

检测PDF中的/OpenAction(基于Ghostscript PostScript脚本)

我的PDF的Pages字典及相关Catalog内容如下:

<< /Type /Pages /Kids [
5 0 R
142 0 R
225 0 R
296 0 R
302 0 R
308 0 R
314 0 R
4 0 R
336 0 R
] /Count 9
>>
endobj
341 0 obj
<< /Type /Outlines /Count 1 /First 342 0 R /Last 342 0 R >>
endobj
1 0 obj
<< /Type /Catalog /Pages 3 0 R
/Outlines 341 0 R
/OpenAction [4 0 R /XYZ null null null]
/PageLabels<<
/Nums [0 <<
/S /D
>>]
>>

因为这个/OpenAction设置,PDF总是打开在第8页而非首页。我已经通过在PostScript文件中添加[/Page 1 /DOCVIEW pdfmark]重置了默认打开页,但现在需要用Ghostscript检测PDF是否存在/OpenAction。

我基于Ghostscript自带的PS示例写了一段脚本,可以获取PDF的各类信息,但无法检测/OpenAction,脚本如下:

/PDFContext << >> .PDFInit def
(D:\Test\test.pdf) (r) file PDFContext .PDFStream

PDFContext .PDFInfo

dup /Title knownoget { (Title: ) print write-doc-string () = flush } if
dup /Author knownoget { (Author: ) print write-doc-string () = flush } if
dup /Subject knownoget { (Subject: ) print write-doc-string () = flush } if
dup /Keywords knownoget { (Keywords: ) print write-doc-string () = flush } if
dup /Creator knownoget { (Creator: ) print write-doc-string () = flush } if
dup /Producer knownoget { (Producer: ) print write-doc-string () = flush } if
dup /CreationDate knownoget { (CreationDate: ) print write-doc-string () = flush } if
dup /ModDate knownoget { (ModDate: ) print write-doc-string () = flush } if

(Pages: ) print dup /NumPages get = flush

/NumPages get 0 1 3 -1 roll 1 sub
{
    dup
    PDFContext exch .PDFPageInfoExt exch
    ( - page: ) print 1 add =print ( - ) print

    dup /MediaBox knownoget
    {
        /MediaBox exch def 
        (left ) print MediaBox 0 get =print
        (, top ) print MediaBox 1 get =print
        (, width ) print MediaBox 2 get =print
        (, height ) print MediaBox 3 get =print
    } 
    { 
        (left 0, top 0, width 0, height 0) print
    } ifelse
    dup /Rotate knownoget
    { 
        (, rotate ) print =print
    }
    {
        (, rotate 0) print
    } ifelse
    (, annotations ) print
    dup /Annots knownoget
    {
        (yes) print
    }
    {
        (no) print
    } ifelse
    (\n) print
} for flush

PDFContext .PDFClose

解决方案:添加/OpenAction检测逻辑

要检测/OpenAction,需从PDF的Catalog字典中读取该字段。Ghostscript的PDF API提供了.PDFCatalog方法可直接获取Catalog字典,之后判断是否存在/OpenAction键即可。

修改后的完整脚本(保留原有功能,新增检测模块):

/PDFContext << >> .PDFInit def
(D:\Test\test.pdf) (r) file PDFContext .PDFStream

% 获取文档基础信息(原有逻辑保留)
PDFContext .PDFInfo

dup /Title knownoget { (Title: ) print write-doc-string () = flush } if
dup /Author knownoget { (Author: ) print write-doc-string () = flush } if
dup /Subject knownoget { (Subject: ) print write-doc-string () = flush } if
dup /Keywords knownoget { (Keywords: ) print write-doc-string () = flush } if
dup /Creator knownoget { (Creator: ) print write-doc-string () = flush } if
dup /Producer knownoget { (Producer: ) print write-doc-string () = flush } if
dup /CreationDate knownoget { (CreationDate: ) print write-doc-string () = flush } if
dup /ModDate knownoget { (ModDate: ) print write-doc-string () = flush } if

(Pages: ) print dup /NumPages get = flush

% 核心:检测/OpenAction
(OpenAction: ) print
PDFContext .PDFCatalog % 获取根目录Catalog字典
dup /OpenAction knownoget {
    % 存在/OpenAction时输出细节
    (Present, value: ) print
    % 处理两种常见格式:数组或字典
    dup type /arraytype eq {
        % 数组形式(如示例中的[4 0 R /XYZ null null null])
        { =print ( ) print } forall
    } {
        % 字典形式(如<< /Type /Action /S /GoTo /D [...] >>)
        dup ==
    } ifelse
    () = flush
} {
    % 不存在时输出提示
    (Not present) = flush
} ifelse

% 原有页面信息逻辑保留
/NumPages get 0 1 3 -1 roll 1 sub
{
    dup
    PDFContext exch .PDFPageInfoExt exch
    ( - page: ) print 1 add =print ( - ) print

    dup /MediaBox knownoget
    {
        /MediaBox exch def 
        (left ) print MediaBox 0 get =print
        (, top ) print MediaBox 1 get =print
        (, width ) print MediaBox 2 get =print
        (, height ) print MediaBox 3 get =print
    } 
    { 
        (left 0, top 0, width 0, height 0) print
    } ifelse
    dup /Rotate knownoget
    { 
        (, rotate ) print =print
    }
    {
        (, rotate 0) print
    } ifelse
    (, annotations ) print
    dup /Annots knownoget
    {
        (yes) print
    }
    {
        (no) print
    } ifelse
    (\n) print
} for flush

PDFContext .PDFClose

关键说明:

  • 使用PDFContext .PDFCatalog直接获取PDF的根目录(Catalog),/OpenAction是Catalog的顶层属性。
  • 兼容/OpenAction的两种常见格式:
    1. 数组形式:直接遍历数组元素输出内容;
    2. 字典形式:用==命令完整输出字典结构,适合包含更多属性的动作定义。
  • 脚本完全保留原有功能,仅新增/OpenAction检测模块,不影响其他信息获取。

内容的提问来源于stack exchange,提问作者Kees van Spelde

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:05:23