iTextSharpでPDF結合

以前、「iTextSharpで日本語出力」を紹介しましたが、今回は複数のPDFファイルを選択して、それらを結合出力する方法をご紹介します。

とりあえず単純に結合

今回もフォームはシンプルにこんな感じ
以下がソース

        private void btnJoin_Click(object sender, EventArgs e)
        {
            string joinPdfPath = "C:\\join.pdf";
            // ファイル選択ダイアログを表示
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "PDFファイル(*.pdf)|*.pdf";
            ofd.Title = "結合するPDFを選択してください";
            ofd.Multiselect = true; // 複数ファイル選択
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                // PDFドキュメント作成
                Document joinDc = new Document();
                // 結合先PDFファイルの作成
                FileStream joinFs = new FileStream(joinPdfPath, FileMode.Create, FileAccess.Write);
                // 結合先PDFオブジェクトとPDFファイルの関連付け
                PdfWriter joinWr = PdfWriter.GetInstance(joinDc, joinFs);
                // 結合先PDFオープン
                joinDc.Open();
                // PdfContentByte取得
                PdfContentByte joinPcb = joinWr.DirectContent;foreach (string fn in ofd.FileNames)
                foreach(string fileName in ofd.FileNames)
                {
                    // ファイル読み込み
                    PdfReader joinRd = new PdfReader(File.ReadAllBytes(fileName));
                    // 結合元PDFファイルのページ数取得
                    int joinNp = joinRd.NumberOfPages;
                    for (int joinPageNum = 1; joinPageNum <= joinNp; joinPageNum++)
                    {
                        // ページサイズ設定
                        joinDc.SetPageSize(joinRd.GetPageSizeWithRotation(joinPageNum));
                        // 改ページ
                        joinDc.NewPage();
                        // ページ取得
                        PdfImportedPage joinPage = joinWr.GetImportedPage(joinRd, joinPageNum);
                        // ページ結合
                        joinPcb.AddTemplate(joinPage,0,0);
                    }
                }
                // 結合先PDFクローズ
                joinDc.Close();
            }
        }

これで複数選択したファイルを結合完了するはず!
と、思いきや、思わぬ落とし穴。

PDFは実は回転情報があるので、これだと90度回転とかしているPDFファイルだといきなり横向きのPDFが縦向きに結合されてしまう現象が起きます。

これではいかんよねぇ・・・。

なので改良して結合

対応するには無回転、90度回転、180度回転、270度回転それぞれの対応が必要となる。

対応したソースは以下の通り

        private void btnJoin_Click(object sender, EventArgs e)
        {
            string joinPdfPath = "C:\\join.pdf";
            // ファイル選択ダイアログを表示
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "PDFファイル(*.pdf)|*.pdf";
            ofd.Title = "結合するPDFを選択してください";
            ofd.Multiselect = true; // 複数ファイル選択
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                // PDFドキュメント作成
                Document joinDc = new Document();
                // 結合先PDFファイルの作成
                FileStream joinFs = new FileStream(joinPdfPath, FileMode.Create, FileAccess.Write);
                // 結合先PDFオブジェクトとPDFファイルの関連付け
                PdfWriter joinWr = PdfWriter.GetInstance(joinDc, joinFs);
                // 結合先PDFオープン
                joinDc.Open();
                // PdfContentByte取得
                PdfContentByte joinPcb = joinWr.DirectContent;foreach (string fn in ofd.FileNames)
                foreach(string fileName in ofd.FileNames)
                {
                    // ファイル読み込み
                    PdfReader joinRd = new PdfReader(File.ReadAllBytes(fileName));
                    // 結合元PDFファイルのページ数取得
                    int joinNp = joinRd.NumberOfPages;
                    for (int joinPageNum = 1; joinPageNum <= joinNp; joinPageNum++)
                    {
                        // ページ回転向き取得
                        int pageRotation = joinRd.GetPageRotation(1);
                        // ページサイズ設定
                        joinDc.SetPageSize(joinRd.GetPageSizeWithRotation(joinPageNum));
                        // 改ページ
                        joinDc.NewPage();
                        // ページ取得
                        PdfImportedPage joinPage = joinWr.GetImportedPage(joinRd, joinPageNum);
                        // ページ結合(90,180,270度の回転に対応)
                        if (pageRotation == 90)
                            joinPcb.AddTemplate(joinPage, 0, -1, 1, 0, 0, joinRd.GetPageSizeWithRotation(joinPageNum).Height);
                        else if (pageRotation == 180)
                            joinPcb.AddTemplate(joinPage, -1, 0, 0, -1, joinRd.GetPageSizeWithRotation(joinPageNum).Width, joinRd.GetPageSizeWithRotation(joinPageNum).Height);
                        else if (pageRotation == 270)
                            joinPcb.AddTemplate(joinPage, 0, 1, -1, 0, joinRd.GetPageSizeWithRotation(joinPageNum).Width, 0);
                        else
                            joinPcb.AddTemplate(joinPage, 1, 0, 0, 1, 0, 0);
                    }
                }
                // 結合先PDFクローズ
                joinDc.Close();
            }
        }

これで回転向きが変わらずにPDFの結合が完了します。