2

我正在开发一个应用程序,其中将 word 文档转换为 pdf 格式。我的问题太复杂了,请帮帮我。

我的 word doc 有目录、书签、尾注和超链接。当我将此文档另存为 pdf 时,只会转换书签。经过长时间的研究,我发现 PDF 文档不支持书签到书签超链接,它需要页码或命名目的地。

因此,我为此目的选择了命名目的地,但我又被卡住了,因为简单的"save as“无法在 pdf doc 中生成命名目的地。所以我在 adobe PDF 打印机上打印了 word doc,并根据需要获得了命名目的地,但同样,这个文档也没有里面有书签也没有超链接所以我决定从一个单词生成两个pdf,第一个是另存为选项,第二个是打印。

  1. test.pdf(另存为)(包含书签、超链接)
  2. test_p.pdf(通过打印)(仅包含命名目的地)

然后我再次研究并找到了一种方法,可以test_p.pdf通过 itextsharp 的函数将所有命名的目的地从 XML 中提取出来。但不幸的是,我没有任何方法可以将其导入回来……这xml就是test.pdf我来这里的原因。

如果这种方法可以,请指导我下一步该怎么做。否则向我建议任何其他方法来完成这项任务。

4

1 回答 1

2

前段时间我写了一个类来替换我的 PDF 文件中的 url:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using iTextSharp.text.pdf;

namespace ReplaceLinks
{
    public class ReplacePdfLinks
    {
        Dictionary<string, PdfObject> _namedDestinations;
        PdfReader _reader;

        public string InputPdf { set; get; }
        public string OutputPdf { set; get; }
        public Func<Uri, string> UriToNamedDestination { set; get; }

        public void Start()
        {
            updatePdfLinks();
            saveChanges();
        }

        private PdfArray getAnnotationsOfCurrentPage(int pageNumber)
        {
            var pageDictionary = _reader.GetPageN(pageNumber);
            var annotations = pageDictionary.GetAsArray(PdfName.ANNOTS);
            return annotations;
        }

        private static bool hasAction(PdfDictionary annotationDictionary)
        {
            return annotationDictionary.Get(PdfName.SUBTYPE).Equals(PdfName.LINK);
        }

        private static bool isUriAction(PdfDictionary annotationAction)
        {
            return annotationAction.Get(PdfName.S).Equals(PdfName.URI);
        }

        private void replaceUriWithLocalDestination(PdfDictionary annotationAction)
        {
            var uri = annotationAction.Get(PdfName.URI) as PdfString;
            if (uri == null)
                return;

            if (string.IsNullOrWhiteSpace(uri.ToString()))
                return;

            var namedDestination = UriToNamedDestination(new Uri(uri.ToString()));
            if (string.IsNullOrWhiteSpace(namedDestination))
                return;

            PdfObject entry;
            if (!_namedDestinations.TryGetValue(namedDestination, out entry))
                return;

            annotationAction.Remove(PdfName.S);
            annotationAction.Remove(PdfName.URI);

            var newLocalDestination = new PdfArray();
            annotationAction.Put(PdfName.S, PdfName.GOTO);
            var xRef = ((PdfArray)entry).First(x => x is PdfIndirectReference);
            newLocalDestination.Add(xRef);
            newLocalDestination.Add(PdfName.FITH);
            annotationAction.Put(PdfName.D, newLocalDestination);
        }

        private void saveChanges()
        {
            using (var fileStream = new FileStream(OutputPdf, FileMode.Create, FileAccess.Write, FileShare.None))
            using (var stamper = new PdfStamper(_reader, fileStream))
            {
                stamper.Close();
            }
        }

        private void updatePdfLinks()
        {
            _reader = new PdfReader(InputPdf);
            _namedDestinations = _reader.GetNamedDestinationFromStrings();

            var pageCount = _reader.NumberOfPages;
            for (var i = 1; i <= pageCount; i++)
            {
                var annotations = getAnnotationsOfCurrentPage(i);
                if (annotations == null || !annotations.Any())
                    continue;

                foreach (var annotation in annotations.ArrayList)
                {
                    var annotationDictionary = (PdfDictionary)PdfReader.GetPdfObject(annotation);

                    if (!hasAction(annotationDictionary))
                        continue;

                    var annotationAction = annotationDictionary.Get(PdfName.A) as PdfDictionary;
                    if (annotationAction == null)
                        continue;

                    if (!isUriAction(annotationAction))
                        continue;

                    replaceUriWithLocalDestination(annotationAction);
                }
            }
        }
    }    
}

要使用它:

    new ReplacePdfLinks
    {
        InputPdf = @"test.pdf",
        OutputPdf = "mod.pdf",
        UriToNamedDestination = uri =>
        {
            if (uri.Host.ToLowerInvariant().Contains("google.com"))
            {
                return "entry1";
            }

            return string.Empty;
        }
    }.Start();

此示例将修改所有包含 google.com 的 url,以指向特定的命名目的地“entry1”。这是测试上述类的示例文件:

void WriteFile()
{
    using (var doc = new Document(PageSize.LETTER))
    {
        using (var fs = new FileStream("test.pdf", FileMode.Create))
        {
            using (var writer = PdfWriter.GetInstance(doc, fs))
            {
                doc.Open();
                var blueFont = FontFactory.GetFont("Arial", 12, Font.NORMAL, BaseColor.BLUE);
                doc.Add(new Chunk("Go to URL", blueFont).SetAction(new PdfAction("http://www.google.com/", false)));

                doc.NewPage();
                doc.Add(new Chunk("Go to Test", blueFont).SetLocalGoto("entry1"));

                doc.NewPage();
                doc.Add(new Chunk("Test").SetLocalDestination("entry1"));

                doc.Close();
            }
        }
    }
}
于 2013-04-06T07:42:26.230 回答