C# itextsharp替换PDF中的某个图片

因业务需要把pdf中的logo图片换成其它图片.
百度了很久也没找到相关的解决方案. 后来总算是解决了.
总结起来一句话, itextsharp的文档太少了. 尤其是关于几个基础类的相关文档, 还有pdf文档格式也是很要命的难理解. 简直是狗屎般的格式. 用Sprie.pdf 很好用很简单, 就是得花钱.

业务需求还需要合并多个pdf, 搞了好久实在是不知道如何合并的同时再去掉logo.
就改成分两步走. 先合并成一个文件后, 输出到MemoryStream,然后再去掉logo…

废话不多说上代码.


        private void Main()
        {
            //读取待替换logo的pdf文件, 这个地方可以是Stream可以放在内存里.
            PdfReader reader2 = new PdfReader("D:\\a.pdf");
            //输出文件流.
            using (FileStream fs = new FileStream("D:\\Marge.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
            {
                using (PdfStamper stamper = new PdfStamper(reader2, fs))
                { 
                    PdfDictionary page; 

                    //Get the page count
                    int pageCount2 = reader2.NumberOfPages;
                    //Loop through each page
                    for (int i = 1; i <= pageCount2; i++)
                    {
                        //Get the page
                        page = reader2.GetPageN(i);
                        PdfObject obj = FindImageInPDFDictionary(page, DistinguishImageIsLogo);
                        //Get the raw content
                        //contentarray = page.GetAsArray(PdfName.RESOURCES);
                        if (obj != null)
                        {
                            PdfReader.KillIndirect(obj);//移除老图片,只是移除了关联. 
                            iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance("D:\\cc.png"); //必须每个页面新建一个图片的对象,否则会只在第一个页面有图片.
                            iTextSharp.text.Image maskImage = img.ImageMask;
                            if (maskImage != null)
                            {
                                stamper.Writer.AddDirectImageSimple(maskImage); //把新图片写进去
                                stamper.Writer.AddDirectImageSimple(img, (PRIndirectReference)obj); //把新图片写进去.
                            } 
                        }  
                    } 

                }
            } 
        }


 
 //在pdf页面中 找到logo图片
        private static PdfObject FindImageInPDFDictionary(PdfDictionary pg, DistinguishImage distinguishMethod)
        {
            PdfDictionary res = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES));
            PdfDictionary xobj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
            if (xobj != null)
            {
                foreach (PdfName name in xobj.Keys)
                {
                    Console.WriteLine(name.ToString());
                    PdfObject obj = xobj.Get(name);
                    if (obj.IsIndirect())
                    {
                        PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject(obj);
                        PdfName type = (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE));
                        //image at the root of the pdf
                        if (PdfName.IMAGE.Equals(type))
                        {
                            if (distinguishMethod(tg) == true)
                            {
                                return obj;
                            }
                            else
                            {
                                continue;//继续找
                            }
                        }// image inside a form
                        else if (PdfName.FORM.Equals(type))
                        {
                            return FindImageInPDFDictionary(tg, distinguishMethod);
                        } //image inside a group
                        else if (PdfName.GROUP.Equals(type))
                        {
                            return FindImageInPDFDictionary(tg, distinguishMethod);
                        }
                    }
                }
            }

            return null;

        }

        /// <summary>
        /// 辨别图片的委托
        /// </summary>
        /// <param name="imgObject"></param>
        /// <returns></returns>
        delegate bool DistinguishImage(PdfDictionary imgObject);

        /// <summary>
        /// 辨别图片是不是LOGO
        /// </summary>
        /// <param name="imgObject"></param>
        /// <returns></returns>
        private static bool DistinguishImageIsLogo(PdfDictionary imgObject)
        {
            int width, height, length;
            int.TryParse(imgObject.Get(PdfName.WIDTH).ToString(), out width);
            int.TryParse(imgObject.Get(PdfName.HEIGHT).ToString(), out height);
            int.TryParse(imgObject.Get(PdfName.LENGTH).ToString(), out length);

			//从这3个参数就可以判断是不是logo, 也可以按照name来判断.还可以硬编码判断两个图片对象是否一样.
            if (width == 270 && height == 111 && length == 11878)
            {
                return true; 
            }
            else
            {
                return false;
            }
        }

以上是处理文件的方式,处理MemoryStream流, 需要用到特殊的自定义的内存流,防止程序自动关闭了流.


    public class PdfMemoryStream : System.IO.MemoryStream
    {

        public PdfMemoryStream(byte[] bytes) :base(bytes)
        {   
            AllowClose = true;
        }

        public PdfMemoryStream()
        {
            AllowClose = true;
        } 

        public bool AllowClose { get; set; }

        public override void Close()
        {
            if (AllowClose)
                base.Close();
        }

    }

然后把Main方法重构了一下如下

        /// <summary>
        /// 替换PDF中的图片
        /// </summary>
        /// <param name="src">pdf文件流</param>
        /// <param name="distinguishMethod">识别需要被替换图片的方法</param>
        /// <param name="replaceToImg">替换成这个图片</param>
        /// <returns></returns>
       public static MemoryStream ReplaceImage(Stream src, DistinguishImage distinguishMethod, System.Drawing.Image replaceToImg)
        {
            PdfReader reader2 = new PdfReader(src);
            PdfMemoryStream outMemoryStream = new PdfMemoryStream();
            outMemoryStream.AllowClose = false;

            using (PdfStamper stamper = new PdfStamper(reader2, outMemoryStream))
            {  
                int pageCount2 = reader2.NumberOfPages; 
                for (int i = 1; i <= pageCount2; i++)
                {
                    //Get the page
                    var page = reader2.GetPageN(i);
                    PdfObject obj = FindImageInPDFDictionary(page, distinguishMethod); 
                    if (obj != null)
                    {
                        PdfReader.KillIndirect(obj);//移除老图片 
                        iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(replaceToImg,BaseColor.WHITE,true);
                        iTextSharp.text.Image maskImage = img.ImageMask;
                        if (maskImage != null)
                        {
                            stamper.Writer.AddDirectImageSimple(maskImage);
                            stamper.Writer.AddDirectImageSimple(img, (PRIndirectReference)obj);
                        }
                    }
                }
            }

            outMemoryStream.Position = 0;
            return outMemoryStream;
        }

参考链接
https://yq.aliyun.com/articles/565318 用程序自动替换PDF文件中的图像
https://blog.csdn.net/java2000_net/article/details/3734534 iText使用入门:编辑,增加,导入,水印,合并PDF的例子
https://zhuchengzzcc.iteye.com/blog/1603671 iText 操作Pdf 简单整理
https://blog.csdn.net/sand_clock/article/details/77505181 ITEXT PDF文件的拆分与合并

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值