此功能通过 iTextSharp 读取PDF文档信息,并循环查找每一页PDF文件,在整个PDF中只要是符合条件的地方都会盖章,如只需要在最后一页盖章,请将方法中For循环去掉,并将
PdfContentByte contentByte = pdfStamper.GetUnderContent(i);
parser.ProcessContent<PdfLocation>(i, location);
改为
// 获得文档页数
int pdfPageSize = pdfReader.NumberOfPages;
//文档最后一页,如需要第一页则直接将pdfPageSize改为1
PdfContentByte contentByte = pdfStamper.GetUnderContent(pdfPageSize);
//读取文档最后一页内容
parser.ProcessContent<PdfLocation>(pdfPageSize, location);
这几句改掉之后即可精确到第几页盖章
以下为具体代码实现:
1、具体盖章实现,引用 iTextSharp.text.pdf
/// <summary>
/// pdf签字签章,以图片形式
/// </summary>
public class PDFSealHelper
{
/// <summary>
/// 图片最大宽度
/// </summary>
private static float ReSizeMaxWidth = 50;
/// <summary>
/// 图片最大高度
/// </summary>
private static float ReSizeMaxHeight = 50;
/// <summary>
/// 签字盖章(文件流和Base64格式图片)
/// </summary>
/// <param name="bytePdf">需要签字盖章byte数组的pdf文件</param>
/// <param name="outPdfPath">签字盖章后输出pdf路径</param>
/// <param name="SignImgBase64">Base64格式图片</param>
/// <param name="SignKeyWord">关键字</param>
public static void SignBase64Img(byte[] bytePdf, string outPdfPath, string SignImgBase64, string SignKeyWord)
{
System.IO.Stream outputPdfStream = new System.IO.FileStream(outPdfPath, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None);
// 创建一个PdfReader对象
PdfReader pdfReader = new PdfReader(bytePdf);
PdfStamper pdfStamper = new PdfStamper(pdfReader, outputPdfStream);
{
// 获得文档页数
int pdfPageSize = pdfReader.NumberOfPages;
for (int i = 1; i <= pdfPageSize; i++)
{
//获取当前页
PdfContentByte contentByte = pdfStamper.GetUnderContent(i);
PdfLocation location = new PdfLocation();
iTextSharp.text.pdf.parser.PdfReaderContentParser parser = new iTextSharp.text.pdf.parser.PdfReaderContentParser(pdfReader);
parser.ProcessContent<PdfLocation>(i, location);
//查找当前页的关键字
location.SearchKeywords(SignKeyWord);
if (location.TextLocationInfo.Count > 0)
{
//坐标是从左下角往上,左下角为(0,0)零点
XTextInfo o = location.TextLocationInfo[0];
//获取关键字左上角开始坐标
var ltLocation = o.TopLeft.ToString().Split(',');//272.15,766.46,1
var leftX = float.Parse(ltLocation[0]);
var topY = float.Parse(ltLocation[1]);
//获取关键字右下角结束坐标
var rbLocation = o.BottomRight.ToString().Split(',');//305.15,755.46,1
var rightX = float.Parse(rbLocation[0]);
var bottomY = float.Parse(rbLocation[1]);
//计算得到关键字的中心点
float x = (rightX - leftX) / 2 + leftX;
float y = (topY - bottomY) / 2 + bottomY;
var imageByByte = ConvertBase64ToImage(SignImgBase64);
//创建一个图片对象
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(imageByByte, System.Drawing.Imaging.ImageFormat.Jpeg);
//设置图片的指定大小
float expectWidth = image.Width;
float expectHeight = image.Height;
if (image.Width > image.Height && image.Width > ReSizeMaxWidth)
{
expectWidth = ReSizeMaxWidth;
expectHeight = expectWidth * image.Height / image.Width;
}
else if (image.Height > image.Width && image.Height > ReSizeMaxHeight)
{
expectHeight = ReSizeMaxHeight;
expectWidth = expectHeight * image.Width / image.Height;
}
//设置图片的指定大小
image.ScalePercent(40);
//image.ScaleToFit(expectWidth, expectHeight);
//盖章位置于关键字右下方
image.SetAbsolutePosition(x + (expectWidth / 2), y + (expectHeight / 2) - expectHeight);
contentByte.AddImage(image);
}
}
pdfStamper.Close();
pdfReader.Close();
System.Diagnostics.Process.Start(outPdfPath);
}
}
/// <summary>
/// 签字盖章(文件路径)
/// </summary>
/// <param name="pdfPath">要签字盖章的pdf文件路径</param>
/// <param name="outPdfPath">签字盖章后输出pdf路径</param>
/// <param name="SignImgPath">签字的图片路径</param>
/// <param name="SignKeyWord">关键字</param>
public static void SignFile(string pdfPath, string outPdfPath, string SignImgPath, string SignKeyWord)
{
//创建盖章后生成pdf
System.IO.Stream outputPdfStream = new System.IO.FileStream(outPdfPath, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None);
// 创建一个PdfReader对象
PdfReader pdfReader = new PdfReader(pdfPath);
PdfStamper pdfStamper = new PdfStamper(pdfReader, outputPdfStream);
// 获得文档页数
int pdfPageSize = pdfReader.NumberOfPages;
//循环每一页
for (int i = 1; i <= pdfPageSize; i++)
{
//获取当前页
//GetUnderContent 加在内容下层
//GetOverContent 加在内容上层
PdfContentByte contentByte = pdfStamper.GetUnderContent(i);
PdfLocation location = new PdfLocation();
iTextSharp.text.pdf.parser.PdfReaderContentParser parser = new iTextSharp.text.pdf.parser.PdfReaderContentParser(pdfReader);
parser.ProcessContent<PdfLocation>(i, location);
//查找当前页的关键字及其坐标
location.SearchKeywords(SignKeyWord);
if (location.TextLocationInfo.Count > 0)
{
XTextInfo o = location.TextLocationInfo[0];
//获取关键字左上角开始坐标
var ltLocation = o.TopLeft.ToString().Split(',');//272.15,766.46,1
var leftX = float.Parse(ltLocation[0]);
var topY = float.Parse(ltLocation[1]);
//获取关键字右下角结束坐标
var rbLocation = o.BottomRight.ToString().Split(',');//305.15,755.46,1
var rightX = float.Parse(rbLocation[0]);
var bottomY = float.Parse(rbLocation[1]);
//计算得到关键字的中心点
float x = (rightX - leftX) / 2 + leftX;
float y = (topY - bottomY) / 2 + bottomY;
//创建一个图片对象
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(SignImgPath);
float expectWidth = image.Width;
float expectHeight = image.Height;
if (image.Width > image.Height && image.Width > ReSizeMaxWidth)
{
expectWidth = ReSizeMaxWidth;
expectHeight = expectWidth * image.Height / image.Width;
}
else if (image.Height > image.Width && image.Height > ReSizeMaxHeight)
{
expectHeight = ReSizeMaxHeight;
expectWidth = expectHeight * image.Width / image.Height;
}
//设置图片的指定大小
image.ScalePercent(40);
//image.ScaleToFit(expectWidth, expectHeight);
//盖章位置于关键字右下方
image.SetAbsolutePosition(x + (expectWidth / 2), y + (expectHeight / 2) - expectHeight);
contentByte.AddImage(image);
}
}
pdfStamper.Close();
pdfReader.Close();
System.Diagnostics.Process.Start(outPdfPath);
}
/// <summary>
/// Base64转图片
/// </summary>
/// <param name="base64String"></param>
/// <returns></returns>
private static System.Drawing.Image ConvertBase64ToImage(string base64String)
{
byte[] imageBytes = Convert.FromBase64String(base64String);
System.Drawing.Bitmap bitmap = null;
MemoryStream stream = null;
stream = new MemoryStream(imageBytes);
bitmap = new System.Drawing.Bitmap(stream);
return bitmap;
}
}
2、查找pdf关键字坐标类,引用 iTextSharp.text.pdf.parser
public class PdfLocation : LocationTextExtractionStrategy
{
/// <summary>
/// 文档文本及坐标
/// </summary>
public List<XTextChunk> LocationResult = new List<XTextChunk>();
/// <summary>
/// 关键字及其坐标
/// </summary>
public List<XTextInfo> TextLocationInfo = new List<XTextInfo>();
/// <summary>
/// 重写读取文档文本方法,第一步就是执行此方法,不可删除,
/// 删除后LocationResult数据为空,影响关键字坐标查找方法执行
/// </summary>
/// <param name="renderInfo">文本渲染信息</param>
public override void RenderText(TextRenderInfo renderInfo)
{
LineSegment segment = renderInfo.GetBaseline();
XTextChunk location = new XTextChunk(renderInfo.GetText(), segment.GetStartPoint(), segment.GetEndPoint(), renderInfo.GetSingleSpaceWidth(), renderInfo.GetAscentLine(), renderInfo.GetDescentLine());
LocationResult.Add(location);
}
/// <summary>
/// 关键字坐标查找
/// </summary>
/// <param name="sKeyword">关键字</param>
public void SearchKeywords(string sKeyword)
{
var keyWordLen = sKeyword.Length;
var keyWordList = sKeyword.ToList();
LocationResult.Sort();
TextLocationInfo.Clear();
XTextInfo lastXTextInfo = new XTextInfo();
if (LocationResult != null && LocationResult.Any())
{
for (int i = 0; i < LocationResult.Count; i++)
{
//当关键字的第一个字匹配上后循环匹配后面的几个关键字
if (LocationResult[i].Text == keyWordList[0].ToString())
{
if (keyWordLen > 1)
{
for (int j = 0; j < keyWordList.Count; j++)
{
//往后几个字符都符合关键字
if (LocationResult[i + j].Text == keyWordList[j].ToString())
{
lastXTextInfo.appendText(LocationResult[i + j]);
}
}
}
else
{
lastXTextInfo.appendText(LocationResult[i]);
}
if (lastXTextInfo.Text.Contains(sKeyword))
{
TextLocationInfo.Add(lastXTextInfo);
break;
}
}
}
}
}
}
/// <summary>
/// 文本块
/// </summary>
public class XTextChunk : IComparable, ICloneable
{
#region 字段
/// <summary>
/// 上升线段
/// </summary>
public LineSegment AscentLine { get; set; }
/// <summary>
/// 下降线段
/// </summary>
public LineSegment DecentLine { get; set; }
/// <summary>
/// 方向
/// </summary>
public Vector OrientationVector { get; set; }
/// <summary>
/// 文本
/// </summary>
public string Text { get; set; }
/// <summary>
/// 字符宽度
/// </summary>
public float CharSpaceWidth { get; set; }
/// <summary>
/// 平行距离开始
/// </summary>
public float DistParallelStart { get; set; }
/// <summary>
/// 平行距离结束
/// </summary>
public float DistParallelEnd { get; set; }
/// <summary>
/// 垂直距离
/// </summary>
public int DistPerpendicular { get; set; }
/// <summary>
/// 方向幅值(坐标角度)
/// </summary>
public int OrientationMagnitude { get; set; }
/// <summary>
/// 开始坐标
/// </summary>
public Vector StartLocation { get; set; }
/// <summary>
/// 结束坐标
/// </summary>
public Vector EndLocation { get; set; }
#endregion
/// <summary>
/// 文本块、它的方向以及相对于方向向量的位置
/// </summary>
/// <param name="txt"></param>
/// <param name="startLoc"></param>
/// <param name="endLoc"></param>
/// <param name="charSpaceWidth"></param>
public XTextChunk(string txt, Vector startLoc, Vector endLoc, float charSpaceWidth, LineSegment ascentLine, LineSegment decentLine)
{
Text = txt;
StartLocation = startLoc;
EndLocation = endLoc;
CharSpaceWidth = charSpaceWidth;
AscentLine = ascentLine;
DecentLine = decentLine;
OrientationVector = EndLocation.Subtract(StartLocation).Normalize();
OrientationMagnitude = (int)(Math.Atan2(OrientationVector[Vector.I2], OrientationVector[Vector.I1]) * 1000);
Vector origin = new Vector(0, 0, 1);
DistPerpendicular = (int)(StartLocation.Subtract(origin)).Cross(OrientationVector)[Vector.I3];
DistParallelStart = OrientationVector.Dot(StartLocation);
DistParallelEnd = OrientationVector.Dot(EndLocation);
}
/// <summary>
/// 创建作为当前实例副本的新对象。
/// </summary>
/// <returns></returns>
public object Clone()
{
XTextChunk copy = new XTextChunk(Text, StartLocation, EndLocation, CharSpaceWidth, AscentLine, DecentLine);
return copy;
}
/// <summary>
/// 根据方向、垂直距离和平行距离进行比较
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public int CompareTo(object obj)
{
if (obj == null) {throw new Exception ("obj参数为空");}
XTextChunk rhs = obj as XTextChunk;
if (rhs != null)
{
if (this == rhs) { return 0; }
int rslt = OrientationMagnitude - rhs.OrientationMagnitude;
if (rslt != 0) { return rslt; }
rslt = DistPerpendicular - rhs.DistPerpendicular;
if (rslt != 0) { return rslt; }
//注意:检查浮点数是否相等是不安全的,如果两个块
//真的在彼此之上,哪一个排在第一还是第二并不重要
//所以我们任意选择了这种方式。
rslt = DistParallelStart < rhs.DistParallelStart ? -1 : 1;
return rslt;
}
else
{
throw new Exception ("XTextChunk为空");
}
}
}
/// <summary>
/// 符合条件的文本信息
/// </summary>
public class XTextInfo
{
#region 字段
/// <summary>
/// 左上角开始坐标
/// </summary>
public Vector TopLeft { get; set; }
/// <summary>
/// 右下角结束坐标
/// </summary>
public Vector BottomRight { get; set; }
/// <summary>
/// 关键字
/// </summary>
public string Text { get; set; }
#endregion
#region 构造方法
/// <summary>
/// 构造方法
/// </summary>
/// <param name="initialXTextChunk"></param>
public XTextInfo(XTextChunk initialXTextChunk)
{
//上升线=AscentLine
TopLeft = initialXTextChunk.AscentLine.GetStartPoint();
BottomRight = initialXTextChunk.DecentLine.GetEndPoint();
Text = initialXTextChunk.Text;
}
/// <summary>
/// 构造方法
/// </summary>
public XTextInfo() { }
#endregion
/// <summary>
/// 添加文本
/// </summary>
/// <param name="additionalXTextChunk"></param>
public void appendText(XTextChunk additionalXTextChunk)
{
//DecentLine=下降线
BottomRight = additionalXTextChunk.DecentLine.GetEndPoint();
TopLeft = additionalXTextChunk.AscentLine.GetStartPoint();
Text += additionalXTextChunk.Text;
}
}
仅个人记录,不喜勿喷,谢谢