Esta página puede contener texto traducido automáticamente.

Generador de PDF .NET

Con la ayuda de Docotic.Pdf, puede generar documentos PDF componiéndolos a partir de elementos estructurales como páginas, contenedores, fragmentos de texto, imágenes, vínculos, encabezados, pies de página, tablas, listas y más. Estos elementos están disponibles a través de la API de Layout de alto nivel, proporcionada por el complemento Layout gratuito para Docotic.Pdf. La API también admite componentes personalizados reutilizables.

Ilustración de cómo Docotic.Pdf genera PDF: usted organiza elementos como imágenes, tablas y texto, y la biblioteca produce un PDF a partir de ese diseño

La API de Layout le permite definir documentos por completo en código C# o VB.NET usando un enfoque fluido. Basado en esta descripción, el generador de PDF proporcionado por el complemento puede producir documentos con diseños arbitrariamente complejos, que van desde páginas simples hasta informes PDF altamente estructurados.

Conceptos básicos de generación de PDF

Para generar documentos PDF mediante la API de Layout, necesita el complemento Layout gratuito. También se requiere una clave de licencia para usar la biblioteca principal y los complementos. Puede usar una clave de prueba gratuita o una clave comprada.

Instalar el complemento

La forma recomendada es instalar el complemento desde NuGet.

Install-Package BitMiracle.Docotic.Pdf.Layout

El administrador de paquetes manejará automáticamente las dependencias.

Si prefiere instalar el complemento manualmente, comience descargando el archivo ZIP con los binarios de Docotic.Pdf. Descomprima el archivo y agregue referencias a las siguientes DLL:

  • BitMiracle.Docotic.Pdf.dll
  • BitMiracle.Docotic.Pdf.Layout.dll de la subcarpeta Layout add-on.

Obtener una clave de licencia

Para probar la biblioteca, solicite una clave de licencia gratuita con límite de tiempo completando el formulario en la página de descarga de Docotic.Pdf. Si ya ha comprado una licencia, use el código que se le proporcionó después de la compra.

El complemento Layout es gratuito y no requiere una licencia adicional. Puede usar la API de Layout con la licencia de Docotic.Pdf que ya tiene.

¡Hola, mundo! con la Layout API

Aquí hay un ejemplo de código que usa la API para generar un PDF con la clásica frase "¡Hola, mundo!":

BitMiracle.Docotic.LicenseManager.AddLicenseData("PUT-LICENSE-HERE");

PdfDocumentBuilder.Create().Generate("hello.pdf", doc => doc.Pages(pages =>
{
    pages.Content().Text("Hello, world!");
}));

Este código produce un PDF de una sola página con el texto en la esquina superior izquierda.

Comprender el ejemplo de código

El ejemplo comienza agregando una clave de licencia. Sin una licencia, la biblioteca Docotic.Pdf no generará nada. El código de generación del PDF comienza en la línea siguiente.

El código crea una instancia del generador de documentos llamando al método estático PdfDocumentBuilder.Create(). La llamada al método Generate inicia el proceso de generación del PDF. Este método acepta dos parámetros: el nombre del archivo que se va a generar y un delegado de tipo Action<Document>. El complemento genera hello.pdf como resultado de la llamada a Generate.

Para saber qué diseño debe tener el PDF, el generador de documentos llama al delegado con una instancia de Document. El código del delegado compone el contenido del documento. En este ejemplo, el delegado usa el método Pages para proporcionar al generador otro delegado que define el diseño de las páginas del documento.

El generador llama al delegado proporcionado al método Pages con una instancia de PageLayout. Esta instancia representa una o más páginas del documento. El número exacto de páginas depende del contenido que se agregue a ellas.

El delegado de página llama al método Content para acceder al contenedor de diseño del contenido principal de la página o páginas. Una llamada encadenada al método Text del contenedor agrega el fragmento de texto de ejemplo a la página. Consulte la guía sobre contenedores de diseño para una explicación detallada de cómo funcionan.

El generador de documentos divide automáticamente el contenido entre páginas, creando exactamente tantas páginas como sean necesarias para contener todos los datos agregados al contenedor de diseño de contenido principal. En este ejemplo, una sola página es suficiente, por lo que la salida contiene exactamente una página.

Tareas comunes más allá del ejemplo básico

El código de ejemplo primero crea una instancia de PdfDocumentBuilder y luego llama al método Generate para producir un PDF. Puede configurar el generador antes de que comience a generar el PDF.

Por ejemplo, puede producir un PDF cifrado proporcionando un controlador de cifrado al generador. También puede especificar metadatos para que el generador los incluya en el documento generado. Para obtener más detalles sobre cómo personalizar el generador, consulte el artículo independiente.

El código de ejemplo usa solo el contenedor de diseño del espacio de contenido principal, pero también hay otros espacios de contenido disponibles. Esta es la lista completa de métodos de PageLayout para acceder a los espacios de contenido:

  • Background() - devuelve la capa de fondo, que queda cubierta por otro contenido.
  • Header() - devuelve el encabezado común para todas las páginas.
  • Content() - devuelve el espacio de contenido principal de la página.
  • Footer() - devuelve el pie de página común para todas las páginas.
  • Foreground() - devuelve la capa de primer plano, que aparece encima del resto del contenido.

Solo el contenido del espacio de contenido principal afecta al número de páginas del PDF generado. El generador de documentos repite todos los espacios distintos del proporcionado por Content() en cada página. Para más información sobre los espacios de contenido, consulte el artículo sobre diseño de página.

Muchos documentos usan diseños diferentes en páginas distintas. Por ejemplo, la primera página puede tener un diseño tipo portada, mientras que las páginas posteriores usan un diseño más sencillo. Algunos documentos incluyen páginas especiales para tablas o aplican fondos diferentes según la sección. Para generar esos documentos con Docotic.Pdf y el complemento Layout, llame al método Document.Pages varias veces. Puede encontrar un ejemplo funcional en nuestro repositorio de ejemplos.

Organizar el código

Para código breve, como en el ejemplo, está bien encadenar llamadas y usar lambdas anidadas. Cuando construye algo más grande, puede resultar más conveniente dividir el código en métodos separados. Esto hace que el código sea más fácil de leer y mantener.

Así es como se ve el ejemplo de ¡Hola, mundo! cuando su código se divide en métodos.

public void GeneratePdf()
{
    BitMiracle.Docotic.LicenseManager.AddLicenseData("PUT-LICENSE-HERE");

    PdfDocumentBuilder.Create().Generate("hello.pdf", BuildDocument);
}

private void BuildDocument(Document doc)
{
    doc.Pages(BuildPages);
}

private void BuildPages(PageLayout pages)
{
    pages.Content().Text("Hello, world!");
}

Por qué generar PDF con la Docotic.Pdf Layout API

La API de Layout es una forma moderna y fácil para desarrolladores de generar PDF a partir de bloques de construcción componibles sin necesidad de comprender los detalles internos del formato PDF. Diseña los PDF con alto rendimiento y comportamiento determinista y predecible. Puede usar la API en escenarios de generación de documentos de gran volumen.

La API está disponible cuando se usa Docotic.Pdf junto con el complemento Layout gratuito. Tanto Docotic.Pdf como el complemento Layout son DLL de código administrado al 100 %, sin bloques de código inseguros. La API de Layout se implementa sin dependencias externas de terceros, como un navegador o binarios de Skia, lo que da como resultado una solución ligera, con poca sobrecarga, fácil de implementar y mantener.

Resumen de la API

La API de Layout es una API fluida y agradable de usar. Usted describe el diseño de su documento por completo en código usando elementos de diseño flexibles, y el generador fluye su contenido, lo paginiza automáticamente y representa el resultado como un PDF.

El complemento Layout usa un sistema de diseño declarativo basado en flujo. Sus elementos de diseño incluyen listas, columnas, filas, tablas, imágenes, fragmentos de texto, encabezados y pies de página, contenedores y más. En lugar de colocar manualmente los elementos en coordenadas exactas, usted describe cómo deben comportarse. Luego, el generador de documentos calcula el diseño final y crea el PDF.

El sistema de diseño basado en flujo garantiza que el diseño se adapte al tamaño de la página y al contenido. Gracias a este sistema, el complemento destaca en diseños complejos, estructurados y basados en reglas. Puede anidar distintos tipos de contenedores y construir estructuras sofisticadas sin sacrificar legibilidad.

Al trabajar con la API de Layout, puede encadenar la mayoría de las llamadas. Esto da lugar a un código más compacto y expresivo que con las API tradicionales. El orden de las llamadas en una cadena es importante. Todo está fuertemente tipado, lo que proporciona seguridad en tiempo de compilación y hace que el código sea fácil de refactorizar. También puede realizar pruebas unitarias del código que usa la API de Layout.

Para hacer que la implementación de su diseño sea aún más concisa, puede ampliar la API con sus propios métodos y construir alrededor de ella un DSL limpio y expresivo.

Para obtener más información sobre posicionamiento y creación de DSL, consulte el artículo que explica cómo controlar el tamaño, la posición, la alineación y el comportamiento de representación de los contenedores.

Versiones de .NET y compatibilidad de plataforma

Puede usar la API de Layout en proyectos dirigidos a .NET Standard 2.1 y marcos más recientes. En otras palabras, el complemento Layout es compatible con .NET 5 hasta .NET 10. Además, se admite .NET Core 3.0+.

Puede generar PDF con la API de Layout en ASP.NET Core, aplicaciones MAUI, Unity, Xamarin y aplicaciones de consola. Docotic.Pdf con el complemento Layout puede producir PDF en Windows, macOS y Linux.

Plataformas en la nube e imágenes de Docker

Docotic.Pdf con el complemento Layout puede ejecutarse en entornos en la nube de Azure y AWS, incluidas configuraciones sin servidor. La biblioteca y el complemento admiten por completo cambios dinámicos de hardware, escalado automático y otras características de tiempo de ejecución nativas de la nube.

En la mayoría de los escenarios en la nube, se requiere una licencia no vinculada. Las preguntas frecuentes sobre licencias explican cómo elegir la licencia adecuada para aplicaciones en la nube.

La API de Layout funciona directamente en contenedores Docker. No necesita ninguna configuración especial para generar PDF cuando ejecuta la biblioteca y el complemento Layout dentro de un contenedor.

Agregar texto a archivos PDF

El texto es una parte fundamental de cualquier documento PDF. Puede usar métodos Text de la clase LayoutContainer para agregar texto a un espacio de contenido.

Ilustración de páginas de documentos rodeadas de ejemplos de estilos de texto como Title, Caption, Plain, Hyperlink, Strong y Footnote

Fragmentos de texto

En el ejemplo de ¡Hola, mundo!, usé la sobrecarga LayoutContainer.Text(string) para agregar texto al contenido principal de la página. Ahora veamos otra sobrecarga del método Text.

public static void GenerateTextPdf()
{
    PdfDocumentBuilder.Create().Generate("text-spans.pdf", doc => doc.Pages(pages =>
    {
        pages.Content().Text(AddTextSpans);
    }));
}

private static void AddTextSpans(TextContainer text)
{
    text.Line("About VB.NET")
        .Style(t => t.Strong);

    text.Span("VB.NET is a multi-paradigm, object-oriented language ");
    text.Span("that runs on .NET, Mono, and the ");
    text.Hyperlink(
        ".NET Framework",
        new Uri("https://dotnet.microsoft.com/download/dotnet-framework"));
    text.Line(".");

    text.Span("Released by Microsoft in 2002, ");
    text.Line("it continues the lineage of the original Visual Basic language.");
}

Este código usa los métodos Span y Line de la clase TextContainer para agregar texto a la línea actual. El método Line además completa la línea actual. El código de ejemplo también usa el método Hyperlink para adjuntar un vínculo a un recurso externo a un fragmento de texto específico.

Observe cómo el código de ejemplo aplica formato en negrita a la primera línea usando el método Style. Exploremos el concepto de estilos de texto con más detalle.

Estilos de texto

Los estilos de texto le permiten personalizar la apariencia del texto. La clase TextStyle proporciona métodos para cambiar el tamaño de fuente, el espaciado entre letras, los colores y otras propiedades del texto. Los objetos TextStyle son inmutables, por lo que cada llamada a un método produce una nueva instancia de estilo. Puede aplicar estilos de texto en diferentes niveles de diseño.

PdfDocumentBuilder.Create().Generate("text-styles.pdf", doc =>
{
    doc.Pages(pages =>
    {
        pages.TextStyle(TextStyle.Parent.FontSize(30));

        pages.Content()
            .TextStyle(TextStyle.Parent.FontColor(new PdfRgbColor(0, 0, 255)))
            .Text(text =>
            {
                text.Span("Hello,");

                text.Span("World!")
                    .Style(TextStyle.Parent.Underline());
            });
    });
});

La propiedad TextStyle.Parent devuelve un estilo especial en el que todas las propiedades de texto están indefinidas. En el ejemplo anterior, el código dibuja “Hello, World!” en azul, con la segunda palabra subrayada, usando un tamaño de fuente de 30 puntos.

Esto ocurre porque el código:

  • establece el tamaño de fuente en 30 puntos a nivel de página,
  • luego establece el color del texto en azul para el espacio de contenido principal,
  • luego aplica el estilo de subrayado al último fragmento de texto.

Cada estilo posterior hereda los anteriores mediante la propiedad TextStyle.Parent.

Usando los métodos de la clase TextStyle, puede, entre otras cosas, cambiar la dirección del texto de derecha a izquierda. Vea otro ejemplo de uso de herencia de estilos de texto en nuestro repositorio de ejemplos.

Tipografía

La clase TextStyle admite la personalización de todas las propiedades del texto excepto la fuente asociada. Para cambiar la fuente predeterminada, use los métodos Document.TextStyleWithFont para crear un estilo de texto basado en una fuente específica. Puede usar una fuente instalada en el sistema operativo o cargar una desde un archivo o un flujo.

Después de crear un estilo basado en una fuente, puede aplicar propiedades opcionales adicionales y luego usar el estilo resultante en un fragmento de texto. Este ejemplo en C# muestra cómo usar una fuente del sistema.

PdfDocumentBuilder.Create().Generate("text-style-with-font.pdf", doc =>
{
    var font = SystemFont.Family("Calibri");
    var style = doc.TextStyleWithFont(font).FontSize(30);

    doc.Pages(pages =>
    {
        pages.Content().Text(text =>
        {
            text.Span("Hello,");

            text.Span("World!")
                .Style(style);
        });
    });
});

El método TextStyleWithFont incluye un parámetro opcional que especifica cómo debe incrustarse la fuente en el documento generado. De forma predeterminada, la biblioteca:

  • incrusta los glifos usados para fuentes TrueType/OpenType,
  • incrusta todos los glifos para fuentes Type1 y CFF,
  • no incrusta glifos para fuentes PDF integradas (fuentes Base14).

Gracias a estos valores predeterminados, los documentos que usan fuentes TrueType y OpenType pueden seguir siendo pequeños incluso cuando se utilizan fuentes grandes. También puede especificar un cargador de fuentes personalizado, fuentes de reserva y un controlador para glifos faltantes. Consulte el código de ejemplo en nuestro repositorio de ejemplos para obtener detalles sobre la administración de fuentes en documentos PDF.

La API de Layout proporciona una colección de estilos predefinidos, a los que puede acceder y modificar mediante la clase Typography.

PdfDocumentBuilder.Create().Generate("typography.pdf", doc =>
{
    doc.Typography(t =>
    {
        var fontsPath = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
        var arialFont = new FileInfo(Path.Combine(fontsPath, "arial.ttf"));

        t.Document = doc.TextStyleWithFont(arialFont);
        t.Header = t.Parent.FontSize(20).FontColor(new PdfGrayColor(20));
        t.Footer = t.Footnote;
    });

    doc.Pages(pages =>
    {
        pages.Header().AlignCenter().Text("Header");

        pages.Content().Text(t =>
        {
            t.Line("Title").Style(t => t.Title);
            t.Line("Heading 1").Style(t => t.Heading1);
            t.Line("Regular");
        });

        pages.Footer()
            .Height(20)
            .AlignCenter()
            .Text(t => t.CurrentPageNumber());
    });
});

Recomiendo sobrescribir los estilos predefinidos configurando la tipografía para todo el documento, aunque esto no es obligatorio y todavía puede aplicar estilos de texto a nivel de fragmento de texto.

Con la clase Typography, no necesita almacenar referencias a estilos de texto en variables. En su lugar, registra los estilos necesarios usando los métodos Document.Typography y luego accede a ellos mediante las propiedades del objeto Typography. Consulte el ejemplo de Typography para ver cómo usar estilos de texto predefinidos y personalizados al generar documentos PDF.

Muchos documentos PDF reales, como informes o facturas, incluyen encabezados y pies de página. Esta sección muestra cómo agregar ambos a un PDF.

public static void GeneratePdfWithHeaderAndFooter()
{
    PdfDocumentBuilder.Create()
        .Generate("header-footer.pdf", doc => doc.Pages(pages =>
    {
        pages.Size(PdfPaperSize.A6).Margin(10);

        BuildPagesHeader(pages.Header());
        BuildPagesFooter(pages.Footer());

        pages.Content().Text("Hello, world!");
    }));
}

public 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}");
        });
}

public static void BuildPagesFooter(LayoutContainer footer)
{
    footer.AlignRight().Text(text =>
    {
        text.Style(t => t.Parent.FontColor(new PdfRgbColor(255, 0, 0)));

        text.CurrentPageNumber();
        text.Span(" / ");
        text.PageCount();
    });
}

El método BuildPagesHeader establece un tamaño de fuente más pequeño para el texto del encabezado. Usa dos líneas para el contenido del encabezado: una con el nombre del usuario actual y otra con la fecha actual. El texto está alineado a la derecha.

Observe que el código no especifica ningún tamaño explícito para el encabezado. Ocupa todo el ancho de página menos los márgenes izquierdo y derecho, y su altura depende de la altura de las líneas de texto.

El método BuildPagesFooter demuestra cómo colocar el número de página actual en el pie de página del PDF. La biblioteca calcula automáticamente el número de página actual y el número total de páginas. Puede acceder a estos valores mediante los métodos CurrentPageNumber y PageCount de un objeto TextContainer.

La API de Layout también proporciona una forma de formatear números de página. Por ejemplo, puede dibujar números de página hexadecimales así:

text.CurrentPageNumber().Format(p => "0x" + p?.ToString("x2"));

Nuestro repositorio de ejemplos contiene otro ejemplo de agregar un encabezado y pie de página a un PDF. Ese ejemplo formatea los números de página como números romanos.

Insertar imágenes

Como dice el refrán, una imagen vale más que mil palabras. En cotizaciones o recibos, a menudo incluirá el logotipo de su empresa u otra imagen importante. Para este ejemplo, usaré una sencilla y vistosa.

Para usar una imagen, primero debe agregarla al documento. La biblioteca puede cargar imágenes desde un archivo o un flujo. Solo se admiten formatos raster: PNG, JPEG, JPEG 2000, BMP, GIF y TIFF.

Una vez que tenga un objeto Image, puede establecerlo como contenido de uno o más contenedores de diseño llamando al método Image del contenedor. Puede escalar, rotar, agregar relleno y disponer la imagen como cualquier otro contenido.

PdfDocumentBuilder.Create().Generate("image-with-text.pdf", doc =>
{
    var imageFile = new FileInfo("red-flowers-at-butterfly-world.jpg");
    var image = doc.Image(imageFile);

    doc.Pages(pages =>
    {
        pages.Size(PdfPaperSize.A6);
        pages.Content().Column(c =>
        {
            c.Spacing(20);

            c.Item()
                .AlignCenter()
                .Text("Hello, world!")
                .FontSize(20);

            c.Item()
                .AlignCenter()
                .MaxWidth(200)
                .Image(image);
        });
    });
});

El código de ejemplo usa tanto texto como una imagen en el espacio de contenido principal. Sin embargo, un contenedor de diseño solo puede contener texto o solo una imagen. Para incluir ambos en el espacio de contenido principal de la página, necesita un contenedor compuesto.

Uso un contenedor Column para colocar el texto y la imagen verticalmente, uno tras otro. El método Item del contenedor de columnas proporciona un subcontenedor. Una llamada a Item crea un contenedor para el texto, y otra crea un contenedor para la imagen. El contenedor compuesto con todos sus subcontenedores se convierte en el contenido principal.

Para ejecutar el código de ejemplo, descargue la imagen de flores de nuestro repositorio de ejemplos y colóquela en el directorio de trabajo de su aplicación.

Imágenes en línea

Si solo dispone de una URL de imagen en lugar de un archivo, descargue la imagen en un flujo de memoria y cree un Image a partir de ese flujo. El siguiente ejemplo muestra cómo usar imágenes en línea con la API de Layout.

public static async Task AddImageWithTextFromUrl()
{
    using var http = new HttpClient();
    using var stream = await http.GetStreamAsync("url/to/image");

    var memoryStream = new MemoryStream();
    await stream.CopyToAsync(memoryStream);
    memoryStream.Position = 0;

    PdfDocumentBuilder.Create().Generate("online-image-with-text.pdf", doc =>
    {
        var image = doc.Image(memoryStream);

        doc.Pages(pages =>
        {
            pages.Size(PdfPaperSize.A6);
            pages.Content().Column(c =>
            {
                c.Spacing(20);

                c.Item()
                    .AlignCenter()
                    .Text("Hello, world!")
                    .FontSize(20);

                c.Item()
                    .AlignCenter()
                    .MaxWidth(200)
                    .Image(image);
            });
        });
    });
}

Como el método realiza trabajo asincrónico (descargar una imagen desde una URL), se declara como async Task en lugar de void. Quienes lo llamen deben hacer await para garantizar que la generación del PDF se complete correctamente. En su propio código, un método similar también puede devolver un valor; en ese caso, se declararía como async Task<TResult>.

Crear listas

¿Qué es una lista? Puede pensar en ella como un grupo de elementos numerados escritos uno debajo del otro. La API de Layout no proporciona un tipo de contenedor especial para listas, pero es fácil implementar uno usando otros contenedores compuestos.

var dayNames = DateTimeFormatInfo.InvariantInfo.DayNames;
var dayNamesSpain = DateTimeFormatInfo.GetInstance(new CultureInfo("es-ES")).DayNames;

PdfDocumentBuilder.Create().Generate("list.pdf", doc => doc.Pages(pages =>
{
    pages.Size(PdfPaperSize.A6);
    pages.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 código de ejemplo crea la lista como una columna de filas. Cada fila contiene dos elementos: el primero (a la izquierda) contiene el número del elemento, y el segundo (a la derecha) contiene el texto del elemento. El código establece explícitamente el espaciado entre los elementos de cada fila.

Para disponer los elementos, el contenedor Row debe tener especificado explícitamente el tamaño de cada elemento o calcularlo. En este ejemplo, se usan los métodos AutoItem y RelativeItem. Como resultado, el contenedor de filas calcula el ancho necesario para el primer elemento y luego usa el ancho disponible restante para el segundo elemento.

Usando este enfoque y ajustando la apariencia de las filas según sea necesario, puede crear una lista que se adapte mejor al diseño y estilo de su documento.

Crear tablas

Muchos documentos PDF contienen tablas, lo cual no sorprende porque las tablas mejoran la claridad y la organización de los datos. Esta sección muestra cómo crear una tabla en un PDF usando la API de Layout.

public static void AddTable()
{
    PdfDocumentBuilder.Create().Generate("table.pdf", doc => doc.Pages(pages =>
    {
        pages.Size(PdfPaperSize.A6);

        var color = new PdfGrayColor(75);
        pages.Content().Padding(20).Table(t =>
        {
            t.Columns(c =>
            {
                c.RelativeColumn(4);
                c.RelativeColumn(1);
                c.RelativeColumn(4);
            });

            t.Header(h =>
            {
                h.Cell().Background(color).Text("Month");
                h.Cell().Background(color).Text("Days");
                h.Cell().Background(color).Text("First Day");
            });

            var year = DateTime.Now.Year;
            for (int yearDiff = 0; yearDiff < 4; yearDiff++)
            {
                for (int i = 11; i >= 0; i--)
                {
                    var stats = GetMonthStats(year - yearDiff, i);

                    t.Cell().Text(stats.Item1);
                    t.Cell().Text(stats.Item2);
                    t.Cell().Text(stats.Item3);
                }
            }
        });
    }));
}

private static (string, string, string) GetMonthStats(int year, int monthIndex)
{
    return (
        $"{DateTimeFormatInfo.InvariantInfo.MonthNames[monthIndex]} {year}",
        DateTime.DaysInMonth(year, monthIndex + 1).ToString(),
        new DateTime(year, monthIndex + 1, 1).DayOfWeek.ToString()
    );
}

El código de ejemplo crea una tabla sencilla que muestra información básica sobre los meses del año actual y de los tres años anteriores. El código define tres columnas con anchos relativos. Las columnas más a la izquierda y más a la derecha son cuatro veces más anchas que la columna central.

El código también define el encabezado de la tabla agregando celdas de encabezado y especificando el texto y el color de fondo para cada celda. Cuando una tabla no cabe en una sola página, el encabezado se repite en todas las páginas que ocupa la tabla. Puede ver este comportamiento en el PDF generado por el código de ejemplo.

Se usan dos bucles simples para construir las filas. El bucle externo recorre los años y el interno recorre los meses en orden inverso. El bucle interno obtiene información sobre cada mes y luego agrega tres celdas para formar una fila.

Para más detalles, puede leer el artículo que explica en profundidad las características del contenedor Table.

Los documentos PDF admiten vínculos internos que permiten a los lectores saltar a otra ubicación dentro del mismo archivo. En un visor de PDF, estos vínculos aparecen como elementos de texto o imagen clicables. Funcionan como hipervínculos, pero en lugar de apuntar a un sitio web externo, navegan dentro del propio documento.

Ilustración de vínculos internos en un PDF, que muestra secciones del documento conectadas con iconos de vínculo y destino

Muchos documentos PDF usan vínculos internos para marcadores o una tabla de contenido, ayudando a los lectores a moverse rápidamente entre secciones. Así es como puede agregar un vínculo a una sección del documento usando la API de Layout:

PdfDocumentBuilder.Create().Generate("link.pdf", doc =>
{
    doc.Pages(pages =>
    {
        pages.Content().Column(c =>
        {
            const string SectionName = "Chapter 1";
            c.Item().SectionLink(SectionName).Text("Link");

            c.Item().PageBreak();

            c.Item().Section(SectionName).Text("Target");
        });
    });
});

El código de ejemplo convierte el texto de la primera página en un vínculo a la sección con el nombre especificado. Lo hace llamando al método SectionLink en el contenedor de diseño que contiene el texto. Es posible que la sección exista o no en este momento. El texto se vuelve clicable en un visor de PDF.

El código luego marca el texto de la segunda página como el inicio de la sección con el mismo nombre. Su apariencia y comportamiento no cambian, pero se convierte en el destino del vínculo de la primera página. Esto se hace llamando al método Section en el contenedor de diseño correspondiente.

En este ejemplo, tanto el vínculo como su destino son fragmentos de texto, pero puede crear secciones y vínculos en cualquier contenedor de diseño. Puede ser un contenedor con una imagen, un contenedor de tablas o un contenedor que construya usted mismo.

Vea un ejemplo de cómo crear una tabla de contenido de PDF en nuestro repositorio de ejemplos.

Diseñar maquetaciones PDF complejas

La API de Layout proporciona una variedad de contenedores de diseño que puede combinar para producir documentos PDF arbitrariamente complejos. También puede ampliar la API con sus propios componentes personalizados.

Los ejemplos de esta página son intencionalmente sencillos, diseñados para crear documentos directos para que pueda concentrarse en las ideas centrales sin perderse en los detalles. Si le gustaría ver cómo se pueden combinar diferentes contenedores para generar un PDF más complejo, eche un vistazo al ejemplo correspondiente en nuestro repositorio de ejemplos en GitHub.

Además de usar contenedores integrados, puede definir y usar componentes de diseño personalizados. Estos componentes son especialmente útiles cuando desea que una sola clase encapsule tanto los datos como la lógica de diseño. Mantener todo en un solo lugar hace que el componente sea más fácil de entender, modificar y reutilizar, a la vez que le da una forma flexible de manejar diseños complejos.

Para crear un componente de diseño personalizado, implemente la interfaz ILayoutComponent en su clase. Al generar un PDF, la biblioteca llama al método Compose de la interfaz y proporciona un objeto LayoutContext. Su código puede usar este objeto para crear elementos de diseño y acceder a información sobre el documento que se está generando.

Para agregar un componente de diseño personalizado a su diseño, llame al método Component de la clase LayoutContainer. En términos de tamaño y posición, un componente personalizado se comporta igual que el texto o las imágenes.

Para ver un ejemplo de implementación de un componente personalizado con la interfaz ILayoutComponent, consulte el ejemplo Componentes de diseño.

Otras formas de crear PDF

Docotic.Pdf ofrece múltiples formas de crear PDF, cada una adecuada para distintos escenarios. Esta sección explica cuándo confiar en la API de Layout y cuándo otros enfoques pueden servirle mejor.

Cuándo preferir la API de Layout

La API de Layout de Docotic.Pdf es una forma potente de generar PDF a partir de diseños estructurados. Le permite construir documentos componiendo texto, imágenes, contenedores y tablas en estructuras anidadas arbitrariamente complejas. El proceso de generación es rápido, usa una cantidad razonable de memoria y se comporta de forma predecible.

Docotic.Pdf y el complemento Layout forman un conjunto ligero y totalmente autónomo. La API no requiere bibliotecas externas ni navegadores para generar PDF. Esto la convierte en una opción sólida para microservicios .NET, aplicaciones en la nube, especialmente las sin servidor, y otros entornos donde importa el tamaño de la huella.

Como el diseño del documento se define en código, puede realizar pruebas unitarias de cualquier parte. La lógica de diseño puede reutilizarse como cualquier otro código, y puede encapsular tanto los datos como el comportamiento de diseño en componentes personalizados.

Alternativas a la API de Layout

Un artículo dedicado ofrece una comparación detallada de todas las formas de crear PDF con Docotic.Pdf. A continuación se muestran algunas de las alternativas más utilizadas.

  • Conversión de HTML a PDF
    Reutiliza plantillas HTML/CSS existentes. Elija el enfoque de HTML a PDF cuando su equipo ya produzca documentos en HTML/CSS y necesite versiones PDF de esos documentos.

  • Generación de PDF de bajo nivel
    Proporciona el máximo control disponible en la biblioteca sobre la estructura y el contenido del PDF. Elija esto cuando necesite posicionamiento a nivel de píxel o gráficos vectoriales complejos. Este enfoque se recomienda para escenarios críticos de rendimiento o cuando se requiere la huella más pequeña posible.

  • Generación de PDF basada en plantillas
    Ofrece una forma rápida y predecible de rellenar documentos sin diseñar ni disponer sus elementos. Elija esto cuando tenga una estructura de PDF predefinida, como plantillas aprobadas o controladas por cumplimiento, y solo necesite cambiar campos de texto, reemplazar marcadores de posición, adjuntar documentos relacionados y realizar tareas similares.

  • Fusión y composición de PDF
    Le permite crear un PDF a partir de piezas existentes en lugar de construirlo desde cero. Elija esto cuando tenga imágenes, páginas escaneadas u otros PDF que deban combinarse en un solo archivo.

Comparación con otras soluciones de generación de PDF

Esta sección contiene dos tablas de comparación: una con conclusiones clave y otra con información detallada y estructurada sobre cómo Docotic.Pdf con el complemento Layout se compara con otras soluciones populares para generar PDF.

Conclusiones clave de la comparación

Hay opciones sólidas para generar PDF, incluidas algunas gratuitas. Sin embargo, capacidades como firmar, cifrar o combinar documentos varían, lo que puede limitar qué herramientas se ajustan realmente a sus necesidades.

Solución Cuándo usar Ideal para
Docotic.Pdf con el complemento Layout Cuando desea un motor de diseño de alta calidad y alto rendimiento capaz de producir PDF optimizados, con soporte avanzado para firmas, cifrado y edición de PDF en todas las plataformas Generación de alta calidad de facturas, informes, estados de cuenta y documentos similares, con una excelente experiencia de desarrollo. Ideal cuando necesita procesamiento de PDF de nivel empresarial y soporte profesional
PDFsharp + MigraDoc Cuando desea una biblioteca gratuita con licencia MIT para generación básica de PDF y no requiere firmas digitales ni algoritmos de cifrado modernos Creación sencilla de documentos en proyectos de código abierto o con presupuesto limitado
QuestPDF Cuando desea un motor de diseño moderno dedicado únicamente a la generación de PDF y no necesita edición, firmas ni cifrado Generación de PDF de alta calidad con licencia MIT o comercial de bajo coste, siempre que todas las funciones distintas de la generación se gestionen en otro lugar
iText Cuando necesita un conjunto de herramientas de PDF maduro y rico en funciones tanto para generar como para procesar PDF, y está preparado para publicar su solución como código abierto bajo la licencia AGPL/GPLv3 o comprar una costosa licencia comercial Equipos ya familiarizados con la API de iText y, por tanto, no afectados por su pronunciada curva de aprendizaje

Comparación detallada

Revise la tabla para comprender el contexto más amplio y sacar sus propias conclusiones.

  Docotic.Pdf con Layout PDFsharp + MigraDoc QuestPDF iText
Capacidades de PDF Biblioteca de PDF con todas las funciones Generación de PDF y edición limitada Solo generación de PDF Funcionalidad de PDF amplia
Modelo de representación Motor de diseño moderno, declarativo y de modo retenido Motor de diseño basado en cajas Motor de diseño moderno, declarativo y de modo retenido Motor de diseño basado en cajas + árbol de representación
Tipo de API API fluida API imperativa API fluida API imperativa
Experiencia de desarrollo Excelente. La API es limpia, moderna e intuitiva Buena. El diseño de la API es convencional Excelente. La API es limpia, moderna e intuitiva Satisfactoria. La API es verbosa y demasiado compleja
Subconjunto de fuentes Compatible; solo se incrustan los glifos usados de forma predeterminada No compatible; puede dar lugar a PDF innecesariamente grandes Compatible; solo se incrustan los glifos usados de forma predeterminada Compatible; solo se incrustan los glifos usados de forma predeterminada
Dirección del contenido de derecha a izquierda (RTL) Compatible No compatible Compatible Compatible
Firmas digitales Compatible, incluidas LTV y firmas externas No compatible No compatible Compatible, incluidas LTV y firmas externas
Cifrado / permisos Totalmente compatible Solo cifrado RC4, sin compatibilidad con AES ni certificados No compatible Totalmente compatible
Dependencias externas Ninguna Ninguna Componentes basados en SkiaSharp / Skia Ninguna
Soporte Soporte profesional para prospectos y clientes; soporte prioritario con licencias de primer nivel Soporte de la comunidad; el soporte profesional puede adquirirse por separado Soporte de la comunidad a través de GitHub Soporte de la comunidad para la versión AGPL; soporte profesional para titulares de licencias comerciales
Licencia Comercial, con licencias gratuitas para casos de uso elegibles MIT MIT para particulares y pequeñas empresas; se requiere licencia comercial para empresas más grandes AGPL para uso de código abierto, costosa licencia comercial para proyectos propietarios
Licenciamiento para desarrolladores Desarrolladores ilimitados con todas las licencias Desarrolladores ilimitados con todas las licencias Desarrolladores ilimitados con MIT; 10 desarrolladores con Professional; desarrolladores ilimitados con Enterprise Desarrolladores ilimitados con la versión AGPL; licenciamiento por desarrollador con licencia comercial

Conclusión

Docotic.Pdf con el complemento Layout ofrece una forma moderna, de alto rendimiento y alta calidad de generar PDF en C# y VB.NET. La biblioteca produce informes, estados de cuenta, facturas y documentos similares. Su API fluida y bien diseñada ofrece una excelente experiencia de desarrollo. Puede confiar en el soporte profesional que Bit Miracle proporciona para Docotic.Pdf y sus complementos.

A diferencia de algunas otras soluciones de generación de PDF, Docotic.Pdf es una API de PDF con todas las funciones. La biblioteca puede firmar PDFs generados con firmas digitales, incluidas firmas con LTV. Docotic.Pdf puede usar certificados almacenados en hardware seguro como tokens USB y tarjetas inteligentes. También se admiten módulos de seguridad de hardware (HSM) basados en la nube, como Microsoft Azure Key Vault y AWS Key Management Service (KMS).

Con Docotic.Pdf, puede adjuntar documentos de apoyo como hojas de cálculo o notas de voz a los PDF generados. Para mostrar documentos en una página web o en una interfaz similar, puede crear imágenes en miniatura a partir de una o más de sus páginas.

Próximos pasos:

  • Explore los ejemplos de código de la API de Layout.
  • Compare la generación de PDF a partir de bloques de construcción componibles con otros enfoques para crear PDF.
  • Contáctenos si tiene preguntas, comentarios o casos límite.