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

业务需求需将PDF中的logo图片替换,并合并多个PDF。作者尝试多种方法,发现itextsharp文档少、PDF格式难理解,Sprie.pdf好用但需付费。最终采用先合并再去logo的两步走方案,还提及处理MemoryStream流的注意事项,并给出参考链接。

因业务需要把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.youkuaiyun.com/java2000_net/article/details/3734534 iText使用入门:编辑,增加,导入,水印,合并PDF的例子
https://zhuchengzzcc.iteye.com/blog/1603671 iText 操作Pdf 简单整理
https://blog.youkuaiyun.com/sand_clock/article/details/77505181 ITEXT PDF文件的拆分与合并

C#中,`iTextSharp`是一个非常流行的用于创建和操作PDF文档的库。要向现有的PDF文件中插入图片或是在新建的PDF文件里添加图片,你需要遵循以下步骤: ### 1. 安装 iTextSharp 首先确保已安装了`iTextSharp`库,你可以通过NuGet包管理器来安装它,在Visual Studio中的Nuget软件包管理控制台输入命令: ``` Install-Package itext7 ``` > 注意:这里提到的是 `itext7`, 因为原始的 `iTextSharp` 已经停止更新,而 `itext7` 是它的后续版本并支持 .NET Core 和 .NET Framework。 ### 2. 引入命名空间 接着,在代码顶部引入必要的命名空间以便使用其提供的功能: ```csharp using iText.Kernel.Pdf; using iText.Layout; using iText.Layout.Element; using System.IO; ``` ### 3. 插入图像到 PDF 中 下面是具体的例子展示了如何加载一张本地磁盘上的图像并且将其放置在一个新的或是既有的PDF文档当中: #### 新建一个包含图片PDF 文件 示例: ```csharp // 创建一个新的 PDF 文档 string dest = "output.pdf"; PdfWriter writer = new PdfWriter(dest); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); // 添加图像至页面 Stream imgStream = File.OpenRead("path/to/your/image.png"); ImageData imageData = ImageDataFactory.Create(imgStream); Image image = new Image(imageData); document.Add(image); // 将图像加入到文档中 // 关闭所有资源 imgStream.Close(); document.Close(); Console.WriteLine($"带有图片的新 PDF 成功保存到了 {dest}"); ``` #### 向已有 PDF 文件中追加一页带图片 页面 示例: ```csharp // 打开现有 PDF 并准备写入模式 string src = "existing_file.pdf"; // 存放源 PDF 的路径 string dest = "new_output_with_image.pdf"; PdfReader reader = new PdfReader(src); PdfWriter writer = new PdfWriter(dest); PdfDocument pdfDoc = new PdfDocument(reader, writer); Document document = new Document(pdfDoc); int numberOfPages = pdfDoc.GetNumberOfPages(); // 在原有基础上增加新页码,并将图片置于该新增页面上 pdfDoc.AddNewPage(numberOfPages + 1); document.SetMargins(0, 0, 0, 0).ShowTextAligned(new Paragraph(), "", 595 / 2f - 86 / 2f, 842 / 2f - 121 / 2f, pdfDoc.GetPage(numberOfPages+1), TextAlignment.CENTER, VerticalAlignment.MIDDLE); Stream imgStream = File.OpenRead("path/to/your/image.jpg"); // 替换为你自己的图片位置 ImageData data = ImageDataFactory.Create(imgStream); Image pic = new Image(data); pic.ScaleToFit(500, 500); // 根据需要调整大小 document.ShowTextAligned(pic, "", 0, 0, pdfDoc.GetPage(numberOfPages+1)); // 清理工作完成后的收尾任务 imgStream.Close(); document.Close(); Console.WriteLine($"成功地把图片嵌入到了 {src}."); ``` 请注意上述示例仅作为基础用法展示,在实际项目中可能还需要根据具体需求做相应调整(例如设置图像的位置、尺寸等)。此外,记得处理好异常情况以及释放占用的相关资源。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值