c# - iTextSharp 从内容 PDF C# 中获取操作
问题描述
我有一个带有 TOC 的 PDF:
使用 iTextSharp.dll 我试图获取注释然后对这些注释执行操作。然后我想操纵/更改链接以指向另一个页面。例如,如果目录中的第 1 章指向第 5 页,我希望当我单击链接时它指向第 2 页。由于某种原因,注释上的操作为空,因此我无法操作此数据。下面的代码有效,但一直提供 null操作。我不明白为什么会这样。重现有问题的pdf
- 创建一个 3 页的 word 文档
- 第 1 页为目录,第 2 页为第 1 章,第 3 页为第 2 章
- 导出为 PDF
- 拥有 PDF 后,目录应该是“可点击的”。
然后我希望能够操纵它点击的位置。谢谢你。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
using System.Collections;
namespace PDFLinks
{
class Program
{
//Folder that we are working in
//private static readonly string WorkingFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Hyperlinked PDFs");
//Sample PDF
private static readonly string BaseFile = Path.Combine("C:\\Temp", "TableOfContentsTest.pdf");
//Final file
private static readonly string OutputFile = Path.Combine("C:\\Temp", "NewFile.pdf");
static void Main(string[] args)
{
//Setup some variables to be used later
PdfReader R = default(PdfReader);
int PageCount = 0;
//Open our reader
R = new PdfReader(BaseFile);
//Get the page cont
PageCount = R.NumberOfPages;
Console.WriteLine("Page Count= " + PageCount);
//Loop through each page
//for (int i = 1; i <= PageCount; i++)
//{
//Get the current page
PdfDictionary PageDictionary = R.GetPageN(1);
//Get all of the annotations for the current page
PdfArray Annots = PageDictionary.GetAsArray(PdfName.ANNOTS);
//Make sure we have something
if ((Annots == null) || (Annots.Length == 0))
{
Console.WriteLine("nothing");
}
//Loop through each annotation
if (Annots != null)
{
Console.WriteLine("ANNOTS Not Null" + Annots[0]);
foreach (PdfObject A in Annots.ArrayList)
{
//Convert the itext-specific object as a generic PDF object
PdfDictionary AnnotationDictionary = (PdfDictionary)PdfReader.GetPdfObject(A);
//Make sure this annotation has a link
if (!AnnotationDictionary.Get(PdfName.SUBTYPE).Equals(PdfName.LINK))
continue;
//Make sure this annotation has an ACTION
if (AnnotationDictionary.Get(PdfName.A) == null)
continue;
if (AnnotationDictionary.Get(PdfName.A) != null)
{
Console.WriteLine("ACTION Not Null");
}
//Get the ACTION for the current annotation
PdfDictionary AnnotationAction = AnnotationDictionary.GetAsDict(PdfName.A);
// Test if it is a URI action (There are tons of other types of actions,
// some of which might mimic URI, such as JavaScript,
// but those need to be handled seperately)
if (AnnotationAction.Get(PdfName.S).Equals(PdfName.URI))
{
PdfString Destination = AnnotationAction.GetAsString(PdfName.URI);
string url1 = Destination.ToString();
}
}
}
//}
}
}
}
解决方案
目的地_
在您的链接注释中,您只查找一个动作条目,但也可能有一个目标条目,参见。PDF 规范 ISO 32000-2:
字典 (可选;PDF 1.1)激活链接注释时应执行的操作(参见 12.6,“操作”)。
目标 数组、名称或字节字符串 (可选;如果存在A条目则不允许)激活注释时应显示的目标(12.3.2,“目标”)。
(ISO 32000-2 表 176 - 特定于链接注释的附加条目)
有多种类型的目的地,参见。这个答案,特别是那里的规范引用,但是那里处理其中一些类型的代码也可能很有趣。
行动_
即使对于带有A动作的Link,您也只考虑a)第一个动作和b)类型URI的动作。
多个动作
Link可以触发一系列动作,后续动作从第一个动作引用,参见。规范
下一个 字典或数组 (可选;PDF 1.2)在此字典表示的动作之后应执行的下一个动作或动作序列。该值可以是单个动作字典或应按顺序执行的动作字典数组;进一步讨论见注 1。
注 1 动作字典的下一个条目 (PDF 1.2) 允许将动作序列链接在一起。例如,用鼠标单击链接注释的效果可能是播放声音、跳转到新页面和启动电影。请注意,Next条目不限于单个动作,而是可能包含一组动作,每个动作又可能有自己的Next条目。因此,动作可以形成树而不是简单的链表。
(ISO 32000-2 表 196——所有动作词典共有的条目)
正如注释中的示例所暗示的那样,跳转到新页面不一定是Link的第一个操作,因此对于您的任务,您应该明确检查Link的所有操作。
动作类型
统一资源标识符(URI) 是一个字符串,用于标识(解析为)Internet 上的资源——通常是作为超文本链接目标的文件,尽管它也可以解析为查询或其他实体。(URI 在Internet RFC 3986,统一资源标识符 (URI):通用语法中进行了描述。)
URI操作导致 URI 被解析。
(ISO 32000-2,第 12.6.4.8 节 URI 操作)
因此,不太可能在 PDF 的 TOC 中找到URI操作。您最好寻找GoTo操作。
转到操作将视图更改为指定的目标(页面、位置和放大倍数)。“表 202 - 特定于转到操作的附加条目”显示特定于此类操作的操作字典条目。
注意在链接注释或大纲项的A条目中指定转到操作(请参阅“表 176 — 特定于链接注释的附加条目”和“表 151 — 大纲项字典中的条目”)具有相同的效果直接使用Dest条目指定目的地。
(ISO 32000-2 第 12.6.4.2 节 Go-To 操作)
D 名称、字节串或数组 (必需)要跳转到的目标(参见 12.3.2,“目标”)。
(ISO 32000-2 表 202 - 特定于首选操作的附加条目)
因此,在检查GoTo操作时,您最终必须处理与检查答案顶部讨论的直接链接目标时相同类型的目标规范。
推荐阅读
- docker - 在单个基础架构中部署多个不太可用的应用程序以优化云成本的最佳方法
- ios - 尝试读取无主引用但对象已被释放 Swift 5
- linux - 有什么方法可以在 WSL 下运行 perf 吗?
- python - 如何拆分列表中的项目,用括号括起来,用 , 分隔
- java - 为什么 && 作为回报和铸造?
- python - 如何为要在 windows10 上的 python3.8 32bits 上运行的库打包轮子?
- google-apps-script - Apps Script 适合公共服务应用吗?
- javascript - 无法使用 ajax 开发登录页面
- c++ - 使用 std::move over ofstream
- scala - 基于优先级匹配的 Spark SQL 连接