Logo

Logo

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

Pastore Antonio
Pastore Antonio 2022年07月18日
1165 阅读 0 评论 约 10680 字 阅读约 22 分钟

一、背景

最近有个项目需要实现给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);
            }
        }

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

欢迎大家一起探讨学习。

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

查看完整代码

橙子主题打折出售

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

购买它

附件下载

共 6 个文件
在这里插入图片描述
PNG 47.5 KB
在这里插入图片描述
PNG 29.3 KB
在这里插入图片描述
PNG 27.9 KB
在这里插入图片描述
PNG 39.4 KB
在这里插入图片描述
PNG 31.3 KB
在这里插入图片描述
PNG 167.0 KB
部分文章可能存在转载,如果涉及到侵权,请联系删除文章。

探索AIGC相关的精彩内容,共 15 篇文章

Azure AI 服务之语音识别

简介 Azure AI 服务中的语音识别 API 是微软提供的一项先进技术,旨在帮助开发者轻松实现语 ... Aspose、iText实现给PDF添加水印功能

2026-02-17 · Xzavier Aaron
MCP | 一文详解什么是 MCP以及 MCP 可以做什么

一、什么是 MCP MCP(Model Context Protocol)是一个专为大型语言模型(L ... Aspose、iText实现给PDF添加水印功能

2026-02-14 · Shen, Luke
你的工作流程,值得一个“全自动数字分身”:录制、截图、成文,一气呵成

一、一句话认识 TestFlow Recorder 在数字化工作环境中,如何准确记录操作步骤并生成清 ... Aspose、iText实现给PDF添加水印功能

2026-02-14 · Xzavier Aaron
Flowise 前端框架配置指南

用户需求 问题:有没有适合配置 Flowise 的前端框架? 目标:寻找类似 Open WebUI ... Aspose、iText实现给PDF添加水印功能

2026-02-14 · Xzavier Aaron