iTextSharp - 在合并PDF中使用PDFAction.GotoLocalPage [英] iTextSharp - Using PDFAction.GotoLocalPage in Merged PDF

查看:323
本文介绍了iTextSharp - 在合并PDF中使用PDFAction.GotoLocalPage的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一些代码,将多个PDF合并为一个PDF,然后我从MemoryStream中显示。这很好用。我需要做的是在文件的末尾添加一个目录,其中包含指向每个PDF的开头的链接。我计划使用GotoLocalPage操作执行此操作,该操作具有页码选项,但似乎不起作用。如果我将对下面代码的操作更改为像PDFAction.FIRSTPAGE这样的预设,那么它可以正常工作。这不起作用,因为我使用PDFCopy对象作为GotoLocalPage的writer参数吗?

I have written some code that merges together multiple PDF's into a single PDF that I then display from the MemoryStream. This works great. What I need to do is add a table of contents to the end of the file with links to the start of each of the individual PDF's. I planned on doing this using the GotoLocalPage action which has an option for page numbers but it doesn't seem to work. If I change the action to the code below to one of the presset ones like PDFAction.FIRSTPAGE it works fine. Does this not work because I am using the PDFCopy object for the writer parameter of GotoLocalPage?

Document mergedDoc = new Document();
MemoryStream ms = new MemoryStream();
PdfCopy copy = new PdfCopy(mergedDoc, ms);
mergedDoc.Open();

MemoryStream tocMS = new MemoryStream();
Document tocDoc = null;
PdfWriter tocWriter = null;

for (int i = 0; i < filesToMerge.Length; i++)
{
     string filename = filesToMerge[i];

     PdfReader reader = new PdfReader(filename);
     copy.AddDocument(reader);

     // Initialise TOC document based off first file
     if (i == 0)
     {
          tocDoc = new Document(reader.GetPageSizeWithRotation(1));
          tocWriter = PdfWriter.GetInstance(tocDoc, tocMS);
          tocDoc.Open();
     }

     // Create link for TOC, added random number of 3 for now
     Chunk link = new Chunk(filename);
     PdfAction action = PdfAction.GotoLocalPage(3, new PdfDestination(PdfDestination.FIT), copy);
     link.SetAction(action);
     tocDoc.Add(new Paragraph(link));
}

// Add TOC to end of merged PDF
tocDoc.Close();
PdfReader tocReader = new PdfReader(tocMS.ToArray());
copy.AddDocument(tocReader);

copy.Close();

displayPDF(ms.ToArray());

我想另一种方法是链接到命名元素(而不是页码)但我可以在添加到合并文档之前,看看如何在每个文件的开头添加一个'invisible'元素?

I guess an alternative would be to link to a named element (instead of page number) but I can't see how to add an 'invisible' element to the start of each file before adding to the merged document?

推荐答案

我只会两次通过。在第一次传递中,按原样进行合并,但也记录它应链接到的文件名和页码。在第二次传递中,使用 PdfStamper ,这将允许您访问 ColumnText ,您可以使用一般抽象,如段落 in。以下是显示此项的示例:

I would just go with two passes. In your first pass, do the merge as you are but also record the filename and page number it should link to. In your second pass, use a PdfStamper which will give you access to a ColumnText that you can use general abstractions like Paragraph in. Below is a sample that shows this off:

由于我没有您的文件,下面是代码创建10个带有随机页数的文档,每个文档仅用于测试目的。 (您显然不需要执行此部分。)它还会创建一个简单的字典,其中伪文件名作为键,而PDF中的原始字节作为值。你有一个真正的文件集合可以使用,但你应该能够适应那个部分。

Since I don't have your documents, the below code creates 10 documents with a random number of pages each just for testing purposes. (You obviously don't need to do this part.) It also creates a simple dictionary with a fake file name as the key and the raw bytes from the PDF as a value. You have a true file collection to work with but you should be able to adapt that part.

//Create a bunch of files, nothing special here
//files will be a dictionary of names and the raw PDF bytes
Dictionary<string, byte[]> Files = new Dictionary<string, byte[]>();
var r = new Random();
for (var i = 1; i <= 10; i++) {
    using (var ms = new MemoryStream()) {
        using (var doc = new Document()) {
            using (var writer = PdfWriter.GetInstance(doc, ms)) {
                doc.Open();

                //Create a random number of pages
                for (var j = 1; j <= r.Next(1, 5); j++) {
                    doc.NewPage();
                    doc.Add(new Paragraph(String.Format("Hello from document {0} page {1}", i, j)));
                }
                doc.Close();
            }
        }
        Files.Add("File " + i.ToString(), ms.ToArray());
    }
}

下一个块合并PDF。这与你的代码大致相同,除了不是在这里写一个TOC,我只是跟踪我将来想写的东西。我在哪里使用 file.value 你会使用你的完整文件路径以及我在哪里 file.key 您将使用您的文件名。

This next block merges the PDFs. This is mostly the same as your code except that instead of writing a TOC here I'm just keeping track of what I want to write in the future. Where I'm using file.value you'd use your full file path and where I'm using file.key you'd use your file's name instead.

//Dictionary of file names (for display purposes) and their page numbers
var pages = new Dictionary<string, int>();

//PDFs start at page 1
var lastPageNumber = 1;

//Will hold the final merged PDF bytes
byte[] mergedBytes;

//Most everything else below is standard
using (var ms = new MemoryStream()) {
    using (var document = new Document()) {
        using (var writer = new PdfCopy(document, ms)) {
            document.Open();

            foreach (var file in Files) {

                //Add the current page at the previous page number
                pages.Add(file.Key, lastPageNumber);

                using (var reader = new PdfReader(file.Value)) {
                    writer.AddDocument(reader);

                    //Increment our current page index
                    lastPageNumber += reader.NumberOfPages;
                }
            }
        }
    }
    mergedBytes = ms.ToArray();
}

这最后一个块实际上写了TOC。如果我们使用 PdfStamper ,我们可以创建 ColumnText ,这允许我们使用 Paragraphs

This last block actually writes the TOC. If we use a PdfStamper we can create a ColumnText which allows us to use Paragraphs

//Will hold the final PDF
byte[] finalBytes;
using (var ms = new MemoryStream()) {
    using (var reader = new PdfReader(mergedBytes)) {
        using (var stamper = new PdfStamper(reader, ms)) {

            //The page number to insert our TOC into
            var tocPageNum = reader.NumberOfPages + 1;

            //Arbitrarily pick one page to use as the size of the PDF
            //Additional logic could be added or this could just be set to something like PageSize.LETTER
            var tocPageSize = reader.GetPageSize(1);

            //Arbitrary margin for the page
            var tocMargin = 20;

            //Create our new page
            stamper.InsertPage(tocPageNum, tocPageSize);

            //Create a ColumnText object so that we can use abstractions like Paragraph
            var ct = new ColumnText(stamper.GetOverContent(tocPageNum));

            //Set the working area
            ct.SetSimpleColumn(tocPageSize.GetLeft(tocMargin), tocPageSize.GetBottom(tocMargin), tocPageSize.GetRight(tocMargin), tocPageSize.GetTop(tocMargin));

            //Loop through each page
            foreach (var page in pages) {
                var link = new Chunk(page.Key);
                var action = PdfAction.GotoLocalPage(page.Value, new PdfDestination(PdfDestination.FIT), stamper.Writer);
                link.SetAction(action);
                ct.AddElement(new Paragraph(link));
            }

            ct.Go();
        }
    }
    finalBytes = ms.ToArray();
}

这篇关于iTextSharp - 在合并PDF中使用PDFAction.GotoLocalPage的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆