Insertar una marca de agua en documentos PDF
Hace ya algún tiempo escribí un articulo introductorio a la librería iTextSharp - http://www.devjoker.com/contenidos/Articulos/374/Generar-archivos-PDFcon-C.aspx -. Este articulo tiene además una interesante discusion sobre los diferentes usos que podemos dar a esta libreria.
El siguiente ejemplo muestra uno de estos usos, como insertar una marca de agua a un documento PDF existente - de nuevo dar las gracias a mi ex compañero Raúl García-Escribano, en realidad el código de este articulo es suyo (yo solo lo he adaptado y modificado ligeramente).
Para la realizacion de este articulo he utilizado Visual Studio 2008 y C#. Creamos un nuevo proyecto de tipo consola y - evidentemente - tendremos que descargar y referenciar la librería iTextSharp para que todo funcione correctamente.
El objetivo del programa es partiendo de un archivo existente - "devjoker.pdf" -, leer el documento y "estampar" una marca de agua en cada página. El resultado de este proceso lo guardaremos en un nuevo documento.
Lo primero que necesitamos es incluir las clausulas using a la librería iTextSharp.
using iTextSharp.text; using iTextSharp.text.pdf;
|
En el Main de nuestro programa - al final del articulo está el código completo - declaramos un lector para el documento pdf - de tipo PdfReader e identificado por reader - un objeto document - ojo , es del tipo iTextSharp.text.Document - identificado por documento y un FileStream - ambos necesarios para escribir el archivo de salida - cuyo nombre formamos con un Guid.
string path = @"C:\devjoker.pdf"; PdfReader reader = new PdfReader(path); FileStream fs = null; Document document = null; document = new Document(); string outputPdf = String.Format("C:\\temp\\{0}.pdf", Guid.NewGuid().ToString());
fs = new FileStream( outputPdf, FileMode.CreateNew, FileAccess.Write);
|
Lo siguiente que vamos a necesitar es un "estampador" - PdfStamper -, asociado a este estampador definimos la fuente y el estado del grafico con la que queremos insertar la marca de agua - BaseFont y PdfGState respectivamente. Es importante tener en cuenta que es un ejemplo y la ruta de fuentes está directamente en el código - esta ruta puede variar dependiendo del SO - en entornos reales se recomienda obtener la ruta de un archivo de configuración o de formandola dinamicamente con el valor de la variable de entorno WINDIR.
PdfStamper stamp = null; stamp = new PdfStamper(reader, fs); BaseFont bf = BaseFont.CreateFont(@"c:\windows\fonts\arial.ttf", BaseFont.CP1252, true); PdfGState gs = new PdfGState(); gs.FillOpacity = 0.35F; gs.StrokeOpacity = 0.35F;
|
Con esto ya tenemos los elementos necesarios para recorrer todas la páginas devueltas por el lector - reader. En cada iteracion del bucle obtenemos el tamaño y contenido de la página y llamamos a un método auxiliar WriteTextToDocument que se encarga de escribir el texto www.devjoker.com en cada página.
for (int nPag = 1; nPag <= reader.NumberOfPages; nPag++) { Rectangle tamPagina = reader.GetPageSizeWithRotation(nPag); PdfContentByte over = stamp.GetOverContent(nPag); over.BeginText(); WriteTextToDocument(bf, tamPagina, over, gs, "www.devjoker.com"); over.EndText(); }
|
El método WriteTextToDocument se encarga de calcular la diagonal de la página e insertar el texto cruzando la página.
private static void WriteTextToDocument( BaseFont bf, Rectangle tamPagina, PdfContentByte over, PdfGState gs, string texto) { over.SetGState(gs); over.SetRGBColorFill(220, 220, 220); over.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_STROKE); over.SetFontAndSize(bf, 46); Single anchoDiag = (Single)Math.Sqrt(Math.Pow((tamPagina.Height - 120), 2) + Math.Pow((tamPagina.Width - 60), 2)); Single porc = (Single)100 * (anchoDiag / bf.GetWidthPoint(texto, 46)); over.SetHorizontalScaling(porc); double angPage = (-1) * Math.Atan((tamPagina.Height - 60) / (tamPagina.Width - 60)); over.SetTextMatrix( (float)Math.Cos(angPage), (float)Math.Sin(angPage), (float)((-1F) * Math.Sin(angPage)), (float)Math.Cos(angPage), 30F, (float)tamPagina.Height - 60); over.ShowText(texto); }
|
Podemos ver el resultado de la ejecución en la siguiente imagen:

El código completo del ejemplo es el siguiente:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using iTextSharp.text;using iTextSharp.text.pdf;using System.IO;namespace iTextSharpSample2{ class Program { static void Main(string[] args) { string path = @"C:\devjoker.pdf"; PdfReader reader = new PdfReader(path); FileStream fs = null; PdfStamper stamp = null; Document document = null; try { document = new Document(); string outputPdf = String.Format("C:\\temp\\{0}.pdf", Guid.NewGuid().ToString()); fs = new FileStream( outputPdf, FileMode.CreateNew, FileAccess.Write); stamp = new PdfStamper(reader, fs); BaseFont bf = BaseFont.CreateFont( @"c:\windows\fonts\arial.ttf", BaseFont.CP1252, true); PdfGState gs = new PdfGState(); gs.FillOpacity = 0.35F; gs.StrokeOpacity = 0.35F; for (int nPag = 1; nPag <= reader.NumberOfPages; nPag++) { Rectangle tamPagina = reader.GetPageSizeWithRotation(nPag); PdfContentByte over = stamp.GetOverContent(nPag); over.BeginText(); WriteTextToDocument(bf, tamPagina, over, gs, "www.devjoker.com"); over.EndText(); } } finally { // Garantizamos que aunque falle se cierran los objetos // alternativa:usar using reader.Close(); if (stamp != null) stamp.Close(); if (fs != null) fs.Close(); if (document != null) document.Close(); } Console.WriteLine("Fin de ejecucion"); Console.Read(); } private static void WriteTextToDocument(BaseFont bf, Rectangle tamPagina, PdfContentByte over, PdfGState gs, string texto) { over.SetGState(gs); over.SetRGBColorFill(220, 220, 220); over.SetTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_STROKE); over.SetFontAndSize(bf, 46); Single anchoDiag = (Single)Math.Sqrt(Math.Pow((tamPagina.Height - 120), 2) + Math.Pow((tamPagina.Width - 60), 2)); Single porc = (Single)100 * (anchoDiag / bf.GetWidthPoint(texto, 46)); over.SetHorizontalScaling(porc); double angPage = (-1) * Math.Atan((tamPagina.Height - 60) / (tamPagina.Width - 60)); over.SetTextMatrix((float)Math.Cos(angPage), (float)Math.Sin(angPage), (float)((-1F) * Math.Sin(angPage)), (float)Math.Cos(angPage), 30F, (float)tamPagina.Height - 60); over.ShowText(texto); } } }
|
Saludos y hasta la proxima. DJK