昨日に引き続き今日もPDFアレコレをバージョンアップ。変更点は以下の通り。
Ver2.03 2020/3/22
・捺印データとしてpng画像に対応した。
・捺印時にマウスカーソルにプレビューデータを表示するようにした。
(pngは指定したファイルのプレビュー。pdfは円だけで少々ずれる。)
pngで捺印する処理は以下の通りで、pdfの場合とちょっとちがう。
public bool AddImg(ref string file, int pno, string strImg, double rx, double ry) { double imgSizemm = 12.0; // 画像の印影は固定的な値として認識させる(画像のDPI値がいい加減だから) string temp = uty.GetTempPDFName(); bool stat = true; PdfReader src = new PdfReader(file); try { int pagesCount = src.NumberOfPages; if (0 < pno && pno <= pagesCount) { iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(strImg); iTextSharp.text.Rectangle srcBox = src.GetPageSize(pno); 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; } double imgSizePoint = uty.mm2point(imgSizemm); pos_y -= imgSizePoint / 2.0; // 捺印用PDFは中央に捺印イメージがある前提なので、用紙サイズから半分引く pos_x -= imgSizePoint / 2.0; PdfStamper stamper = new PdfStamper(src, new FileStream(temp, FileMode.Create)); PdfContentByte cb = stamper.GetOverContent(pno); image.ScaleAbsoluteHeight((float)imgSizePoint); image.ScaleAbsoluteWidth((float)imgSizePoint); image.SetAbsolutePosition((float)pos_x, (float)pos_y); cb.AddImage(image); stamper.Close(); } else { stat = false; MessageBox.Show("ページが範囲外"); } } catch (PdfException ex) { stat = false; MessageBox.Show(string.Format("捺印に失敗({0})", ex.Message)); } finally { src.Close(); if (stat) { uty.FileDelete(file); file = temp; } } return stat; } </pre> 画像ファイルにはDPI値(解像度)が入っていることもあるが、入っていないこともある。解像度があれば物理的な大きさ(つまり何ミリかってこと)がわかるから、印影を何ミリにするかって指定が不要になるんだけどねぇ。よって、解像度がない前提で印影は12ミリ固定とした。解像度があるかどうかで処理を分岐するのが今後の課題。 pngでもう一つ重要なのは透過ができること。捺印するんだから印影の背景は透明である必要がある。BitmapやJpegでは透過ができないから、透過ができるpngで実現することにした。印影は、<a href="http://www.hakusyu.com/webmtm/" target="_blank" rel="noopener noreferrer">Web認印</a>で作成できて、結果としてpdfとpngができる。pdfは透過できるんだけど、なにぶんサイズがデカい。印影用のフォントpdfに埋め込んでいるからだろう。そのデカさが問題で4MBはまずい。1つ捺印するごとに4MBずつ増加したんじゃ実用に向かない。だからpngなわけだけど、Web認印でできるpngは透過されていない。そこで、<a href="https://tojikomorin.sakura.ne.jp/inkan/" target="_blank" rel="noopener noreferrer">印鑑透過</a>が必要になる。透過されていない元画像をアップロードすると、透過された状態のpngが取得できる。これはすぐれもので、ちゃんと周囲の空白まで除去してくれている。 マウスカーソルに印影のプレビューを配置するコードも書いておく。pictureBoxのImageに画像データを読み込んで、タイマー処理でマウスカーソル位置にくっつけるというもの。MouseMoveだと遅くてしょうがないから、タイマー処理が吉。InterValを10ミリ秒にしても、マウスがサクサク動いてくれた。 <pre class="brush: c-sharp;"> private void ChangeCursor() { string ext = Path.GetExtension(m_strNtinFile); if (string.Compare(ext, ".pdf", true) == 0 || string.Compare(ext, ".png", true) == 0) { timer1.Interval = 10; timer1.Enabled = true; pictureBox2.Visible = true; pictureBox2.SizeMode = PictureBoxSizeMode.StretchImage; if (string.Compare(ext, ".pdf", true) == 0) { Bitmap img = new Bitmap(100, 100); Graphics g = Graphics.FromImage(img); Pen p = new Pen(Color.Red, 5); g.SmoothingMode = SmoothingMode.AntiAlias; g.DrawEllipse(p, 5, 5, 90, 90); //g.FillRectangle(Brushes.Red, g.VisibleClipBounds); p.Dispose(); g.Dispose(); pictureBox2.Image = img; } else if (string.Compare(ext, ".png", true) == 0) pictureBox2.Image = Image.FromFile(m_strNtinFile); double width = pictureBox1.Image.Width / m_papermm_width * m_imgSizemm; double height = pictureBox1.Image.Height / m_papermm_height * m_imgSizemm; m_CursorX = pictureBox2.Width = (int)width; m_CursorY = pictureBox2.Height = (int)height; } } private void ReverseCursor() { string ext = Path.GetExtension(m_strNtinFile); if (string.Compare(ext, ".pdf", true) == 0 || string.Compare(ext, ".png", true) == 0) { timer1.Enabled = false; pictureBox2.Visible = false; } } private void timer1_Tick(object sender, EventArgs e) { // PictureBoxをカーソルの位置に動かす。カーソルの真ん中に画像が表示されるよう、 // カーソルを表示しているPictureBoxのサイズの二分の一をX,Yそれぞれ引く Point Coordinate = this.PointToClient(Cursor.Position); pictureBox2.Location = new Point(Coordinate.X - (m_CursorX / 2), Coordinate.Y - (m_CursorY / 2)); // 印影プレビューは相対的な大きさとする double width = pictureBox1.Image.Width / m_papermm_width * m_imgSizemm; double height = pictureBox1.Image.Height / m_papermm_height * m_imgSizemm; pictureBox2.Width = (int)width; pictureBox2.Height = (int)height; }
pdfを指定した場合に、配置される印影が少しずれるのは、pdf内の中央に印影がないため。右上にずれているから、配置した点よりも右上に配置されてしまう。pdfだから容易に編集できない。空白を無視した領域の中央で認識させればいいんだろうが、現状pdfの用紙サイズでしか認識していない。pdfでオブジェクト範囲を認識できればいいのだができるだろうか。これも今後の課題。pdfで配置している限りは、元pdfのサイズ分増えてしまうという問題もある。pdfから透過pngを作るところまで自前でやってしまうのもありか。。pdfの画像変換だって、現状やっているんだからきっとできる。課題がどんどん出てきて、いいんだか悪いんだか。