Logo

Aspose、iText实现给PDF添加水印功能

photo

2022年07月18日

一、背景

最近有个项目需要实现给pdf、word、excel、图片等资源添加水印功能,最开始用的是前端来添加水印,后面发现会一点技术的还是可以通过请求捕获到你的源文件,那我加水印的意义何在?最后只能在后台直接返回已经处理过的文件,这样就不会有源文件被捕获的问题了。
好了,功能背景介绍完后,进入正题。
是怎么实现的呢?最开始想到的就是Aspose PDF.dll这个来做,因为项目中有其他地方用了Aspose,cell、Aspose,word。所以对于这个需求,第一时间想到还是Aspose。
下面就看看具体代码是怎么实现的吧。

二、实现功能

1、Aspose PDF.dll 实现PDF添加水印

/// <summary>
        /// pdf添加文字水印(自定义水印行数和列数)
        /// </summary>
        /// <param name="pdfStream">pdf文件流</param>
        /// <param name="watermarkText">水印文字</param>
        /// <param name="fontSize">文字大小</param>
        /// <param name="fontColor">文字颜色</param>
        /// <param name="typeface">字体:(中文水印请自行查找相应字体的英文名称,如:宋体(SimSun),黑体(SimHei),仿宋(FangSong),微软雅黑(Microsoft YaHei)等等...)</param>
        /// <param name="rotation">倾斜角度</param>
        /// <param name="opacity">不透明度(值为:0-1)</param>
        /// <param name="watermarkRowNum">水印行数</param>
        /// <param name="watermarkColumnNum">水印列数</param>
        /// <returns></returns>
        public MemoryStream AddTextWatermarkCustom(MemoryStream pdfStream, string watermarkText, float fontSize, Color fontColor, string typeface, double rotation = 0, double opacity = 0, int watermarkRowNum = 1, int watermarkColumnNum = 1)
        {
            try
            {
                /*计算倾斜高度-start*/
                var angle = Math.Abs(rotation);
                var width = watermarkText.Length * fontSize;
                var radian = 2 * Math.PI / 360 * angle;
                var top = Math.Sin(radian) * width;
                /*计算倾斜高度-end*/
                Document document = new Document(pdfStream);
                for (int i = 1; i <= document.Pages.Count; i++)
                {
                    var pageWidth = document.Pages[i].GetPageRect(false).Width;
                    var pageHeight = document.Pages[i].GetPageRect(false).Height;
                    WatermarkArtifact artifact = new WatermarkArtifact();
                    artifact.SetTextAndState(watermarkText, new TextState
                    {
                        FontSize = fontSize,
                        ForegroundColor = fontColor,
                        Font = FontRepository.FindFont(typeface),
                    });
                    artifact.Rotation = rotation;
                    artifact.Opacity = opacity;
                    artifact.IsBackground = false;
                    if (watermarkRowNum == 1 && watermarkColumnNum == 1)
                    {
                        artifact.ArtifactHorizontalAlignment = HorizontalAlignment.Center;
                        artifact.ArtifactVerticalAlignment = VerticalAlignment.Center;
                        document.Pages[i].Artifacts.Add(artifact);
                    }
                    else
                    {
                        artifact.ArtifactHorizontalAlignment = HorizontalAlignment.Left;
                        artifact.ArtifactVerticalAlignment = VerticalAlignment.Top;
                        for (int j = 1; j <= watermarkColumnNum; j++)
                        {
                            artifact.LeftMargin = (j - 1) * (pageWidth / watermarkColumnNum) + fontSize;
                            for (int z = 1; z <= watermarkRowNum; z++)
                            {
                                artifact.TopMargin = (z - 1) * (pageHeight / watermarkRowNum) + top;
                                document.Pages[i].Artifacts.Add(artifact);
                            }
                        }
                    }
                }
                var outStream = new MemoryStream();
                document.Save(outStream, SaveFormat.Pdf);
                outStream.Seek(0, SeekOrigin.Begin);
                return outStream;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

这个方法基本网上都有,我就直接贴上来了。
所以Aspose实现给PDF加水印还是比较方便的。
但是
但是
但是
经过简单的测试就发现一个巨大的问题。
在这里插入图片描述
抛异常了,翻译了一下:在评估模式下最多可以查看 4 个元素(对于任何集合)。
在这里插入图片描述
什么玩意?百度了一下,发现我们用的Aspose是试用版,试用版有限制,最多支持4页。wnm~
怎么办呢,正式版老贵了,咋办,找破解的呗。费了老大劲找了很多资源,最后,终于

我放弃了。。。。

在这里插入图片描述
含泪,没有办法,没有积分,C币,网上都要积分啥的才能下载。
至此Aspose实现给PDF添加水印的功能也就这样了。最起码学习了一下。

2、iTextSharp 实现PDF添加水印

经过上面的一系列打击之后,我决定请教微信群聊里面的众多大佬。
在这里插入图片描述
大佬的一句itext让我打开的新的大门。我立马流利的打开浏览器,百度输入itext,研究了一下发现真的可以,而且有很多写好的文章,于是我立马起来劲头,又是一波流利的ctrl c+v。根据自己的实际场景,略加修改,就有了一下代码:

/// <summary>
        /// 添加水印
        /// </summary>
        /// <param name="pdfStream"></param>
        /// <param name="waterMarkName"></param>
        /// <returns></returns>
        public MemoryStream SetWaterMark(Stream pdfStream, string waterMarkName)
        {
            try
            {
                MemoryStream outStream = new MemoryStream();
                PdfReader pdfReader = new PdfReader(pdfStream);
                PdfStamper pdfStamper = new PdfStamper(pdfReader, outStream);
                
                pdfStamper.Writer.CloseStream = false;
                int total = pdfReader.NumberOfPages + 1;
                iTextSharp.text.Rectangle psize = pdfReader.GetPageSize(1);
                float width = psize.Width;
                float height = psize.Height;
                PdfContentByte content;
                BaseFont font = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\SIMFANG.TTF", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
                PdfGState gs = new PdfGState();
                for (int i = 1; i < total; i++)
                {
                    content = pdfStamper.GetOverContent(i);//在内容上方加水印
                                                           //content = pdfStamper.GetUnderContent(i);//在内容下方加水印
                                                           //透明度
                    gs.FillOpacity = 0.3f;
                    content.SetGState(gs);
                    //content.SetGrayFill(0.3f);
                    //开始写入文本
                    content.BeginText();
                    content.SetColorFill(BaseColor.GRAY);
                    content.SetFontAndSize(font, 30);
                    content.SetTextMatrix(0, 0);

                    for (int ii = 0; ii < 5; ii++)
                    {
                        for (int j = 0; j < 5; j++)
                        {
                            content.ShowTextAligned(Element.ALIGN_CENTER, waterMarkName, (50.5f + ii * 350),(40.0f + j * 150), -45);
                        }
                    }

                    content.EndText();
                }

                if (pdfStamper != null)
                    pdfStamper.Close();

                if (pdfReader != null)
                    pdfReader.Close();

                return outStream;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

看了一下代码,发现并没有什么难点。算是一眼就能看明白写的是啥,我略加修改添加了两个for循环来实现水印的重复,不然原来它就一页一个水印。
同学们如果不需要一个多个水印的,可以把for循环去掉哈。
代码借鉴完后,抱着激动的心,尝试了一下,我擦,可以,而且很快,2380多页的pdf,不到6s就导出了。可以可以。
看来微信群里面的大佬还是比较厉害的,主要自己太菜了。
在这里插入图片描述
哦哦,差点忘记了,调用我顺便实现了两种,提供给大家参考,虽然不算是什么牛逼的代码,但是可以省去大家写哎,ctrl c+v 不香么~~

第一种:网络地址的pdf文件加水印后直接浏览器下载

/// <summary>
/// 下载水印PDF
/// </summary>
/// <param name="fileUrl">pdf地址</param>
/// <param name="waterMarkText">水印文字</param>
/// <param name="outFileName">输出文件名</param>
void GetWatermark(string fileUrl, string waterMarkText, string outFileName)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fileUrl);
            request.Method = "GET";
            WebResponse response = request.GetResponse();
            var stream = response.GetResponseStream();

            var outStream = SetWaterMark(stream, waterMarkText);
            var fileBytes = outStream.ToArray();

            httpContext.Response.ContentType = "application/octet-stream";
            httpContext.Response.AppendHeader("Content-Disposition", "attachment;filename=" + outFileName);//文件名和格式(格式可以自己定)
            httpContext.Response.AddHeader("Content-Length", fileBytes.Length.ToString());//文件大小
            httpContext.Response.BinaryWrite(fileBytes); //放入byte[]
            httpContext.Response.End();
            httpContext.Response.Close();
        }

第二种:给本地pdf文件添加水印

/// <summary>
        /// 给本地PDF文件添加水印
        /// </summary>
        /// <param name="filePath">E:/studyHome/my_tools_project/tools_project/123.pdf</param>
        /// <param name="text">xxx</param>
        public void AddWaterMark(string filePath, string text)
        {
            PdfReader pdfReader = null;
            PdfStamper pdfStamper = null;
            string tempPath = Path.GetDirectoryName(filePath) + Path.GetFileNameWithoutExtension(filePath) + "_temp.pdf";

            try
            {
                pdfReader = new PdfReader(filePath);
                pdfStamper = new PdfStamper(pdfReader, new FileStream(tempPath, FileMode.Create));
                int total = pdfReader.NumberOfPages + 1;
                iTextSharp.text.Rectangle psize = pdfReader.GetPageSize(1);
                float width = psize.Width;
                float height = psize.Height;
                PdfContentByte content;
                BaseFont font = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\SIMFANG.TTF", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
                PdfGState gs = new PdfGState();
                for (int i = 1; i < total; i++)
                {
                    content = pdfStamper.GetOverContent(i);//在内容上方加水印
                                                           //content = pdfStamper.GetUnderContent(i);//在内容下方加水印
                                                           //透明度
                    gs.FillOpacity = 0.3f;
                    content.SetGState(gs);
                    //content.SetGrayFill(0.3f);
                    //开始写入文本
                    content.BeginText();
                    content.SetColorFill(BaseColor.GRAY);
                    content.SetFontAndSize(font, 30);
                    content.SetTextMatrix(0, 0);
                    content.ShowTextAligned(Element.ALIGN_CENTER, text, width - 120, height - 120, -45);

                    content.EndText();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (pdfStamper != null)
                    pdfStamper.Close();

                if (pdfReader != null)
                    pdfReader.Close();
                File.Copy(tempPath, filePath, true);
                File.Delete(tempPath);
            }
        }

好了,至此,这个功能点算是解决了,我呢也学习了不少东西
发出来给大家做个参考,也是给自己一个记录。

欢迎大家一起探讨学习。

差点忘记,给大家看看效果:
在这里插入图片描述

橙子主题打折出售

其实我不卖,主要是这里是放广告的,所以就放了一个
毕竟主题都没做完,卖了也是坑.

购买它
本文为原创文章,请注意保留出处!

热门文章

Windows Server IIS+ARR反向代理(配置反向代理服务器) 1.概念说明:反向代理反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相...WindowsServerIIS+ARR反向代理(配置反向代理服务器) 作者:Pastore Antonio
1581 浏览量
ffmpeg 生成水印 1:先要配置ffmpeg的滤镜:参考:https://www.jianshu.com/p/9d24...ffmpeg生成水印 作者:Pastore Antonio
1508 浏览量
C#中List的FindAll方法的正确打开方式 初略的介绍一种常见的List写法,这种写法在3.0以后其实是很简单的,但是在2.0左右的系统运用中还...C#中List的FindAll方法的正确打开方式 作者:Pastore Antonio
1467 浏览量
IntelliJ IDEA 代码字体大小的快捷键设置放大缩小(很实用)(图文详解) 这是在设置IntelliJIDEA...IntelliJIDEA代码字体大小的快捷键设置放大缩小(很实用)(图文详解) 作者:Pastore Antonio
1461 浏览量
Navicat Premium 12.0.22 安装与破解 一、安装  NavicatPremium12.0.22的下载链接:https://pan.ba...NavicatPremium12.0.22安装与破解 作者:Pastore Antonio
1447 浏览量