Ответ 1
Это немного сложно, если вы не знаете внутренности формата 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
для карт изображений, которые я не могу себе представить никому, использующим.)
Уф. Все еще читаете? Ниже приведено полное приложение VS 2010 С# WinForms app на основе моего сообщения здесь, нацеленное на 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();
}
}
}
}
}
}
ИЗМЕНИТЬ
Я должен отметить, что это только изменяет фактическую ссылку. Любой текст внутри документа не будет обновляться. Аннотации рисуются поверх текста, но на самом деле не привязаны к тексту под ним. Это еще одна тема.