How to insert files into folders of an existing PDF portfolio with folders using iTextsharp

余生颓废 提交于 2020-01-22 16:09:13

问题


Using the answers in How to merge PDFs into a PDF Portfolio?, I've been able to create an PDF portfolio using iTextSharp. However, using Adobe Acrobat I'm able to create folders, and I'm able to put files in those folders.

How do I create folders and how do I put files in those folders in a PDF portfolio using iTextSharp?

I've tried using a pdf inspector program to see the differences between a portfolio with and without folders, but I haven't been able to see any. I guess I'm looking in the wrong places

EDIT

For this specific use case of mine it is actually possible to create the PDF portfolio with folder up front. So it's way more important to be able to insert files in folders in an existing PDF portfolio as opposed to actually creating the folders themselves.


回答1:


Here is some proof of concept code that creates a new portfolio pdf with couple of folders and inserts an existing pdf file into each of those folders. This approach is based on using a text editor to look at a pdf file created using the sample code linked to in the original post, then using Acrobat to create a folder and move the embedded file into that folder, saving the pdf, then looking at the changes with a text editor. In the code I'm recreating the changes found while comparing the two versions of the portfolio pdf, so while it works (at least on my machine), it may not be the best way to accomplish the task.

If you want to view the before/after files like I did, create the portfolio using iTextsharp, then open with Acrobat and create a folder and move the embedded file(s) into the folder, then just save the file again using the save icon on the toolbar. Do not use the File -> Save As... option to save the file as a Portfolio PDF. Acrobat reorganizes the file and compresses or in some other way converts a lot of the file to binary data that you won't be able read in a text editor. I found that deleting the binary stream data made the structure much easier to follow. Just get rid of everything between each pair of stream/endstream keywords.

One thing that Acrobat does in portfolio pdfs is embed a flash file that provides animation and a more attractive theme for the portfolio. I wasn't able to figure out how to do that, so the resulting file from this code is a bit plain looking.

using System;
using System.IO;
using System.Linq;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.collection;

public class FolderWriter {
    private const string Folder = @"C:\Path\to\your\pdf\files";
    private const string File1 = @"Pdf File 1.pdf";
    private const string File2 = @"Pdf File 2.pdf";
    private readonly string file1Path = Path.Combine(Folder, File1);
    private readonly string file2Path = Path.Combine(Folder, File2);
    private readonly string[] keys = new[] {
        "Type",
        "File"
    };

    public void Write(Stream stream) {
        using (Document document = new Document()) {
            PdfWriter writer = PdfWriter.GetInstance(document, stream);

            document.Open();
            document.Add(new Paragraph("This document contains a collection of PDFs"));

            PdfIndirectReference parentFolderObjectReference = writer.PdfIndirectReference;
            PdfIndirectReference childFolder1ObjectReference = writer.PdfIndirectReference;
            PdfIndirectReference childFolder2ObjectReference = writer.PdfIndirectReference;

            PdfDictionary parentFolderObject = GetFolderDictionary(0);
            parentFolderObject.Put(new PdfName("Child"), childFolder1ObjectReference);
            parentFolderObject.Put(PdfName.NAME, new PdfString());

            PdfDictionary childFolder1Object = GetFolderDictionary(1);
            childFolder1Object.Put(PdfName.NAME, new PdfString("Folder 1"));
            childFolder1Object.Put(PdfName.PARENT, parentFolderObjectReference);
            childFolder1Object.Put(PdfName.NEXT, childFolder2ObjectReference);

            PdfDictionary childFolder2Object = GetFolderDictionary(2);
            childFolder2Object.Put(PdfName.NAME, new PdfString("Folder 2"));
            childFolder2Object.Put(PdfName.PARENT, parentFolderObjectReference);

            PdfCollection collection = new PdfCollection(PdfCollection.DETAILS);
            PdfCollectionSchema schema = CollectionSchema();
            collection.Schema = schema;
            collection.Sort = new PdfCollectionSort(keys);
            collection.Put(new PdfName("Folders"), parentFolderObjectReference);
            writer.Collection = collection;

            PdfFileSpecification fs;
            PdfCollectionItem item;

            fs = PdfFileSpecification.FileEmbedded(writer, file1Path, File1, null);
            item = new PdfCollectionItem(schema);
            item.AddItem("Type", "pdf");
            fs.AddCollectionItem(item);
            // the description is apparently used to place the 
            // file in a particular folder.  The number between the < and >
            // is used to put the file in the folder that has the matching id
            fs.AddDescription(GetDescription(1, File1), false);
            writer.AddFileAttachment(fs);

            fs = PdfFileSpecification.FileEmbedded(writer, file2Path, File2, null);
            item = new PdfCollectionItem(schema);
            item.AddItem("Type", "pdf");
            fs.AddCollectionItem(item);
            fs.AddDescription(GetDescription(2, File2), false);
            writer.AddFileAttachment(fs);

            writer.AddToBody(parentFolderObject, parentFolderObjectReference);
            writer.AddToBody(childFolder1Object, childFolder1ObjectReference);
            writer.AddToBody(childFolder2Object, childFolder2ObjectReference);

            document.Close();
        }
    }

    private static string GetDescription(int id, string fileName) {
        return string.Format("<{0}>{1}", id, fileName);
    }

    private static PdfDictionary GetFolderDictionary(int id) {
        PdfDictionary dic = new PdfDictionary(new PdfName("Folder"));
        dic.Put(PdfName.CREATIONDATE, new PdfDate(DateTime.Now));
        dic.Put(PdfName.MODDATE, new PdfDate(DateTime.Now));
        dic.Put(PdfName.ID, new PdfNumber(id));
        return dic;
    }

    private static PdfCollectionSchema CollectionSchema() {
        PdfCollectionSchema schema = new PdfCollectionSchema();
        PdfCollectionField type = new PdfCollectionField("File type", PdfCollectionField.TEXT);
        type.Order = 0;
        schema.AddField("Type", type);
        PdfCollectionField filename = new PdfCollectionField("File", PdfCollectionField.FILENAME);
        filename.Order = 1;
        schema.AddField("File", filename);
        return schema;
    }
}



回答2:


iTextsharp can't create folders, but you can create and find PDF bookmark.

See:

  • http://www.mikesdotnetting.com/Article/84/iTextSharp-Links-and-Bookmarks
  • http://www.geek-tutorials.com/java/itext/itext_bookmark_anchor.php


来源:https://stackoverflow.com/questions/13027074/how-to-insert-files-into-folders-of-an-existing-pdf-portfolio-with-folders-using

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!