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

Pedro  Herrarte  Sánchez
Insertar una marca de agua en documentos PDF
Pedro Herrarte Sánchez

Pedro Herrarte, es consultor independiente, ofreciendo servicios de consultoría, análisis, desarrollo y formación. Posee mas de diez años de experiencia trabajando para las principales empresas de España. Es especialista en tecnologías .NET, entornos Web (ASP.NET, ASP.NET MVC,jQuery, HTML5), bases de datos (SQL Server y ORACLE) e integración de sistemas. Es experto en desarrollo (C#, VB.Net, T-SQL, PL/SQL, , ASP, CGI , C, Pro*C, Java, Essbase, Vignette, PowerBuilder y Visual Basic ...) y bases de datos (SQL Server y ORACLE). Pedro es MCP y MAP 2012, es fundador, diseñador y programador de www.devjoker.com..
Fecha de alta:13/10/2009
Última actualizacion:13/10/2009
Visitas totales:16398
Valorar el contenido:
Últimas consultas realizadas en los foros
Últimas preguntas sin contestar en los foros de devjoker.com