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;
}