C# 通过iTextSharp实现关键字签字盖章(通过在内容中插入盖章图片的形式)

发布时间 2023-05-05 15:03:46作者: 流纹

此功能通过 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;
        }
    }
View Code

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;
        }
    }
View Code