2022年左右就写过一篇 FreeSpire.PDF 实现对pdf页面添加签名贴图 的笔记,但那时贴图定位完全是靠人工写死在配置文件里实现的,这次稍微有些不一样了,一定程度实现了程序自动找位置进行贴图,所以就想着可以记录一下。
说起这个活也挺郁闷的,因为核心也是pdf贴签名上传的活,同事不知道在哪听说过我这边2022年左右就接过一个类似的活,然后也不知道听谁说这功能开发起来贼简单一会就可以搞好(我也是服了,你TM倒是简单了,麻烦的是我呀。。。),近期这种奇葩活也明显多了起来。
然而确认开发业务流程事项时没人知道一问三不知,丢过来一家销售自己不知道在哪找到ca机构的sdk文档就让对接,然后就要求快速上线,搞不完就被投诉(中间因为ca合作费用问题折腾小半个月),牢骚归牢骚 但也是真挺佩服这些销售人员的,前期啥也没有就能拿下这些单子。
自动贴图的思路
相比之前的贴图定位写死,这次的区别是基于pdf内的文字锚点 使用 FreeSpire.PDF 读取到锚点的位置坐标,最后自己在代码里微调下位置偏移量,最后适当缩放贴图的尺寸,即可完成自动贴图定位
读取锚点定位
代码以【报告医师:】作为文字锚点(站长偏医疗方向),因为贴图需要贴在其后面空白处,文字锚点可以根据需求更换
using (PdfDocument doc = new PdfDocument())
{
doc.LoadFromBytes(pdfBytes);
PdfPageBase page = doc.Pages[0];
var reportDocterFinds = page.FindText("报告医师:").Finds;
if (reportDocterFinds.HasItems())
{
var find = reportDocterFinds.FirstOrDefault();
var reportDocterNamePointF = find.Position;//这个里就是文字锚点的坐标
}
}
缩放签名尺寸
这个实现方式很多 站长需求比较简单 这里直接用的GDI+ 做一下尺寸调整,调整到贴图不超出空白区域的尺寸即可
private static Image Resize(this Image resourceImage, int width, int height)
{
// 用指定的大小和格式初始化Bitmap类的新实例
using (Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
{
// 从指定的Image对象创建新Graphics对象
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// 在指定位置并且按指定大小绘制原图片对象
graphics.DrawImage(resourceImage, new Rectangle(0, 0, width, height));
}
return new Bitmap(bitmap);
}
}
签名自动贴图
public static bool DocterSignedPdf(ref byte[] pdfBytes, byte[] docterSignedBytes, PointF signedPointF, out string errorMsg)
{
errorMsg = "";
try
{
using (var docterSignedMS = new MemoryStream(docterSignedBytes))
{
using (var outputPdfStream = new MemoryStream())
{
using (var signImage = Bitmap.FromStream(docterSignedMS))
{
using (var doc = new PdfDocument())
{
doc.LoadFromBytes(pdfBytes);
PdfPageBase page = doc.Pages[0];
float sign_h = 30F;
float bfb = sign_h / signImage.Height;
float sign_w = signImage.Width * bfb;
PdfRubberStampAnnotation loStamp = new PdfRubberStampAnnotation(new RectangleF(new PointF(0, 0), new SizeF(page.ActualSize.Width, page.ActualSize.Height)));
PdfAppearance loApprearance = new PdfAppearance(loStamp);
PdfTemplate template = new PdfTemplate(page.ActualSize.Width, page.ActualSize.Height);
using (var resizeImage = signImage.Resize((int)sign_w, (int)sign_h))
{
PdfImage image = PdfImage.FromImage(resizeImage);
//template.Graphics.DrawImage(image, (int)pos_left - signedPointF.X, (int)pos_top - signedPointF.Y, (int)sign_w, (int)sign_h);
template.Graphics.DrawImage(image, signedPointF.X + 100, signedPointF.Y - 6);
loApprearance.Normal = template;
loStamp.Appearance = loApprearance;
page.AnnotationsWidget.Add(loStamp);
doc.SaveToStream(outputPdfStream, FileFormat.PDF);
outputPdfStream.Flush();
outputPdfStream.Seek(0, SeekOrigin.Begin);
pdfBytes = outputPdfStream.ToArray();
return true;
}
}
}
}
}
}
catch (Exception ex)
{
errorMsg = ex.Message;
//Log4Net.Error("报告签失败", ex);
return false;
}
}