先週に引き続き今週もPDFアレコレをバージョンアップ。変更点は以下の通り。
Ver2.02 2020/3/21
・捺印時に画面でクリックしたところに配置できるようにした。(Ver2.01は固定値)
詳細はコチラ。
上でも触れたように、PDFに捺印できるんだったら画面で位置を指定できなきゃ意味がない。課題は画面でクリックした位置を取得して、どうやってPDFの座標系に落とし込むかってことだった。簡単に言うと、クリックした点を画面のX方向とY方向に対して比率で持っておいて、いざPDFに配置するときにその比率分で座標計算するだけでよかった。PDFが90度や270度で回転している場合に、PDFの高さと幅が逆になるってことに気付くのにずいぶん時間がかかってしまった。このあたりは、言葉では伝えられないのでコードで表そう。
マウスクリックしたときの処理で、XY方向の比率を保持して捺印実行部を呼び出している。
private void pictureBox1_MouseDown(object sender, MouseEventArgs e) { if (!m_isMouseClickMode) return; int p = (int)numericUpDown1.Value; if (!(1 <= p && p <= m_maxpage)) return; SizeF size = m_pdfDoc.PageSizes[p-1]; float h1 = size.Width / size.Height; // pdfの縦横比 float h2 = (float)pictureBox1.Width / (float)pictureBox1.Height; // コントロールの縦横比 int width = 0, height = 0; if (h1 < h2) // フォーム内にImageを当てはめる判定 { width = (int)((float)pictureBox1.Height * h1); height = pictureBox1.Height; } else { width = pictureBox1.Width; height = (int)((float)pictureBox1.Width / h1); } Point pnt = e.Location; if (pnt.X < 0 || pnt.Y < 0 || pnt.X > width || pnt.Y > height) { MessageBox.Show("指定した点が用紙範囲外"); return; } m_rx = pnt.X / (double)width; m_ry = 1.0 - (pnt.Y / (double)height); execNatsuin(p); m_isMouseClickMode = false; ChangeControl(); this.Cursor = Cursors.Default; }
捺印実行部の処理。PDFの回転と画面クリック時の比率を考慮。画面中央に捺印イメージがあるので、捺印用PDFの用紙サイズの高さと幅を半分引いている。
public bool Natsuin(ref string file, int pno, string strNtin, double rx, double ry) { string temp = uty.GetTempPDFName(); bool stat = true; PdfReader src = new PdfReader(file); PdfReader add = new PdfReader(strNtin); try { int pagesCount = src.NumberOfPages; if (0 < pno && pno <= pagesCount) { iTextSharp.text.Rectangle srcBox = src.GetPageSize(pno); iTextSharp.text.Rectangle addBox = add.GetPageSize(1); int rot = src.GetPageRotation(pno); double pos_y = 0, pos_x = 0; if (rot == 0 || rot == 180) { pos_y = srcBox.Height * ry; pos_x = srcBox.Width * rx; } else // 90度または270度回転していると、高さ幅が逆になる { pos_y = srcBox.Width * ry; pos_x = srcBox.Height * rx; } pos_y -= addBox.Height / 2.0; // 捺印用PDFは中央に捺印イメージがある前提なので、用紙サイズから半分引く pos_x -= addBox.Width / 2.0; PdfStamper stamper = new PdfStamper(src, new FileStream(temp, FileMode.Create)); PdfImportedPage page = stamper.GetImportedPage(add, 1); stamper.GetImportedPage(src, pno); PdfContentByte cb = stamper.GetOverContent(pno); cb.AddTemplate(page, pos_x, pos_y); // 配置点はここで指定する stamper.Close(); } else { stat = false; MessageBox.Show("ページが範囲外"); } } catch (PdfException ex) { stat = false; MessageBox.Show(string.Format("捺印に失敗({0})", ex.Message)); } finally { src.Close(); add.Close(); if (stat) { uty.FileDelete(file); file = temp; } } return stat; }
PDFiumの描画エンジンとiTextSharpのPDF編集が組み合わさると、こんなにアレコレできるんだということの一つをはっきり形にできた。でも、まだ課題はある。捺印用PDFが4MBとデカイから、捺印した結果のPDFがデカくなるし、メモリーだってやけに消費してしまう。Web任印というサイトで作ったPDFだからしょうがないんだけど、もっとサイズが小さくならんかね。たぶんハンコ用の文字フォントを埋め込まずにアウトライン化しているためだと思う。たかだか2文字や3文字のために4MBはデカイよな。透過ありの画像またはフォントのベクトル情報で配置できれば、格段にスリム化できるはず。おもしろくなってきたじゃないか。