gpt4 book ai didi

c# - 使用 ITextSharp 提取和更新现有 PDF 中的链接

转载 作者:可可西里 更新时间:2023-11-01 03:05:31 27 4
gpt4 key购买 nike

我需要将几个(阅读:很多)PDF 文件发布到网络上,但其中许多文件都有硬编码的 file://链接和指向非公共(public)位置的链接。我需要通读这些 PDF 并将链接更新到正确的位置。我已经开始使用 itextsharp 编写一个应用程序来读取目录和文件,查找 PDF 并遍历每一页。接下来我需要做的是找到链接,然后更新不正确的链接。

string path = "c:\\html";
DirectoryInfo rootFolder = new DirectoryInfo(path);

foreach (DirectoryInfo di in rootFolder.GetDirectories())
{
// get pdf
foreach (FileInfo pdf in di.GetFiles("*.pdf"))
{
string contents = string.Empty;
Document doc = new Document();
PdfReader reader = new PdfReader(pdf.FullName);

using (MemoryStream ms = new MemoryStream())
{
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
doc.Open();

for (int p = 1; p <= reader.NumberOfPages; p++)
{
byte[] bt = reader.GetPageContent(p);

}
}
}
}

坦率地说,一旦我获得了页面内容,当涉及到 iTextSharp 时,我就很迷茫了。我已经通读了 sourceforge 上的 itextsharp 示例,但确实没有找到我要找的东西。

如有任何帮助,我们将不胜感激。

谢谢。

最佳答案

如果您不了解 PDF 格式的内部结构和 iText/iTextSharp 的抽象/实现,这会有点复杂。您需要了解如何使用 PdfDictionary 对象并通过它们的 PdfName 键查找内容。一旦你得到它,你就可以通读 official PDF spec并很容易地浏览文档。如果您愿意的话,我已在适用的括号中包含了 PDF 规范的相关部分。

无论如何,PDF 中的链接存储为注释 (PDF Ref 12.5)。注释是基于页面的,因此您需要首先单独获取每个页面的注释数组。有许多不同类型的注释,因此您需要检查每个注释的 SUBTYPE 并查看其是否设置为 LINK (12.5.6.5) .每个链接应该有一个与之关联的ACTION 字典(12.6.2) 并且您想检查操作的S 键以查看它是什么类型的操作。有很多可能的链接,链接具体可以是内部链接或打开文件链接或播放声音链接或其他内容 (12.6.4.1)。您只查找类型为 URI 的链接(注意字母 I 而不是字母 L)。 URI 操作 (12.6.4.7) 有一个 URI 键,用于保存要导航到的实际地址。 (还有一个用于图像映射的 IsMap 属性,我无法想象有人会使用它。)

哇哦。还在读书吗?下面是一个完整的 VS 2010 C# WinForms 应用程序 based on my post here针对 iTextSharp 5.1.1.0。此代码主要做两件事:1) 创建一个示例 PDF,其中包含指向 Google.com 的链接,以及 2) 将该链接替换为指向 bing.com 的链接。代码应该有很好的注释,但请随时提出您可能有的任何问题。

using System;
using System.Text;
using System.Windows.Forms;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{

//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(WorkingFolder, "OldFile.pdf");
//Final file
private static readonly string OutputFile = Path.Combine(WorkingFolder, "NewFile.pdf");

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
CreateSamplePdf();
UpdatePdfLinks();
this.Close();
}

private static void CreateSamplePdf()
{
//Create our output directory if it does not exist
Directory.CreateDirectory(WorkingFolder);

//Create our sample PDF
using (iTextSharp.text.Document Doc = new iTextSharp.text.Document(PageSize.LETTER))
{
using (FileStream FS = new FileStream(BaseFile, FileMode.Create, FileAccess.Write, FileShare.Read))
{
using (PdfWriter writer = PdfWriter.GetInstance(Doc, FS))
{
Doc.Open();

//Turn our hyperlink blue
iTextSharp.text.Font BlueFont = FontFactory.GetFont("Arial", 12, iTextSharp.text.Font.NORMAL, iTextSharp.text.BaseColor.BLUE);

Doc.Add(new Paragraph(new Chunk("Go to URL", BlueFont).SetAction(new PdfAction("http://www.google.com/", false))));

Doc.Close();
}
}
}
}

private static void UpdatePdfLinks()
{
//Setup some variables to be used later
PdfReader R = default(PdfReader);
int PageCount = 0;
PdfDictionary PageDictionary = default(PdfDictionary);
PdfArray Annots = default(PdfArray);

//Open our reader
R = new PdfReader(BaseFile);
//Get the page cont
PageCount = R.NumberOfPages;

//Loop through each page
for (int i = 1; i <= PageCount; i++)
{
//Get the current page
PageDictionary = R.GetPageN(i);

//Get all of the annotations for the current page
Annots = PageDictionary.GetAsArray(PdfName.ANNOTS);

//Make sure we have something
if ((Annots == null) || (Annots.Length == 0))
continue;

//Loop through each annotation

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;

//Get the ACTION for the current annotation
PdfDictionary AnnotationAction = (PdfDictionary)AnnotationDictionary.Get(PdfName.A);

//Test if it is a URI action
if (AnnotationAction.Get(PdfName.S).Equals(PdfName.URI))
{
//Change the URI to something else
AnnotationAction.Put(PdfName.URI, new PdfString("http://www.bing.com/"));
}
}
}

//Next we create a new document add import each page from the reader above
using (FileStream FS = new FileStream(OutputFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
using (Document Doc = new Document())
{
using (PdfCopy writer = new PdfCopy(Doc, FS))
{
Doc.Open();
for (int i = 1; i <= R.NumberOfPages; i++)
{
writer.AddPage(writer.GetImportedPage(R, i));
}
Doc.Close();
}
}
}
}
}
}

编辑

我应该注意,这只会更改实际链接。文档中的任何文本都不会更新。注释绘制在文本之上,但实际上并没有真正绑定(bind)到下面的文本。这完全是另一个话题。

关于c# - 使用 ITextSharp 提取和更新现有 PDF 中的链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8140339/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com