PDFアレコレのページ挿入機能とちょっとした不具合修正。
Ver2.08 2020/5/6
・ページ挿入に対応した。指定したページの前に、指定したPDFファイルまたは空白ページを挿入できる。指定ページに最終ページを指定すれば最後に追加できる。
・プロパティ画面にキャンセルボタンを追加した。(OKボタンだと常に更新していたため)
・PDFを編集した際、%Temp%フォルダに作業用のPDFが残っていたので削除するようにした。
詳細はコチラ。
ページ挿入のUIは以下の通り。
位置として指定したページの前に挿入することとして、挿入対象をファイルか空白ページとして指定する。
ファイルとすれば、OKボタンを押した後にPDFファイルを指定して挿入する。位置はコンボボックス形式として、内容は全ページ分の数値と最終ページ。初期値はプレビュー画面で表示していたページ。最終ページという選択を可能としたのがポイントで、これによりPDF内のどこにでもページを挿入できる仕様とした。
空白ページとすれば、内部処理で空白ページを作っている。空白ページの用紙サイズは、プレビュー画面で表示していたページのサイズとした。空のページを追加したいのはヤマヤマだったが、オブジェクトを何も追加しないと0バイトのPDFになってしまったので、何も見えないオブジェクトとしてArialの半角スペース文字を追加しておいた。
以下、iTextSharpをC#で組んでいる人でPDFページ挿入をしようという人に参考になるかと思って、ソースコードを公開しておく。
PDFの空ページを作る処理。空ページを作るために半角スペースの文字を入れているが、文字フォントが埋め込まれて20kbほどのサイズになるのが難点。空ページにするために何かをいれなきゃいけないのはいいとして、それを何にするのか。。今後検討の上、改善していこう。
private bool emptyPage(iTextSharp.text.Rectangle size, out string strEmp) { bool stat = true; strEmp = null; try { using (Document docEmp = new Document(size)) { using (MemoryStream memEmp = new MemoryStream()) { using (PdfWriter writer = PdfWriter.GetInstance(docEmp, memEmp)) { docEmp.Open(); PdfContentByte pdfContentByte = writer.DirectContent; FontFactory.RegisterDirectories(); var baseFont = FontFactory.GetFont("Arial", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, 8f); pdfContentByte.BeginText(); pdfContentByte.SetFontAndSize(baseFont.BaseFont, 8); pdfContentByte.ShowTextAligned(PdfContentByte.ALIGN_LEFT, " ", 100f, 100f, 0); pdfContentByte.EndText(); docEmp.Close(); strEmp = uty.GetTempPDFName(); using (BinaryWriter w = new BinaryWriter(File.OpenWrite(strEmp))) { w.Write(memEmp.ToArray()); } } } } } catch (PdfException ex) { stat = false; MessageBox.Show(string.Format("空ページ作成に失敗({0})", ex.Message)); } finally { if (!stat && strEmp != null) uty.FileDelete(strEmp); } return stat; }
ページ挿入処理。PdfCopyというクラスを使うのがポイント。挿入位置による分岐処理が美しくない。考え方として(selpageの値によって)3つのケースに分けたのはいいんだけど、そもそもケース分けは必要なかったか。元PDFの前半、挿入するページ、元PDFの後半というように3つのブロック分けて、selpageの値によって1つ目と3つ目のいずれかをやらないようにすればよい。
public int PageInsert(ref string file, int selpage, string inspath, int page) { string temp = uty.GetTempPDFName(); int stat = 1; // 挿入したページの最後のページ PdfReader reader1 = new PdfReader(file); PdfReader reader2 = null; PdfReader reader3 = null; string emptyFile = null; if (inspath != null) reader2 = new PdfReader(inspath); else { if (emptyPage(reader1.GetPageSizeWithRotation(page), out emptyFile)) reader3 = new PdfReader(emptyFile); else return 0; } try { using (Document document = new Document()) { using (FileStream stream = new FileStream(temp, FileMode.Create, FileAccess.Write, FileShare.None)) { using (PdfCopy copy = new PdfCopy(document, stream)) { document.Open(); if (selpage == 1) // 先頭に挿入 { if (reader2 != null) { for (int i = 1; i <= reader2.NumberOfPages; i++) copy.AddPage(copy.GetImportedPage(reader2, i)); stat = reader2.NumberOfPages; } else { copy.AddPage(copy.GetImportedPage(reader3, 1)); stat = 1; } for (int i = 1; i <= reader1.NumberOfPages; i++) copy.AddPage(copy.GetImportedPage(reader1, i)); } else if (2 <= selpage && selpage <= reader1.NumberOfPages) // 途中に挿入 { for (int i = 1; i < selpage; i++) copy.AddPage(copy.GetImportedPage(reader1, i)); if (reader2 != null) { for (int i = 1; i <= reader2.NumberOfPages; i++) copy.AddPage(copy.GetImportedPage(reader2, i)); stat = selpage - 1 + reader2.NumberOfPages; } else { copy.AddPage(copy.GetImportedPage(reader3, 1)); stat = selpage; } for (int i = selpage; i <= reader1.NumberOfPages; i++) copy.AddPage(copy.GetImportedPage(reader1, i)); } else if (selpage == 0) // 最後に追加 { for (int i = 1; i <= reader1.NumberOfPages; i++) copy.AddPage(copy.GetImportedPage(reader1, i)); if (reader2 != null) { for (int i = 1; i <= reader2.NumberOfPages; i++) copy.AddPage(copy.GetImportedPage(reader2, i)); stat = reader1.NumberOfPages + reader2.NumberOfPages; } else { copy.AddPage(copy.GetImportedPage(reader3, 1)); stat = reader1.NumberOfPages + 1; } } } } document.Close(); } } catch (PdfException ex) { stat = 0; MessageBox.Show(string.Format("ページ挿入に失敗({0})", ex.Message)); } finally { reader1.Close(); if (reader2 != null) reader2.Close(); if (reader3 != null) { reader3.Close(); uty.FileDelete(emptyFile); } if (stat != 0) { uty.FileDelete(file); file = temp; } } return stat; }