Sunday, July 29, 2007

Reportes en PDF con Report.net

Después de un buen tiempo lejos del mundo blog, vuelvo para hablar de una herramienta que me ha servido para hacer los reportes PDF en ya 3 sistemas de información, me refiero al open-source Report.net, una librería gratuita hosteada en sourceforge (report.net).

Se trata de una librería .net diseñada en lenguaje c# para generar reportes en PDF mediante asp.net y código puro y duro. Aunque a primera vista report.net puede parecer la vuelta al infierno de la generación de reportes, con una adecuada organización de código, llega a ser una herramienta excepcional para la generación de reportes con resultados que igualan y algunas veces superan a los acostumbrados reporteadores "visuales" tales como clásico Crystal Reports o XtraReports de DevExperience.


¿Ventajas?

Pues uno tiene el control total del reporte, es decir, puede manajar todos los aspectos del reporte, no sólo del cargado de datos, sino la creación dinámica de elementos según la programación lo requiera y defina. La libertad otorgada se resume en la customización completa del resultado del reporte. La librería funciona para las versiones 1.1, 2.0 y 3.0 de .net framework.

¿Desventajas?

Al no contar con una interfaz visual, es necesario definir todos y cada uno de los elementos del reporte, desde una tabla, línea de texto o caja de dibujo hasta una constante para definir los bordes. Se debe tener instalado Adobe Acrobat Reader, sugiero que esté instalada a partir de la versión 5.

¿Que tipo de contenido puedo generar?

Pues casi de todo: tablas, cuadros, adición de imágenes, párrafos, listas, formas, etc. Basta con descargar los ejemplos y ver los resultados que pueden realizarse.


Bueno, creo que es hora de un "Hola mundo". Para ello:

  1. Descargar la librería de aqui...

  2. Adicionar la librería Reports.dll a la carpeta bin de nuestra solución web.

  3. Crear una página asp.net llamada PaginaReporte.aspx y en el code-behind pegar el siguiente código

  4. Correr la página y listo.




using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using Root.Reports;
using System.Drawing;

public partial class PaginaReporte : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ReporteEjemplo reporte = new ReporteEjemplo();
RT.ResponsePDF(reporte, this);
}
}

public class ReporteEjemplo:Report
{
FontDef _definicionFuente;
FontProp _propiedadFuente;

protected override void Create()
{
NuevaPagina();
InicializarPropiedadesReporte();
ImprimirHolaMundo();
}

private void InicializarPropiedadesReporte()
{
// Este estilo de fuente debe ser definido sólo una vez
_definicionFuente = new FontDef(this, FontDef.StandardFont.TimesRoman);
_propiedadFuente = new FontProp(_definicionFuente, 10, Color.Navy);
}

private void ImprimirHolaMundo()
{
page_Cur.AddCT_MM(100, 50, new RepString(_propiedadFuente, "Hola mundo... ¿que esperabas?"));
}
internal void NuevaPagina()
{
new Root.Reports.Page(this);
}
}

Espero publicar mas ejemplos de reportes para esta librería los siguientes días para ayudar a aquellos que como yo se han visto en la necesidad de crear reportes de manera gratuita.

20 comments:

Rodrigo said...

Saludos, y disculpa por no responder antes.

Bueno, he revisado el código y funciona correctamente. Al principio tuve un error por que hice copy paste del código en el codebehind de una página denominada default.aspx.cs, pero el nombre del archivo aspx es PaginaReporte.aspx, así que se debe copiar el evento Page_Load y la clase ReporteEjemplo ademas de la referencia a Root.Reports

Ricardo Dulanto said...

Hola Rodrigo, interesante tu post. Actualmente estoy buscando una manera de convertir una pagina aspx(esta ha sido construida dinamicamente, y por ello varia siempre la cantidad de controles que lleva), en formato pdf. Osea el resultado de esta página pdf, que puede contener 4, 8, 12,etc. campos, quiero convertirlo a pdf. Como podría hacerlo utilizando esta librería?

Rodrigo said...

Saludos ricardo, bueno, pues es posible la generación de contenido dinámico mediante el uso de esta librería. Te comento que podrías usar la tabla de la librería. También podrías usar un flow layout que te muestra una tabla de una sola columna.

El uso que le dí fué de mostrar tablas con columnas generadas dinámicamente. y varias tablas en una misma página.

Voy a postear un ejemplo de cómo hacerlo, pero básicamente tienes que manejar los objetos de la tabla TableLayoutManager o si deseas el FlowLayoutManager.

Si deseas un poco más puedes dirigirte a http://sourceforge.net/forum/forum.php?forum_id=196392.
ahí tengo algunos aportes también.

Estos días pondré un ejemplo de cómo generar contenido dinámico.
saludos

Ricardo Dulanto said...

Hola Rodrigo, muchas gracias por tu pronta respuesta. Pues te agradecería que me des un ejemplo, por lo que te entendí, me dices que debo colocar el contenido de mi página dentro de tablas. De antemano te agradezco por el apoyo.

Lilian Armas said...

Hola Rodrigo! ha pasado mucho tiempo desde tu Post, pero espero puedas ayudarme... Existirá alguna manera de justificar el texto en el PDF, usando esta libreria? Hasta ahora solo se como centrarlo, alinearlo a la derecha y a la izquierda... Muchas gracias de ante mano...!

Rodrigo said...

Hola Lilian, en lo que respecta a la impresión de texto, decirte que éste es en las coordenadas que le indiques, por lo que necesitarías un contenedor como un ListLayoutManager. Esto te permitiría imprimir el texto estilo justificado.

Te paso un snippet de código que podrías utilizar:

-- Evento:

public void llmTituloIdea_Container(Object oSender, ListLayoutManager.NewContainerEventArgs ea)
{
// the new container must be added to the current page
page_Cur.AddCT_MM(60, 100, ea.container);
}


-- En tu método de muestra el texto :
ListLayoutManager vLayoutManager;
using (vLayoutManager = new ListLayoutManager(this))
{
#region Setea Tabla
vLayoutManager.tlmCellDef_Default.penProp_LineBottom = new PenProp(this, 0.05, Color.White); // set bottom line for all cells
vLayoutManager.tlmHeightMode = TlmHeightMode.AdjustLast;
#endregion

vLayoutManager.eNewContainer += new ListLayoutManager.NewContainerEventHandler(llmTituloIdea_Container);

TlmColumnMM col;

col = new TlmColumnMM(vLayoutManager, 100);
col.tlmCellDef_Default.tlmTextMode = TlmTextMode.MultiLine;

vLayoutManager.NewRow();
vLayoutManager.Add(0, new RepString(_fontProperty,"To Decide on the Grand Vitara that fits your budget. Decidir sobre la Grand Vitara que se ajuste a su presupuesto. The Grand Vitara went into production in 1999 and has been popularly produced for a decade. El Grand Vitara entró en producción en 1999 y ha sido popularmente producido durante una década. There will be a wide fluctuation of price ranges for the used Grand Vitaras depending on whether you decide to purchase a 1999 model (about $3,000 to $5,000 as of August 2009) or a 2008 model ($13,000 to $19,000). Habrá una amplia fluctuación de los rangos de precios para el Gran Vitaras utilizados en función de si usted decide comprar un modelo 1999 (alrededor de $ 3.000 a $ 5.000 a partir de agosto de 2009) o un modelo 2008 ($ 13,000 a $ 19,000). "));
}



Un abrazo

Lilian Armas said...

Gracias Rodrigo por responder. He revisado la solución que me propones, y verás, yo estoy haciendo un reporte, y ya estoy usando un contenedor para delimitar los márgenes del texto, el problema es precisamente que el texto sale alineado a la izquierda, a la derecha, o al centro. No, justificado con ambos márgenes (parecido a la funcion de Justificado de Word). No se si logras entenderme?

Rodrigo said...

Si, te entiendo, al parecer esta característica de justificado no está disponible en este componente.

Tal vez podrías intentar adicionar línea a línea si es que es un contenido estático.

Podrías pedir el justificado en el foro o en esta dirección:
http://sourceforge.net/projects/report/develop

Lamento no poder ayudarte con este tema. Un saludo cordial

Anonymous said...

Hola que tal tocayo, que bueno que has posteado sobre el tema, haz convertido con esta librería de HTML a PDF??, o conoces alguna que lo haga, estoy haciendo una app comercial por lo que iText no me sirve (no me quieren pagar la licencia :@) ni algún otro que tenga licencia, Report.NET es perfecto, pero no logro convertir mi html plano... gracias.
- Rodrigo Márquez.

Anonymous said...

Soy, yo, anónimo(del comentario anterior), mi nombre es Rodrigo Márquez, mi solución hasta hace dos semanas fué utilizar Report.NET y debido a que el HTML que necesitaba convertir utilizaba CSS (como el 99.9999% de los htmls) decidí convertir mi HTML a JPEG (con el web browser de C# y una función que encontré googleando) y luego con Report.NET incrustar la imagen al PDF. Por ahí veo otra opción que es utilizar el PDFCreator invocando su .exe desde mi app en C#. Espero a alguien le sirva mi experiencia... Viva el SW libre!

Rodrigo said...

Hola tocayo Rodrigo, perdona por la tardanza. Me parece genial la solución que brindaste, es una excelente manera de mostrar la página web completa, si puedes enviar un ejemplo de la solución o un link de cómo hacerlo muchas de las personas que requieren una librería como esta te lo agradecerían mucho.

un abrazo

Rodrigo.

Anonymous said...

Hola que tal tocayo!, pensé en pegar el código pero el espacio de texto es reducido, pero les paso el link de donde tomé el código para convertir de html a imagen:
http://www.codeproject.com/KB/graphics/html2image.aspx

El resto es pegar esa imagen al pdf usando Report.NET, algo así:
public static void ConvertToPDF(Stream imageStream, string uriGeneracionPDF)
{
Report report = new Report(new PdfFormatter());
Page page = new Page(report);
page.rAlignH = Page.rAlignCenter;
page.rAlignV = Page.rAlignBottom;

page.AddMM(1, 120, new RepImageMM(imageStream, Double.NaN, 117)); //117 es en el caso de una hoja tamaño dCarta

RT.ViewPDF(report, uriGeneracionPDF);
}

nanainana said...

Buenos días Rodrigo,
Lo primero de todo darte las gracias por tu post. Me gustaría probar el ejemplo que muestras pero el código para el code-behid de PaginaReporte.aspx ya no esta disponible, ¿podrías volverlo a subir? Un saludo y gracias!

Rodrigo said...

Hola nanainana,
Subiré el ejemplo el día de mañana por cuestiones de trabajo. Te pido esperes un poco más.

Un saludo cordial

Rodrigo said...

El ejemplo lo puedes bajar de:
http://www.megaupload.com/?d=ZULKVJKO

saludos.

nanainana said...

Muchas gracias Rodrigo, Ahora lo pruebo

nanainana said...

Buenas tardes,

Me resulto muy util el código, muchas gracias, ahora me fallan dos cosas que no se si me podrían ayudar, tengo el texto dentro de un contenedor, y me gustaria centrar alguna de las frases. He leido en el comentario de lilian que sabia como hacerlo, la otra es que quiero guardar el pdf generado automaticamente en vez de mostrarlo.

Un saludo y Gracias.

Anonymous said...

Hola, yo hace rato estoy trabajando con Reports.Root y la verdad es que es muy útil. Ahora tengo una nueva necesidad y no sé si alguno de uds. ya lo ha solucionado. El tema sería que se abra el PDF dentro de un ContentPlaceHolder.
Si alguien logró hacerlo les agradecería que me envíen la forma (phoenixsebastian@yahoo.com.ar)
Gracias.-

Rodrigo said...

Hola @nanainana, ummm, me parece que podrías hacerlo con el método Save del report, aunque según recuerdo no me funcionaba bien sobretodo porque se guardaba en el servidor y yo quería que se mande al cliente. Pero pueden haber formas intermedias haciendo que el output cambie.

@phoenixsebastian, Me parece que lo que quieres hacer es mostrar el contenido de lo generado por la librería hacia un div (que es a lo que aterriza un ContentPlaceHolder en html) Yo sugeriría intentar poner un iframe el contenido generado o tal vez modificar la librería y buscar el archivo donde formatea a que el tipo de salida sea PDF. Un post escrito hace un tiempo es este blog dice cómo entrar en esa sección.

Espero sea de utilidad.
Saludos

Orlando Fernandez said...

el post esta bueno pero como puedo modificar o donde puedo incluir mas fuentes ya que los q se tienen son muy basicos y a veces se puede necesitar otras fuentes de texto.
por otro lado tambien hay un problemita en los text para poder justificar cosa que todo se vea como en un word por eejemplo
si me puede dar una mano en esto lo mas antes posible se lo agradecere infinitamente gracias