First off, yes, I know there are other tutorials on how to watermark PDF’s with iTextSharp. Unfortunately none of them showed me exactly what I wanted to do – which is why I wrote this one.
Currently I’m involved with a project that utilizes PDF’s as their main product – a legal document. When I arrived to this client they utilized iTextSharp to "watermark" their PDF’s. I’ve been wanting to get my hands dirty with iTextSharp for awhile now. So I cracked open the code base one weekend to see how they were watermarking the PDF’s. After poking around for about 2 minutes I saw how they were performing the "watermarking" and unfortunately it was not the best way to get the job done.
Problems with current implementation:
- Images were used to write text.
- The watermark orientation would always end up as Portrait.
- The watermarked text could never be changed.
- Well, it could be, but it took a code change. The images were kept as resources in the library. So if they needed a new watermark, that meant a code change, testing and a redeploy.
So How Do We Fix This? What’s the End Goal?
- We want to be able to watermark the PDF document with Text, not images.
- The code should detect page orientation.
- We should be able to watermark the PDF with text that we provide at run time.
Current Document | Expected Result |
A Non watermarked document | A watermarked document (red is below the text) |
The Solution
I’m very amazed with iTextSharp’s ability to manipulate PDF’s. From existing PDF’s to new PDF’s to content extraction, iTextSharp does it all. The best part about it is… ITS FREE (other than your development time, that is).
I’ve created a solution which I provide the download link for at the bottom of the post, but for now here’s the code that does the dirty work:
FooTheoryPdf.cs
1 using System.IO; 2 using System.Text; 3 using iTextSharp.text; 4 using iTextSharp.text.pdf; 5 6 namespace FooTheory.iTextSharpLibrary 7 { 8 /// <summary> 9 /// Example PDF Class 10 /// </summary> 11 public class FooTheoryPdf 12 { 13 /// <summary> 14 /// Method that will utilize iTextSharp to write the <see cref="stringToWriteToPdf"/> to the 15 /// pdf on each page of the PDF. 16 /// </summary> 17 /// <param name="sourceFile">The PDf File</param> 18 /// <param name="stringToWriteToPdf">The text to write to the pdf</param> 19 /// <returns>The bytes of the newly updated PDF with <see cref="stringToWriteToPdf"/> in the pdf.</returns> 20 public static byte[] WriteToPdf(FileInfo sourceFile, string stringToWriteToPdf) 21 { 22 PdfReader reader = new PdfReader(sourceFile.FullName); 23 24 using (MemoryStream memoryStream = new MemoryStream()) 25 { 26 // 27 // PDFStamper is the class we use from iTextSharp to alter an existing PDF. 28 // 29 PdfStamper pdfStamper = new PdfStamper(reader, memoryStream); 30 31 for (int i = 1; i <= reader.NumberOfPages; i++) // Must start at 1 because 0 is not an actual page. 32 { 33 // 34 // If you ask for the page size with the method getPageSize(), you always get a 35 // Rectangle object without rotation (rot. 0 degrees)—in other words, the paper size 36 // without orientation. That’s fine if that’s what you’re expecting; but if you reuse 37 // the page, you need to know its orientation. You can ask for it separately with 38 // getPageRotation(), or you can use getPageSizeWithRotation(). - (Manning Java iText Book) 39 // 40 // 41 Rectangle pageSize = reader.GetPageSizeWithRotation(i); 42 43 // 44 // Gets the content ABOVE the PDF, Another option is GetUnderContent(...) 45 // which will place the text below the PDF content. 46 // 47 PdfContentByte pdfPageContents = pdfStamper.GetUnderContent(i); 48 pdfPageContents.BeginText(); // Start working with text. 49 50 // 51 // Create a font to work with 52 // 53 BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, Encoding.ASCII.EncodingName, false); 54 pdfPageContents.SetFontAndSize(baseFont, 40); // 40 point font 55 pdfPageContents.SetRGBColorFill(255, 0, 0); // Sets the color of the font, RED in this instance 56 57 58 // 59 // Angle of the text. This will give us the angle so we can angle the text diagonally 60 // from the bottom left corner to the top right corner through the use of simple trigonometry. 61 // 62 float textAngle = 63 (float) FooTheoryMath.GetHypotenuseAngleInDegreesFrom(pageSize.Height, pageSize.Width); 64 65 // 66 // Note: The x,y of the Pdf Matrix is from bottom left corner. 67 // This command tells iTextSharp to write the text at a certain location with a certain angle. 68 // Again, this will angle the text from bottom left corner to top right corner and it will 69 // place the text in the middle of the page. 70 // 71 pdfPageContents.ShowTextAligned(PdfContentByte.ALIGN_CENTER, stringToWriteToPdf, 72 pageSize.Width/2, 73 pageSize.Height/2, 74 textAngle); 75 76 pdfPageContents.EndText(); // Done working with text 77 } 78 pdfStamper.FormFlattening = true; // enable this if you want the PDF flattened. 79 pdfStamper.Close(); // Always close the stamper or you'll have a 0 byte stream. 80 81 82 return memoryStream.ToArray(); 83 } 84 } 85 } 86 }
Then there is a small math library I created to get the angle of the text through some simple Trig.
FooTheoryMath.cs
1 using System; 2 3 namespace FooTheory.iTextSharpLibrary 4 { 5 /// <summary> 6 /// Math library 7 /// </summary> 8 public static class FooTheoryMath 9 { 10 public static double GetHypotenuseAngleInDegreesFrom(double opposite, double adjacent) 11 { 12 //http://www.regentsprep.org/Regents/Math/rtritrig/LtrigA.htm 13 // Tan <angle> = opposite/adjacent 14 // Math.Atan2: http://msdn.microsoft.com/en-us/library/system.math.atan2(VS.80).aspx 15 16 double radians = Math.Atan2(opposite, adjacent); // Get Radians for Atan2 17 double angle = radians*(180/Math.PI); // Change back to degrees 18 return angle; 19 } 20 } 21 }
The Results
Utilizing a simple interface:
We’re able to generate PDF’s that are watermarked on an angle from bottom left corner to top right corner.
Here is a screen shot of what the generated PDF looks like:
Clicking the Top button:
Clicking the Bottom Button:
I’m able to change the message:
This will produce:
Conclusion
I found the iTextSharp quite versatile for working with PDF’s. This solution will help you write text to existing PDF’s quite easily.
Possible implementations include:
- Place this into a WCF service to create a watermarking service
- Leave it as it is, implemented as a class library.
- Create your own .NET PDF Client that you could sell (I’ve read somewhere – cant find the source – that a couple third party .NET PDF components are actually written on top of iTextSharp).
While working to accomplish what I have above I found the best reference for iTextSharp was actually the iText Book written by Bruno Lowagie. You can purchase it here on Amazon.com.
And Finally … While writing this I kept thinking …..
Why would you want to watermark existing PDF’s?
There are a few options.
- Accountability: Lets say you have a ton of PDF’s stored from a long running highly confidential report process and these PDF’s are stored nightly/weekly on a certain directory. Perhaps you want to make sure that when a user logs in and accesses one of these highly confidential PDF’s you water mark it with the users name on each page. Therefore, if it makes it into the hands of the media, you can see where/who it came from.
- Licensing: Perhaps you main product is a PDF. Lets say you’re a book publisher and you sell PDF versions of the book or you allow people who have already purchased the hard copy to download the PDF version. What you can do is force the user to create a profile in order to download the PDF. Usually this also includes some type of security question like "turn to page 435 and give us the last word on the page" in order to validate the user actually HAS the book in hand. Once they are authorized to download the PDF book, you can watermark every page on the book with their name "Licensed to: <FirstName> <LastName>. Let’s face it, people are MUCH less likely to give a PDF book away on Torrent or P2P software when every single page has their name on it. It’s not the BEST method of licensing, but it works.
- Other: Perhaps Company A is acquired by Company B and Company B wants to make sure that all PDF’s on Company A’s site are amended with the text "Company A is a subsidiary of Company B". What if company A has 15,000 PDF’s that they have on their site? Maybe its a resume assistance site that has over 15,000 sample resumes. Are you going to open each PDF and do this by hand? Nope. Not at all. You can intercept the call for the PDF’s and then write the text at the bottom before they’re delivered to the end user.
- The list could go on and on …
Download The Code
Coach Outlet Online says
http://www.mycoachoutletstoreonline.com
haha says
authentic nfl jerseys Inexpensive items
coach bags on sale I am confident with his
coach outlet store online First step in success
coach outlet online Workmanship
coach bags outlet Value of goods
coach outlet store Of love
wholesale designer bags Beautiful lines
coach bags outlet There range of children
cheap coach What are you waiting
wholesale nfl jerseys Is always expected
authentic nfl jerseys It is pretty good
oakleys says
YT4M327CJS02QNU
Welcome to Oakley Sunglasses Hut to buy cool and cheap oakleys sunglasses.
Coach Factory Outlet says
http://buycoachfactoryoutletsz.com
VPS Hosting says
A mind blowing article is provided here. And it is written
with great skill and the words directly explain the thought of author and it is
nice to know the information provided around the Earth and really it is great
topic of interest.
Edward Joell says
This is wonderful. How weird. We are trying to read a PDF from a database as a stream, add a settable watermark to the document, and then read the document in the browser viewer, from whence it can be printed. We do not wish to save the document with the watermark in the DB, only the pre-watermarked document. This is the only place I could find that shows how this can be done with ITextSharp. PDFSharp and some commercial of the shelf tools can do this just fine. I wonder why I can find so few examples of doing this in ITextSharp but so many examples of this in the other tools?
One thing I am not clear about is your class and namespace. Are you creating this class in the ItextSharp library to extend it, or are you just creating a new class that gets independently referenced in your web application?
Donn Felker says
Creating it as its own class in my project. No need to extend or modify the library.
Donn
rehan mustafa says
I have found a code for adding text in existing pdf file and also formatting the text, it was very useful for me. Below is the link of the code:
http://www.aspose.com/docs/display/pdfjava/Add+Text+to+an+existing+PDF+file