CAD日記

主にAutoCADのことについて書いているけど、近頃は投資系ネタに注力している。自動売買、仮想通貨、PC関係、プログラミングなど。@caddiary

ソフト開発

PDFへの捺印をpdfでするだけでなくpng画像でもできるようにしたPDFアレコレを公開

投稿日:2020年3月22日 更新日:

昨日に引き続き今日も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の画像変換だって、現状やっているんだからきっとできる。課題がどんどん出てきて、いいんだか悪いんだか。

-ソフト開発

執筆者:


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

関連記事

Hyper-Vのvhdxを圧縮するのはPowerShellでやるんだけど、その自動化手法がおもしろいじゃん(2)

Hyper-Vのvhdxを圧縮するのはPowerShellでやるんだけど、その自動化手法がおもしろいじゃんの続き。以下2点の改修をしたスクリプトを作ってみた。 ・vhdファイルが存在しなければ、エラー …

no image

PDFの用紙サイズはポイントで表現されている

PDFの用紙サイズをiTexSharpで取得したら、mmでもinchでもない、 謎の数値が得られたので、調べてみたらポイントという単位だった。 ポイントとは、WordやEXCELで文字の大きさを指定す …

PDFアレコレをバージョンアップ

1年ぶりにPDFアレコレをバージョンアップ。変更点は以下の通り。 Ver2.00 2019/10/13 ・プレービューからのページ回転に対応。PDFiumのPDF編集能力は低いため、iTextShar …

no image

フォルダ監視

フォルダを常時監視しておいて、ファイルが放り込まれたら、 自動的にファイル変換してくれたらよいね。 なんていう話があった。 一週間という短い間に、対象ソフトは別で2件あった。 こいつぁ、なんとかせにゃ …

zipcopy Ver1.06リリース

zipcopyをリビジョンアップして、Ver1.06とした。 詳細は以下の通り。 Ver1.06 2020/2/24 ・ファイル削除時のタイムアウト(秒)を設定可能として、初期値を180秒(3分)とし …