Esta página puede contener texto traducido automáticamente.
Guía de inicio rápido para la generación de PDF en C#
Lea acerca de cómo generar archivos PDF como informes, facturas y recibos en sus proyectos .NET. Usando C# o VB.NET, cree documentos PDF fácilmente componiendo elementos estructurales. Los elementos incluyen encabezados, pies de página, contenedores, tablas, párrafos, imágenes y similares. La API divide automáticamente el contenido en páginas.
Algunos otros métodos para generar archivos PDF se describen en el artículo Crear documentos PDF en C# y VB.NET.
Ofrecemos la API de diseño como complemento gratuito para la biblioteca Docotic.Pdf. Tanto la biblioteca como el complemento Layout están disponibles en NuGet y en nuestro sitio. Obtenga la biblioteca, el complemento y una clave de licencia gratuita por tiempo limitado en la página Descargar la biblioteca PDF de C# .NET.
9.5.17615-dev 9.5.17615-dev14,813 pasaron Descargas totales de NuGet 4,924,084
Instalación
Instale el paquete BitMiracle.Docotic.Pdf.Layout desde NuGet. Esta es la forma más fácil y conveniente de instalar el complemento Layout.
Como alternativa, puede descargar el ZIP con los binarios de la biblioteca en nuestro sitio. Para utilizar Layout API, agregue referencias a las siguientes DLL del paquete ZIP:
BitMiracle.Docotic.Pdf.dll
Layout add-on/BitMiracle.Docotic.Pdf.Layout.dll
El enfoque
El punto de entrada es la clase
PdfDocumentBuilder. Para comenzar a generar un
PDF, llame al método Generate de la
clase. El método requiere un delegado de tipo
Action
<Document> como uno de sus parámetros. La
biblioteca espera que usted diseñe el contenido del documento en el delegado.
PdfDocumentBuilder.Create().Generate("output.pdf", (Document doc) =>
{
// crear contenidos del documento aquí
});
Dado un objeto Document
, el delegado debe definir el diseño. El diseño completo consta de bloques
de construcción más pequeños. Páginas, encabezados y pies de página, contenedores y bloques de
texto son ejemplos de dichos bloques.
Muchas llamadas a métodos están encadenadas. El orden de las llamadas en una cadena es importante. A continuación se muestra un ejemplo que muestra cómo configurar el contenido de las páginas en algunas llamadas encadenadas.
PdfDocumentBuilder.Create()
.Generate("output.pdf", doc => doc.Pages(pages =>
{
pages.Content().Padding(24).AlignCenter().Text("Some text");
}));
Intellisense le ayudará a descubrir la API. Pruebe la API usted mismo. Espero que te resulte fácil de usar.
¡Hola Mundo!
Desarrollemos una aplicación sencilla que muestre los componentes básicos comunes en acción. La aplicación utilizará el enfoque mencionado anteriormente.
Puse el código completo de la aplicación en nuestro repositorio de códigos de
muestra Docotic.Pdf. El código para este paso está en la clase HelloWorld
de la aplicación de
ejemplo.
public void CreatePdf()
{
PdfDocumentBuilder.Create().Generate("hello.pdf", doc => doc.Pages(page =>
{
page.Content().Text("Hello, world!");
}));
}
No hay mucho código, pero ¿qué está pasando aquí?
Explicación larga para el código corto.
El código crea una instancia del generador de documentos y le pide al generador que genere
hello.pdf
. El constructor delega el trabajo de diseño del contenido del documento a mi código.
En el código del delegado, le pido al documento que cree algunas páginas. Ahora el documento delega el trabajo de diseñar el contenido de las páginas en mi código.
En el delegado de las páginas, accedo al contenedor de diseño para el contenido principal de las páginas. Hago esto llamando al método Content. La llamada encadenada a Text agrega el famoso intervalo de texto al contenido de las páginas.
Ahora es el momento de que el constructor genere el documento con algunas páginas según el diseño proporcionado. El constructor crea la cantidad exacta de páginas necesarias para contener los datos que agregué al contenedor de diseño para el contenido principal. ¿Una página es suficiente en este caso? Bueno.
Prepárese para futuras actualizaciones
Voy a agregar algunas características más al código. Para que sea más conveniente seguir desarrollando la aplicación, cambié el código de esta manera:
public void CreatePdf()
{
PdfDocumentBuilder.Create().Generate("hello.pdf", BuildDocument);
}
static void BuildDocument(Document doc)
{
doc.Pages(BuildPages);
}
static void BuildPages(PageLayout pages)
{
pages.Content().Text("Hello, world!");
}
Puede parecer innecesario, pero dividir el código en métodos al menos lo hace más legible.
El código de muestra para este paso está en la clase HelloWorld2
de la aplicación de
ejemplo.
Recursos Relacionados
Consulte los siguientes artículos para obtener más información sobre documentos, páginas y contenedores.
Fuentes y colores
La fuente predeterminada es buena, pero mostraré cómo usar otra. La idea principal es crear un estilo de texto usando una fuente. Luego, si es necesario, aplique algunas propiedades opcionales al estilo y, finalmente, use el estilo en un segmento de texto.
Puede utilizar una fuente de la colección de fuentes instaladas en el sistema operativo o cargar una fuente desde un archivo o secuencia.
Recomiendo anular los estilos predefinidos configurando la tipografía para el documento. Pero eso no es necesario y puedes usar estilos de texto directamente.
El código de muestra para este paso está en la clase HelloWorld3
de la aplicación de
ejemplo. A continuación se muestran las partes que cambiaron desde el paso
anterior.
static void BuildDocument(Document doc)
{
doc.Typography(t =>
{
t.Document = doc.TextStyleWithFont(SystemFont.Family("Calibri"));
});
doc.Pages(BuildPages);
}
static void BuildPages(PageLayout pages)
{
pages.Size(PdfPaperSize.A6);
pages.Margin(10);
BuildTextContent(pages.Content());
}
static void BuildTextContent(LayoutContainer content)
{
var colorAccented = new PdfRgbColor(56, 194, 10);
var styleAccented = TextStyle.Parent.FontColor(colorAccented);
content.Text(t =>
{
t.Span("Hello, ").Style(styleAccented);
t.Span("world!").Style(styleAccented.Underline());
});
}
Como puede ver, actualicé el código para BuildDocument
y BuildPages
. También agregué un nuevo
método llamado BuildTextContent
.
En BuildDocument
, creo un estilo de texto a partir de la fuente del sistema llamado "Calibri".
Luego configuro este estilo de texto como estilo de texto predeterminado para el documento.
El método BuildPages
ahora contiene código para configurar el tamaño y el margen de todas las
páginas. Además, el método llama a BuildTextContent
y pasa el contenedor del contenido principal
de las páginas como parámetro.
La forma en que construyo el contenido principal es diferente ahora. Utilizo dos tramos de texto y aplico diferentes estilos de texto a cada tramo. De hecho, ambos tramos utilizan el color de acento, pero el segundo tramo también tiene un subrayado.
El código produce un PDF con la fuente y el color del texto personalizado. Si su resultado contiene un mensaje de advertencia de prueba, obtenga una licencia gratuita por tiempo limitado en la página de la biblioteca Docotic.Pdf.
Encabezado y pié de página
Muchos documentos PDF del mundo real, como informes o facturas, contienen encabezado y pie de página. Déjame mostrarte cómo agregar encabezado y pie de página a un PDF.
El código de muestra para este paso está en la clase HelloWorld4
de la aplicación de
ejemplo. A continuación se muestran las partes que cambiaron desde el paso
anterior.
static void BuildPages(PageLayout pages)
{
pages.Size(PdfPaperSize.A6);
pages.Margin(10);
BuildPagesHeader(pages.Header());
BuildPagesFooter(pages.Footer());
BuildTextContent(pages.Content());
}
static void BuildPagesHeader(LayoutContainer header)
{
header.TextStyle(TextStyle.Parent.FontSize(8))
.AlignRight()
.Text(t =>
{
t.Line($"Created by: {Environment.UserName}");
t.Line($"Date: {DateTime.Now}");
});
}
static void BuildPagesFooter(LayoutContainer footer)
{
footer.Height(20)
.Background(new PdfGrayColor(95))
.AlignCenter()
.Text(t => t.CurrentPageNumber());
}
Cambié el método BuildPages
para llamar a BuildPagesHeader
con el contenedor del encabezado
como parámetro. El método también llama a BuildPagesFooter
pasándole el contenedor de pie de
página.
El PDF con encabezado y pie de página resultante definitivamente se parece más a un documento PDF profesional.
El método BuildPagesHeader
establece un tamaño de fuente más pequeño para el texto. Utilizo dos
líneas para el contenido del encabezado: una con el nombre del usuario actual y la segunda con la
fecha actual. El texto está alineado a la derecha.
Tenga en cuenta que no especifico ningún tamaño explícito para el encabezado. Ocupará todo el ancho de la página menos los márgenes izquierdo y derecho. La altura dependerá de la altura de las líneas de texto.
El pie de página es similar, excepto que su altura se especifica explícitamente. Y se le aplica un color de fondo. La parte interesante es que para poner el número de página actual en el pie de página del PDF, puedo usar el método CurrentPageNumber. Todos los cálculos se realizan dentro de la biblioteca.
Imágenes
Como dicen, puedes ahorrar muchas palabras usando una imagen. En una cotización o recibo, probablemente utilizará un logotipo de su empresa o alguna otra imagen importante. Para este código de ejemplo, usaré uno bonito.
El archivo está en nuestro sitio, para que veas cómo se ve el PDF con la hermosa imagen resultante.
Para utilizar una imagen, primero deberá agregarla al documento. La biblioteca puede leer la imagen
de un archivo o una secuencia. Cambié el método BuildDocument
para mostrar cómo agregar una
imagen al documento.
El código de muestra para este paso está en la clase HelloWorld5
de la aplicación de
ejemplo. A continuación se muestran las partes que cambiaron desde el paso
anterior.
static void BuildDocument(Document doc)
{
doc.Typography(t =>
{
t.Document = doc.TextStyleWithFont(SystemFont.Family("Calibri"));
});
var imageFile = new FileInfo("red-flowers-at-butterfly-world.jpg");
var image = doc.Image(imageFile);
doc.Pages(pages => {
BuildPages(pages);
pages.Content().Column(c =>
{
BuildTextContent(c.Item());
BuildImageContent(c.Item(), image);
});
});
}
static void BuildPages(PageLayout pages)
{
pages.Size(PdfPaperSize.A6);
pages.Margin(10);
BuildPagesHeader(pages.Header());
BuildPagesFooter(pages.Footer());
}
static void BuildImageContent(LayoutContainer content, Image image)
{
content.AlignCenter()
.PaddingVertical(20)
.Image(image);
}
Como puede ver, hay más cambios en el método BuildDocument
. Antes, el código usaba el método
Text para establecer algo de texto como
contenido principal de las páginas. Esto todavía sucede en el método BuildTextContent
. Pero ahora
también quiero una imagen en el contenido.
Para tener tanto el texto como la imagen en el contenido principal de las páginas, necesito un
contenedor. Utilizo el contenedor Column para agregar el
texto y la imagen verticalmente uno tras otro. El método
Item del contenedor de columnas proporciona un
subcontenedor. Utilizo una llamada al método Item
para obtener un contenedor para el texto y otra
llamada para obtener un contenedor para la imagen.
Como puede ver, no cambié ni un poco BuildTextContent
. Pero, por supuesto, tuve que eliminar una
llamada a BuildTextContent
del método BuildPages
.
BuildImageContent
does an important job in three lines. It adds the image with some padding at
the top and at the bottom. And it also centers the image on the page.
Tenemos más información sobre el contenedor Column y las imágenes en los siguientes artículos.
Listas
¿Qué es una lista? Pensemos en ello como un grupo de elementos numerados escritos uno debajo del otro. Esta idea sugiere una forma de implementar una lista.
El código de muestra para este paso está en la clase HelloWorld6
de la aplicación de
ejemplo. A continuación se muestran las partes que cambiaron desde el paso
anterior.
static void BuildDocument(Document doc)
{
....
doc.Pages(pages => {
BuildPages(pages);
pages.Content().Column(c =>
{
BuildTextContent(c.Item());
BuildImageContent(c.Item(), image);
BuildListContent(c.Item());
});
});
}
static void BuildListContent(LayoutContainer content)
{
var dayNames = DateTimeFormatInfo.InvariantInfo.DayNames;
var dayNamesSpain = DateTimeFormatInfo.GetInstance(new CultureInfo("es-ES")).DayNames;
content.Column(column =>
{
for (int i = 0; i < dayNames.Length; i++)
{
column.Item().Row(row =>
{
row.Spacing(5);
row.AutoItem().Text($"{i + 1}.");
row.RelativeItem().Text(t => {
t.Line(dayNames[i]);
t.Line($"In Spain they call it {dayNamesSpain[i]}");
});
});
}
});
}
El único cambio en BuildDocument
es la nueva llamada al método. Agregué la llamada a
BuildListContent
después de la llamada BuildImageContent
.
BuildListContent
crea la lista como una columna de filas. En cada fila hay dos elementos. El
primero (izquierdo) es para el número de artículo. Otro (derecha) es para el texto del elemento. El
código establece explícitamente el espacio entre los elementos de la fila.
Para organizar los elementos, el contenedor Row necesita saber de antemano o calcular el tamaño de cada elemento. Utilizo los métodos AutoItem y RelativeItem en este ejemplo. Como resultado, el contenedor de filas calculará el ancho requerido para contener el primer elemento. Luego, el contenedor utilizará el ancho restante disponible para el segundo artículo.
Después de agregar la lista, el contenido del PDF resultante ya no cabe en una página. Layout API agrega automáticamente la segunda página y coloca la lista en ella. Puede ver que la API repitió el encabezado y el pie de página en la nueva página en el documento PDF con varias páginas.
Tenemos más información sobre listas en el artículo Contenedores compuestos.
Tablas
Muchos documentos PDF contienen tablas. No es de extrañar que las tablas mejoren la claridad y la organización de los datos. Permítanme mostrarles cómo crear una tabla en PDF usando Layout API.
El código de muestra para este paso está en la clase HelloWorld7
de la aplicación de
ejemplo. A continuación se muestran las partes que cambiaron desde el paso
anterior.
static void BuildDocument(Document doc)
{
....
doc.Pages(pages => {
BuildPages(pages);
pages.Content().Column(c =>
{
BuildTextContent(c.Item());
BuildImageContent(c.Item(), image);
BuildListContent(c.Item());
BuildTableContent(c.Item());
});
});
}
static void BuildTableContent(LayoutContainer content)
{
var color = new PdfGrayColor(75);
content.PaddingTop(20).Table(t =>
{
t.Columns(c =>
{
c.RelativeColumn(4);
c.RelativeColumn(1);
c.RelativeColumn(4);
});
t.Header(h =>
{
h.Cell().Background(color).Text("Month in 2024");
h.Cell().Background(color).Text("Days");
h.Cell().Background(color).Text("First Day");
});
for (int i = 0; i < 12; i++)
{
var stats = GetMonthStats(2024, i);
t.Cell().Text(stats.Item1);
t.Cell().Text(stats.Item2);
t.Cell().Text(stats.Item3);
}
});
}
static (string, string, string) GetMonthStats(int year, int monthIndex)
{
return (
DateTimeFormatInfo.InvariantInfo.MonthNames[monthIndex],
DateTime.DaysInMonth(year, monthIndex + 1).ToString(),
new DateTime(year, monthIndex + 1, 1).DayOfWeek.ToString()
);
}
La llamada a BuildTableContent
es el único cambio en BuildDocument
.
En BuildTableContent
, creo una tabla simple. La tabla muestra información trivial sobre los meses
del año 2024. Para empezar, defino tres columnas con anchos relativos. Las columnas de la izquierda
y de la derecha serán 4 veces más anchas que la columna del medio.
El código también define el encabezado de la tabla. Lo hace agregando celdas de encabezado y especificando texto y color de fondo para cada celda. Cuando la tabla no cabe en una página, el encabezado se repite en cada página ocupada por la tabla. Puede ver esto en el documento PDF con tabla resultante. En el documento, la tabla comienza en la segunda página y continúa en la tercera.
Estoy usando el bucle simple para formar filas. El código del bucle comienza recuperando la información de cada mes. Luego agrega tres celdas que forman una fila de información.
El artículo Contenedor Table explica todas las características del contenedor Table
con mayor
detalle.
Código de muestra
Arriba, presenté algunas de las características más populares de la generación de PDF en C#. Te sugiero que sigas descubriendo la API leyendo el siguiente artículo. Pruebe también el código de muestra del repositorio Docotic.Pdf.Samples en GitHub. El código de muestra para Layout API se encuentra en carpeta de diseño del repositorio.
Puede utilizar el código de muestra como campo de juego de código. De esta manera podrás probar algunas ideas sin tener que empezar desde cero cada vez.
El mismo código de muestra se encuentra en la carpeta Samples
del paquete ZIP. Hay dos archivos
de solución. SamplesCSharp
es para proyectos de muestra que utilizan el lenguaje C#. Y
SamplesVB.NET
es para las versiones de VB.NET.