Это немного сложно, если вы не знаете внутренности формата PDF и его абстракцию / реализацию iText / iTextSharp.Вам нужно понять, как использовать PdfDictionary
объекты и искать их по ключу PdfName
.Как только вы это получите, вы можете прочитать официальную спецификацию в формате PDF и довольно легко осмотреть документ.Если вам не безразлично, я включил соответствующие части спецификации 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
для карт изображений, которое я даже не могу представить, чтобы кто-нибудь использовал.)
Вот так.Все еще читаете?Ниже полнофункциональное приложение Win 2010 C # для Win 2010 C # 1025 * на основе моего поста с таргетингом на 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();
}
}
}
}
}
}
РЕДАКТИРОВАТЬ
Я должен отметить, что это только меняет фактическоессылка на сайт.Любой текст в документе не будет обновлен.Аннотации рисуются поверх текста, но в любом случае не связаны с текстом внизу.Это совсем другая тема.