ShiftPageNumbers with iTextSharp

折月煮酒 提交于 2019-12-13 01:24:32

问题


I'm having some trouble using iTextSharp to merge some PDFs while preserving the bookmarks. I've written the following hackish code to test an idea, but the ShiftPageNumbers method doesn't seem to even be working for me. Does anyone have any idea why?

string[] files = Directory.GetFiles(folder);
string path = Path.GetDirectoryName(files[0]);
IList<Dictionary<string, object>> oldBookmarks
    = SimpleBookmark.GetBookmark(new PdfReader(files[0]));
List<Dictionary<string, object>> newBookmarks = new List<Dictionary<string, object>>();

FileStream outFile = new FileStream(output, FileMode.Create);
PdfConcatenate newPdf = new PdfConcatenate(outFile);

switch (oldBookmarks.Count())
{
    case 0:
        break;

    case 1:
        oldBookmarks = (IList<Dictionary<string, object>>)(oldBookmarks[0])["Kids"];
        break;

    default:
        break;
}

files = oldBookmarks.Select(b => b["File"]).Cast<string>().ToArray();

foreach (string filename in files)
{
    Console.Write:ine(filename);
    PdfReader reader = new PdfReader(Path.Combine(path, filename));
    newPdf.AddPages(reader);

    List<Dictionary<string, object>> tempBookmarks =
        oldBookmarks.Where(b => (string)b["File"] == filename).ToList();

    // handles bookmarks
    SimpleBookmark.ShiftPageNumbers(tempBookmarks, length, null);
    newBookmarks.AddRange(tempBookmarks);
    length += reader.NumberOfPages;

    reader.Close();
}

newPdf.Writer.Outlines = newBookmarks;
newPdf.Close();

回答1:


In the end, I wound up using a recursive function to adjust the page numbers. I figured it was easiest to show if I simply included the code for the entire application. This program is designed to compile eBooks published by the American Radio Relay League (ARRL), which are broken up into many PDFs that all contain the same list of bookmarks. Each first-level bookmark and its children link to a different PDF file. Therefore, a standard PDF merging program will not correctly preserve the bookmarks.

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

namespace ARRL_Book_Compiler
{
    internal class Program
    {
        private const string ACTION_KEY = "Action";
        private const string FILE_KEY = "File";
        private const string KIDS_KEY = "Kids";
        private const string PAGE_KEY = "Page";
        private const char DELIM = ' ';

        private static void Main(string[] args)
        {
            if (args.Count() != 2)
            {
                Console.WriteLine("Arg 1: PDF directory");
                Console.WriteLine("Arg 2: Output filename");
                Environment.Exit(1);
            }

            Merge(args[0], args[1]);
        }

        /// <summary>
        /// Compiles ARRL books.
        /// </summary>
        /// <param name="folder">Directory containing all the PDFs in the entire book.</param>
        /// <param name="output">Path and filename of the output (compiled) PDF.</param>
        private static void Merge(string folder, string output)
        {
            int offset = 1;  // Setting to 0 causes all bookmarks to be off by 1
            string[] dirFiles
                = Directory.GetFiles(folder).Where(f => f.EndsWith("pdf")).ToArray();  // PDFs in directory
            IList<Dictionary<string, object>> oldBookmarks
                = SimpleBookmark.GetBookmark(new PdfReader(dirFiles[0]));
            List<Dictionary<string, object>> newBookmarks = new List<Dictionary<string, object>>();

            FileStream outFile = new FileStream(output, FileMode.Create);
            PdfConcatenate newPdf = new PdfConcatenate(outFile);

            if (oldBookmarks.Count() == 1)
            {
                oldBookmarks = (IList<Dictionary<string, object>>)(oldBookmarks[0])[KIDS_KEY];
            }

            string[] bFiles
                = oldBookmarks.Select(b => b[FILE_KEY]).Cast<string>().ToArray();  // get files in bookmark order
            IEnumerable<string> missingFiles = bFiles.Except(dirFiles.Select(f => Path.GetFileName(f)));

            if (missingFiles.Any())
            {
                Console.Error.WriteLine("The following files are present in the bookmarks but not in the directory:");
                foreach (string filename in missingFiles) Console.Error.WriteLine(filename);
                Environment.Exit(2);
            }

            for(int i = 0; i < bFiles.Count(); i++)
            {
                Console.Write(string.Format("\r{0}% complete", (int)((i + 1f)/bFiles.Count()*100)));
                string filename = bFiles[i];
                PdfReader reader = new PdfReader(Path.Combine(folder, filename));
                List<Dictionary<string, object>> tempBookmarks =
                    oldBookmarks.Where(b => b.ContainsKey(FILE_KEY) && (string)b[FILE_KEY] == filename).ToList();

                // handles bookmarks
                newBookmarks.AddRange(ModifyBookmarks(  // Exception if LINQ can't find FILE_KEY key in ANY list item
                    oldBookmarks.Where(b => b.ContainsKey(FILE_KEY) && (string)b[FILE_KEY] == filename).ToList(),
                    offset));
                offset += reader.NumberOfPages;

                newPdf.AddPages(reader);
                reader.Close();
            }

            newPdf.Writer.Outlines = newBookmarks;
            newPdf.Close();
        }

        private static List<Dictionary<string, object>>
            ModifyBookmarks(List<Dictionary<string, object>> list, int offset)
        {
            for (int i = 0; i < list.Count(); i++)
            {
                string pageKey = (string)list[i][PAGE_KEY];
                int index = pageKey.IndexOf(DELIM);
                list[i][PAGE_KEY] = (int.Parse(pageKey.Substring(0, index)) + offset).ToString()
                    + pageKey.Substring(index);

                if (list[i].ContainsKey(FILE_KEY)) list[i].Remove(FILE_KEY);
                if (list[i].ContainsKey(ACTION_KEY)) list[i][ACTION_KEY] = "GoTo";

                if (list[i].ContainsKey(KIDS_KEY))
                    list[i][KIDS_KEY] = ModifyBookmarks((List<Dictionary<string, object>>)list[i][KIDS_KEY], offset);
            }

            return list;
        }
    }
}


来源:https://stackoverflow.com/questions/30171606/shiftpagenumbers-with-itextsharp

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