Pdf添加水印功能
背景
为防止涉密文件泄露,用户预览或下载pdf文件时,需要以用户信息作为水印内容加到pdf文件中。
实现
附件下载/预览接口:
/// <summary> /// pdf附件下载接口 /// </summary> /// <param name="fileId">fileId</param> /// <param name="userId">用户id</param> /// <returns></returns> [HttpGet("{fileId}/{userId}")] [AllowAnonymous] public IActionResult DownloadPdfFile(string fileId,string userId) { //从Mongo中下载文件 FileByteInfo file = this._fileService.DownloadFileStream(fileId); if (file == null) return Ok("文件不存在或已被删除!"); string type = ""; System.IO.Stream fileStream = file.FileStream; //文件流 string fileName = file.FileName; if (!string.IsNullOrWhiteSpace(userId)) { //获取用户身份 User user = this._userService.GetUser(userId); if (user != null) { //水印:姓名(登录名 所属部门) string waterMarkText = $"{user.Name}({user.Code}) {user.ParentName}"; System.IO.Stream waterPdfStream = PDFHelper.AddWatermark(fileStream, waterMarkText); //pdf添加水印 if (waterPdfStream != null) { fileStream = waterPdfStream; } } } System.IO.Stream fbyte = fileStream; try { var provider = new FileExtensionContentTypeProvider(); type = provider.Mappings[file.ContentType]; } catch (KeyNotFoundException) { type = "application/x-msdownload"; } return File(fbyte, type, fileName); }
● 根据file获取文件流,调用AddWatermark将流添加水印
PDFHelper类:
若出现本地调试支持,部署到docker后预览出错,可能是服务器字体问题:
//本地调用这个配置
BaseFont font = BaseFont.CreateFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
//docker下用这个配置
BaseFont font = BaseFont.CreateFont("/usr/share/fonts/simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
public static class PDFHelper { /// <summary> /// 添加倾斜水印 /// </summary> /// <param name="pdfStream">pdf文件流</param> /// <param name="waterMarkName">水印字符串</param> /// <param name="width">页面宽度</param> /// <param name="height">页面高度</param> public static MemoryStream AddWatermark(Stream pdfStream, string waterMarkName) { PdfReader pdfReader = null; PdfStamper pdfStamper = null; MemoryStream outStream = new MemoryStream(); try { pdfStream.Position = 0; pdfReader = new PdfReader(pdfStream); pdfStamper = new PdfStamper(pdfReader, outStream); 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("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); //docker下用这个配置 BaseFont font = BaseFont.CreateFont("/usr/share/fonts/simhei.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); PdfGState gs = new PdfGState(); int fontSize = 28; for (int i = 1; i < total; i++) { //在内容上方加水印 ;content = pdfStamper.GetUnderContent(i);//在内容下方加水印 content = pdfStamper.GetOverContent(i); gs.FillOpacity = 0.5f; //透明度 content.SetGState(gs); content.SetGrayFill(0.5f); //开始写入文本 content.BeginText(); content.SetColorFill(BaseColor.Blue); content.SetFontAndSize(font, fontSize); content.ShowTextAligned(Element.ALIGN_CENTER, waterMarkName, width / 2 + 150, height / 2 + 150, 55); content.SetColorFill(BaseColor.Blue); content.SetFontAndSize(font, fontSize); content.ShowTextAligned(Element.ALIGN_CENTER, waterMarkName, width / 2 - 150, height / 2 - 150, 55); content.EndText(); } } catch (Exception ex) { Console.WriteLine($"AddWatermark error:{ex.Message}, innerException:{ex.InnerException?.Message},stack:{ex.StackTrace}"); outStream = null; } finally { if (pdfStamper != null) pdfStamper.Close(); if (pdfReader != null) pdfReader.Close(); if (outStream != null) outStream.Position = 0; //必须重置位置,再写MongoDB } return outStream; } /// <summary> /// 加图片水印 /// </summary> /// <param name="inputfilepath">源文件路径</param> /// <param name="outputfilepath">输出路径</param> /// <param name="modelPicName">图片地址</param> /// <param name="top">图片水印top</param> /// <param name="left">图片水印left</param> /// <returns></returns> public static bool AddImageWatermarkPDF(string inputfilepath, string outputfilepath, string modelPicName, float top, float left) { PdfReader pdfReader = null; PdfStamper pdfStamper = null; try { pdfReader = new PdfReader(inputfilepath); int numberOfPages = pdfReader.NumberOfPages; iTextSharp.text.Rectangle psize = pdfReader.GetPageSize(1); float width = psize.Width; float height = psize.Height; pdfStamper = new PdfStamper(pdfReader, new FileStream(outputfilepath, FileMode.Create)); PdfContentByte waterMarkContent; iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(modelPicName); image.GrayFill = 20;//透明度,灰色填充 //image.Rotation //旋转 //image.RotationDegrees //旋转角度 //水印的位置 if (left < 0) { left = width / 2 - image.Width + left; } //image.SetAbsolutePosition(left, (height - image.Height) - top); image.SetAbsolutePosition(left, (height / 2 - image.Height) - top); //每一页加水印,也可以设置某一页加水印 for (int i = 1; i <= numberOfPages; i++) { //waterMarkContent = pdfStamper.GetUnderContent(i);//内容下层加水印 waterMarkContent = pdfStamper.GetOverContent(i);//内容上层加水印 waterMarkContent.AddImage(image); } return true; } catch (Exception ex) { throw ex; } finally { if (pdfStamper != null) pdfStamper.Close(); if (pdfReader != null) pdfReader.Close(); } } /// <summary> /// 添加普通偏转角度文字水印 /// </summary> /// <param name="inputfilepath">源文件路径</param> /// <param name="outputfilepath">输出路径</param> /// <param name="waterMarkName">水印内容</param> public static void AddWordWatermark2PDF(string inputfilepath, string outputfilepath, string waterMarkName) { //PDFHelper.AddWordWatermark2PDF("F:\\pdf1.pdf", "F:\\pdf1副本.pdf", "我是水印内容"); PdfReader pdfReader = null; PdfStamper pdfStamper = null; try { pdfReader = new PdfReader(inputfilepath); pdfStamper = new PdfStamper(pdfReader, new FileStream(outputfilepath, 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.GetUnderContent(i); //content = pdfStamper.GetUnderContent(i);//在内容下方加水印 //透明度 gs.FillOpacity = 0.5f; content.SetGState(gs); content.SetGrayFill(0.5f); //开始写入文本 content.BeginText(); //content.SetColorFill(BaseColor.LIGHT_GRAY); //content.SetFontAndSize(font, 100); //content.SetTextMatrix(0, 0); //content.ShowTextAligned(Element.ALIGN_CENTER, waterMarkName, width / 2 - 50, height / 2 - 50, 55); content.SetColorFill(BaseColor.Gray); content.SetFontAndSize(font, 16); content.ShowTextAligned(Element.ALIGN_CENTER, waterMarkName, width / 2 - 50, height / 2 - 50, 55); content.EndText(); } } catch (Exception ex) { throw ex; } finally { if (pdfStamper != null) pdfStamper.Close(); if (pdfReader != null) pdfReader.Close(); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!