- Home>
- .NET core>
- Stamp a PDF using iTextSharp for .NET core
Recently I had to implement the logic to “stamp” a PDF file in my ASP.NET core project. I found the sample codes from this SO post, which works greatly. I’ve extracted the logic into a sample project, which you can find on my github.
iText is a popular technology for working with PDF files. The current version as of this writing is iText7. However, the library is dual licensed as AGPL/Commercial, which mean you need to open source your project, or purchase the commercial license. The version which works with .NET core is iTextSharp.LGPLv2.Core which is free and what I use in the sample ASP.NET core project.
iTextSharp.LGPLv2.Core
iTextSharp.LGPLv2.Core
is an unofficial port of the last LGPL version of the iTextSharp (V4.1.6) to .NET Core
For another example of using iTextSharp.LGPLv2.Core library, check out my post which shows how to fill out a PDF form using the library.
dotnet add package iTextSharp.LGPLv2.Core
public class StampRequestForm { public string Line1 { get; set; } public string Line2 { get; set; } public string Line3 { get; set; } public float LowerLeftX { get; set; } public float LowerLeftY { get; set; } public float UpperRightX { get; set; } public float UpperRightY { get; set; }
// ASP.NET core has support to bind a
// multipart/form-data request to a model
//via model binding using the IFormFile interface. [Required] public IFormFile Pdf { get; set; } public int RotationDegree { get; set; } }
For simplicity, I store each line of text in a separate field. Then I can just use ASP.NET core model binding to bind a file upload request nicely to the model, without having to do much work.
public interface IStampService { Stream ApplyStamp(StampRequestForm stampRequest); } public class StampService : IStampService { private const int FontSize = 7; private readonly BaseFont Font = BaseFont.CreateFont(); private readonly BaseColor Color = BaseColor.Red; private const int VerticalSpaceBetweenLines = 15; public StampService() { } /// <summary> /// Stamp a PDF with the specific message and position as specified in the <see cref="StampRequest"/> /// https://stackoverflow.com/questions/2372041/c-sharp-itextsharp-pdf-creation-with-watermark-on-each-page# /// </summary> /// <param name="stampRequest"></param> /// <returns></returns> public Stream ApplyStamp(StampRequestForm stampRequest) { MemoryStream pdfOutStream; Stream pdfInstream = null; PdfReader reader = null; PdfStamper stamper = null; try { pdfOutStream = new MemoryStream(); pdfInstream = stampRequest.Pdf.OpenReadStream(); reader = new PdfReader(pdfInstream); stamper = new PdfStamper(reader, pdfOutStream); var dc = stamper.GetOverContent(1); AddWaterMark(dc, reader, stampRequest); return pdfOutStream; } finally { if (pdfInstream != null) { pdfInstream.Close(); } if (reader != null) { reader.Close(); } if (stamper != null) { stamper.Close(); } } } private void AddWaterMark(PdfContentByte dc, PdfReader reader, StampRequestForm stampRequest) { var gstate = new PdfGState { FillOpacity = 0.61f, StrokeOpacity = 0.61f }; dc.SaveState(); dc.SetGState(gstate); dc.SetColorFill(Color); dc.BeginText(); dc.SetFontAndSize(Font, FontSize); var x = (stampRequest.LowerLeftX + stampRequest.UpperRightX) / 2; var y = ((stampRequest.LowerLeftY + stampRequest.UpperRightY) / 2); var lines = new string[] {stampRequest.Line1, stampRequest.Line2, stampRequest.Line3} .Where(line => !string.IsNullOrEmpty(line)); foreach (var line in lines) { dc.ShowTextAligned(Element.ALIGN_CENTER, line, x, y, stampRequest.RotationDegree); y -= VerticalSpaceBetweenLines; } dc.EndText(); dc.RestoreState(); } }
[Route("api/[controller]")] [ApiController] public class PDFController : Controller { private readonly IStampService _stampService; public PDFController(IStampService stampService) { _stampService = stampService; } [HttpPost] [Route("stamp")] [Produces(contentType: "application/pdf")] public FileStreamResult Stamp([FromForm] StampRequestForm stampRequestForm) { Stream outStream = _stampService.ApplyStamp(stampRequestForm); outStream.Position = 0; return new FileStreamResult(outStream, "application/pdf"); } }
curl -X POST \
https://localhost:5001/api/pdf/stamp \
-H 'Postman-Token: d9016159-d9ac-4187-9291-6a0aac8a96c9' \
-H 'cache-control: no-cache' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F 'line1=This is a test stamp' \
-F line2=07/19/2019 \
-F line3=taithienbo.com \
-F LowerLeftX=402 \
-F LowerLeftY=600 \
-F UpperRightX=575 \
-F UpperRightY=900 \
-F pdf=@/PDFStampingExample/PDFStampingExample.Tests/Resources/sample.pdf
The above request applies the stamp near the top right.
Supporting Multiple Microsoft Teams Bots in One ASP.NET Core Application
Enhancing ASP.NET Core/Blazor App Security and Reusability with HttpMessageHandler and Named HttpClient
Dynamically adjust font size of text to fit into a PDF text field using iTextSharp.LGPLv2.Core.
Fill out a PDF form using iTextSharp for .NET core.
Web scraping in C# using HtmlAgilityPack
Building multitenant application – Part 2: Storing value into database session context from ASP.NET core web API
Common frameworks, libraries and design patterns I use
Build and deploy a WebJob alongside web app using azure pipelines