Saltar al pie de página
GUíAS DE MIGRACIóN

Migrar de NReco PDF Generator a IronPDF: VeriFactu, LOPDGDD y Cumplimiento Fiscal en C#

Por qué migrar de Generador de PDF de NReco a IronPDF en España

Para los ISVs y desarrolladores españoles que operan bajo el régimen VeriFactu (Real Decreto-Ley 15/2025), la elección del motor PDF no es solo técnica: es un asunto de conformidad fiscal y protección de datos. Las vulnerabilidades sin parchear de NReco PDF Generator —heredadas de wkhtmltopdf, un proyecto abandonado en 2020— tienen implicaciones directas en flujos de facturación electrónica regulados por la AEAT. Un motor PDF con CVEs activas en la cadena de generación de facturas VERI*FACTU representa un riesgo regulatorio que puede activar sanciones de hasta 150.000 €/año.

La LOPDGDD (Ley Orgánica de Protección de Datos y Garantía de Derechos Digitales), supervisada por la AEPD, exige que los sistemas que tratan datos fiscales de clientes —NIF/CIF, importes, datos de identificación— implementen medidas técnicas adecuadas. Mantener un motor con vulnerabilidades SSRF conocidas (CVE-2020-21365) en un sistema que procesa datos de terceros dificulta el cumplimiento del principio de seguridad por diseño. IronPDF, al procesar todo localmente con motor Chromium moderno y sin CVEs activas, simplifica esta base legal.

Cuestiones críticas de seguridad con NReco PDF Generator

NReco PDF Generator envuelve el obsoleto binario wkhtmltopdf, heredando todas sus vulnerabilidades de seguridad. No se trata de una preocupación teórica: hay más de 20 CVE documentadas sin parches disponibles desde que wkhtmltopdf se abandonó en 2020:

  • CVE-2020-21365: Falsificación de solicitud del lado del servidor (SSRF)
  • CVE-2022-35583: Lectura de archivos locales mediante inyección HTML
  • CVE-2022-35580: Potencial de ejecución remota de código

Estas vulnerabilidades no pueden parchearse porque el proyecto wkhtmltopdf subyacente ya no se mantiene.

Limitaciones adicionales del generador de PDF de NReco

  1. Versión gratuita con marca de agua: el uso en producción requiere una licencia paga con precios opacos que requieren contactar al departamento de ventas.

  2. Motor de renderizado obsoleto: WebKit Qt (circa 2012) ofrece compatibilidad web moderna limitada:

    • Sin CSS Grid ni Flexbox
    • Sin JavaScriptmoderno (ES6+)
    • Escasa compatibilidad con fuentes web
    • Sin variables CSS ni propiedades personalizadas
  3. Dependencia binaria externa: requiere la gestión de binarios wkhtmltopdf por plataforma (wkhtmltopdf.exe, wkhtmltox.dll).

  4. Sin desarrollo activo: el contenedor recibe mantenimiento sin actualizaciones del motor subyacentes.

  5. Compatibilidad asincrónica limitada: la API sincrónica bloquea subprocesos en aplicaciones web.

Comparación entre Generador de PDF de NRecoe IronPDF

Aspecto Generador de PDF de NReco IronPDF
Motor de renderizado WebKit Qt (2012) Chromium (actual)
Seguridad más de 20 CVE, sin parches Actualizaciones de seguridad activas
Soporte CSS CSS2.1, CSS3 limitado CSS3 completo, Grid, Flexbox
JavaScript ES5 básico ES6+ completo, async/await
Dependencias Binario externo wkhtmltopdf Autocontenido
Soporte de Async Sólo sincrónico Async/await completo
Fuentes web Limitado Fuentes Google completas, @font-face
Licencias Precios opacos, póngase en contacto con ventas Precios transparentes
Prueba gratuita Marca de agua Funcionalidad completa

Para los equipos que planifican la adopción de .NET 10 y C# 14 hasta 2025 y 2026, IronPDF proporciona una base preparada para el futuro con desarrollo activo y capacidades de renderización modernas.

Contexto regulatorio español: CVEs en flujos VeriFactu y TicketBAI

Para equipos españoles, el motor wkhtmltopdf subyacente de NReco PDF Generator tiene implicaciones específicas en flujos de cumplimiento:

CVE-2020-21365 y CVE-2022-35583 en facturación electrónica: el SSRF y la lectura de archivos locales sin parchear representan riesgos en sistemas que generan facturas VeriFactu con acceso a la AEAT o a ERPs internos. El Real Decreto-Ley 15/2025 requiere que los proveedores de software de facturación garanticen la integridad de la cadena de auditoría; un motor comprometido rompe esa cadena.

*Leyenda VERIFACTU con CSS moderno:* las representaciones gráficas conformes requieren la leyenda `VERIFACTUoFactura verificable en la sede electrónica de la AEAT` y el QR de la AEAT. El motor WebKit Qt (circa 2012) de NReco sin soporte Flexbox/Grid dificulta maquetaciones modernas. IronPDF con Chromium soporta CSS3 completo.

TicketBAI (Bizkaia, Gipuzkoa, Araba): NReco PDF Generator no tiene soporte de firmas digitales. IronPDF incluye soporte nativo de firma XAdES en el mismo paquete, simplificando la generación de facturas TicketBAI.

Penalización de hasta 150.000 €/año: con el régimen VeriFactu sancionando a proveedores no conformes, mantener vulnerabilidades SSRF conocidas en la cadena de generación de facturas es un riesgo técnico y regulatorio que IronPDF elimina.

Ejemplo: factura conforme con VeriFactu en IronPDF (sin CVEs)

using IronPdf;

// IronPDF: sin CVE-2020-21365, sin CVE-2022-35583, CSS3 completo
var renderer = new ChromePdfRenderer();
var html = @"
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .header { display: flex; justify-content: space-between; }
        .verifactu-legend {
            border: 2px solid #003366;
            padding: 8px 12px;
            font-size: 10px;
            text-align: center;
            margin-top: 20px;
        }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th, td { border: 1px solid #ccc; padding: 8px; }
        th { background-color: #003366; color: white; }
    </style>
</head>
<body>
    <div class='header'>
        <strong>FACTURA Nº 2026-0055</strong>
        <span>Fecha: 20/05/2026</span>
    </div>
    <table>
        <tr><th>Concepto</th><th>Total</th></tr>
        <tr><td>Licencia software anual</td><td>1.200,00 €</td></tr>
    </table>
    <div class='verifactu-legend'>
        <strong>VERI*FACTU</strong><br>
        Factura verificable en la sede electrónica de la AEAT<br>
        [QR AEAT placeholder]
    </div>
</body>
</html>";

var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("factura-verifactu-2026-0055.pdf");
using IronPdf;

// IronPDF: sin CVE-2020-21365, sin CVE-2022-35583, CSS3 completo
var renderer = new ChromePdfRenderer();
var html = @"
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .header { display: flex; justify-content: space-between; }
        .verifactu-legend {
            border: 2px solid #003366;
            padding: 8px 12px;
            font-size: 10px;
            text-align: center;
            margin-top: 20px;
        }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th, td { border: 1px solid #ccc; padding: 8px; }
        th { background-color: #003366; color: white; }
    </style>
</head>
<body>
    <div class='header'>
        <strong>FACTURA Nº 2026-0055</strong>
        <span>Fecha: 20/05/2026</span>
    </div>
    <table>
        <tr><th>Concepto</th><th>Total</th></tr>
        <tr><td>Licencia software anual</td><td>1.200,00 €</td></tr>
    </table>
    <div class='verifactu-legend'>
        <strong>VERI*FACTU</strong><br>
        Factura verificable en la sede electrónica de la AEAT<br>
        [QR AEAT placeholder]
    </div>
</body>
</html>";

var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("factura-verifactu-2026-0055.pdf");
Imports IronPdf

' IronPDF: sin CVE-2020-21365, sin CVE-2022-35583, CSS3 completo
Dim renderer As New ChromePdfRenderer()
Dim html As String = "
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .header { display: flex; justify-content: space-between; }
        .verifactu-legend {
            border: 2px solid #003366;
            padding: 8px 12px;
            font-size: 10px;
            text-align: center;
            margin-top: 20px;
        }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th, td { border: 1px solid #ccc; padding: 8px; }
        th { background-color: #003366; color: white; }
    </style>
</head>
<body>
    <div class='header'>
        <strong>FACTURA Nº 2026-0055</strong>
        <span>Fecha: 20/05/2026</span>
    </div>
    <table>
        <tr><th>Concepto</th><th>Total</th></tr>
        <tr><td>Licencia software anual</td><td>1.200,00 €</td></tr>
    </table>
    <div class='verifactu-legend'>
        <strong>VERI*FACTU</strong><br>
        Factura verificable en la sede electrónica de la AEAT<br>
        [QR AEAT placeholder]
    </div>
</body>
</html>"

Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("factura-verifactu-2026-0055.pdf")
$vbLabelText   $csharpLabel

Conformidad LOPDGDD y eIDAS: ventajas de IronPDF para ISVs españoles

Más allá de la facturación VeriFactu, los ISVs españoles que procesan documentos con datos de clientes deben cumplir con la LOPDGDD y el RGPD. IronPDF refuerza este cumplimiento en tres áreas:

  1. Procesamiento local sin transferencias externas: IronPDF genera PDFs completamente en su infraestructura, sin enviar datos de NIF/CIF ni importes a servidores de terceros.
  2. Firma digital eIDAS: IronPDF soporta firmas PAdES conformes con el reglamento eIDAS, permitiendo firmar facturas electrónicas con certificados emitidos por la FNMT-RCM (Fábrica Nacional de Moneda y Timbre).
  3. Eliminación de CVEs en cadena de auditoría: El Real Decreto-Ley 15/2025 exige que la cadena de generación de facturas tenga integridad verificable. Un motor con SSRF activo no puede garantizar esta integridad.

Ejemplo: factura con NIF/CIF y formato de importes español

Para ISVs que emiten facturas con identificadores fiscales españoles, el formato correcto es NIF (B-12345678 para empresas, 12345678Z para autónomos) y los importes en formato español (EUR 1.234,56 €, con IVA al 21%):

using IronPdf;

var renderer = new ChromePdfRenderer();
var html = @"
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .header { display: flex; justify-content: space-between; }
        .fiscal { font-size: 11px; color: #555; margin-top: 5px; }
        .verifactu-legend {
            border: 2px solid #003366;
            padding: 8px 12px;
            font-size: 10px;
            text-align: center;
            margin-top: 20px;
        }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th, td { border: 1px solid #ccc; padding: 8px; }
        th { background-color: #003366; color: white; }
    </style>
</head>
<body>
    <div class='header'>
        <div>
            <strong>Empresa Ejemplo S.L.</strong><br>
            <span class='fiscal'>NIF: B-87654321 | IVA: ES-B87654321</span>
        </div>
        <div>
            <strong>FACTURA Nº 2026-0055</strong><br>
            <span class='fiscal'>Fecha: 20/05/2026</span>
        </div>
    </div>
    <table>
        <tr><th>Concepto</th><th>Base Imponible</th><th>IVA (21%)</th><th>Total</th></tr>
        <tr><td>Licencia software anual</td><td>1.000,00 €</td><td>210,00 €</td><td>1.210,00 €</td></tr>
        <tr><td>Mantenimiento Q1</td><td>500,00 €</td><td>105,00 €</td><td>605,00 €</td></tr>
    </table>
    <div class='verifactu-legend'>
        <strong>VERI*FACTU</strong><br>
        Factura verificable en la sede electrónica de la AEAT<br>
        [QR AEAT: https://sede.agenciatributaria.gob.es/...]
    </div>
</body>
</html>";

// Motor Chromium: sin CVE-2020-21365, procesamiento local, LOPDGDD compliant
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("factura-2026-0055-verifactu.pdf");
using IronPdf;

var renderer = new ChromePdfRenderer();
var html = @"
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .header { display: flex; justify-content: space-between; }
        .fiscal { font-size: 11px; color: #555; margin-top: 5px; }
        .verifactu-legend {
            border: 2px solid #003366;
            padding: 8px 12px;
            font-size: 10px;
            text-align: center;
            margin-top: 20px;
        }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th, td { border: 1px solid #ccc; padding: 8px; }
        th { background-color: #003366; color: white; }
    </style>
</head>
<body>
    <div class='header'>
        <div>
            <strong>Empresa Ejemplo S.L.</strong><br>
            <span class='fiscal'>NIF: B-87654321 | IVA: ES-B87654321</span>
        </div>
        <div>
            <strong>FACTURA Nº 2026-0055</strong><br>
            <span class='fiscal'>Fecha: 20/05/2026</span>
        </div>
    </div>
    <table>
        <tr><th>Concepto</th><th>Base Imponible</th><th>IVA (21%)</th><th>Total</th></tr>
        <tr><td>Licencia software anual</td><td>1.000,00 €</td><td>210,00 €</td><td>1.210,00 €</td></tr>
        <tr><td>Mantenimiento Q1</td><td>500,00 €</td><td>105,00 €</td><td>605,00 €</td></tr>
    </table>
    <div class='verifactu-legend'>
        <strong>VERI*FACTU</strong><br>
        Factura verificable en la sede electrónica de la AEAT<br>
        [QR AEAT: https://sede.agenciatributaria.gob.es/...]
    </div>
</body>
</html>";

// Motor Chromium: sin CVE-2020-21365, procesamiento local, LOPDGDD compliant
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("factura-2026-0055-verifactu.pdf");
Imports IronPdf

Dim renderer As New ChromePdfRenderer()
Dim html As String = "
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .header { display: flex; justify-content: space-between; }
        .fiscal { font-size: 11px; color: #555; margin-top: 5px; }
        .verifactu-legend {
            border: 2px solid #003366;
            padding: 8px 12px;
            font-size: 10px;
            text-align: center;
            margin-top: 20px;
        }
        table { width: 100%; border-collapse: collapse; margin-top: 20px; }
        th, td { border: 1px solid #ccc; padding: 8px; }
        th { background-color: #003366; color: white; }
    </style>
</head>
<body>
    <div class='header'>
        <div>
            <strong>Empresa Ejemplo S.L.</strong><br>
            <span class='fiscal'>NIF: B-87654321 | IVA: ES-B87654321</span>
        </div>
        <div>
            <strong>FACTURA Nº 2026-0055</strong><br>
            <span class='fiscal'>Fecha: 20/05/2026</span>
        </div>
    </div>
    <table>
        <tr><th>Concepto</th><th>Base Imponible</th><th>IVA (21%)</th><th>Total</th></tr>
        <tr><td>Licencia software anual</td><td>1.000,00 €</td><td>210,00 €</td><td>1.210,00 €</td></tr>
        <tr><td>Mantenimiento Q1</td><td>500,00 €</td><td>105,00 €</td><td>605,00 €</td></tr>
    </table>
    <div class='verifactu-legend'>
        <strong>VERI*FACTU</strong><br>
        Factura verificable en la sede electrónica de la AEAT<br>
        [QR AEAT: https://sede.agenciatributaria.gob.es/...]
    </div>
</body>
</html>"

' Motor Chromium: sin CVE-2020-21365, procesamiento local, LOPDGDD compliant
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("factura-2026-0055-verifactu.pdf")
$vbLabelText   $csharpLabel

Antes de empezar

Prerrequisitos

  1. Entorno .NET : .NET Framework 4.6.2+ o .NET Core 3.1+ / .NET 5/6/7/8/9+
  2. Acceso a NuGet : Capacidad para instalar paquetes NuGet
  3. Licencia deIronPDF: Obtenga su clave de licencia en IronPDF

Cambios en el paquete NuGet

# Remove NReco.PdfGenerator
dotnet remove package NReco.PdfGenerator

# Install IronPDF
dotnet add package IronPdf
# Remove NReco.PdfGenerator
dotnet remove package NReco.PdfGenerator

# Install IronPDF
dotnet add package IronPdf
SHELL

Elimine también los binarios wkhtmltopdf de su despliegue:

  • Eliminar wkhtmltopdf.exe, wkhtmltox.dll del proyecto
  • Eliminar cualquier script de instalación de wkhtmltopdf
  • Eliminar carpetas binarias específicas de la plataforma

Configuración de licencias

// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add at application startup (Program.vb or Startup.vb)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

Identificar el uso del generador de PDF de NReco

# Find all NReco.PdfGenerator references
grep -r "NReco.PdfGenerator\|HtmlToPdfConverter\|GeneratePdf" --include="*.cs" .
# Find all NReco.PdfGenerator references
grep -r "NReco.PdfGenerator\|HtmlToPdfConverter\|GeneratePdf" --include="*.cs" .
SHELL

Referencia completa de la API

Asignaciones de clases principales

Generador de PDF de NReco IronPDF
HtmlToPdfConverter ChromePdfRenderer
PageMargins Propiedades de los márgenes individuales
PageOrientation PdfPaperOrientation
PageSize PdfPaperSize

Métodos de renderizado

Generador de PDF de NReco IronPDF
GeneratePdf(html) RenderHtmlAsPdf(html)
GeneratePdfFromFile(url, output) RenderUrlAsPdf(url)
GeneratePdfFromFile(htmlPath, output) RenderHtmlFileAsPdf(path)
(async no compatible)_ RenderHtmlAsPdfAsync(html)
(async no compatible)_ RenderUrlAsPdfAsync(url)

Configuración de páginas

Generador de PDF de NReco IronPDF
PageWidth = 210 RenderingOptions.PaperSize = PdfPaperSize.A4
PageHeight = 297 RenderingOptions.SetCustomPaperSizeinMilimeters(w, h)
Orientation = PageOrientation.Landscape RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape
Size = PageSize.A4 RenderingOptions.PaperSize = PdfPaperSize.A4

Mapeo de márgenes

Generador de PDF de NReco IronPDF
Margins.Top = 10 RenderingOptions.MarginTop = 10
Margins.Bottom = 10 RenderingOptions.MarginBottom = 10
Margins.Left = 10 RenderingOptions.MarginLeft = 10
Margins.Right = 10 RenderingOptions.MarginRight = 10
nuevos PageMargins { ... } Propiedades individuales

Mapas de marcador de posición de encabezado/pie

Generador de PDF de NReco (wkhtmltopdf) IronPDF
[page] {page}
[topage] {total-pages}
[date] {date}
[time] {time}
[title] {html-title}

Mapeos de manejo de salidas

Generador de PDF de NReco IronPDF
byte[] pdfBytes = GeneratePdf(html) PdfDocument pdf = RenderHtmlAsPdf(html)
File.WriteAllBytes(path, bytes) pdf.SaveAs(path)
return pdfBytes return pdf.BinaryData
new MemoryStream(pdfBytes) pdf.Stream

Ejemplos de migración de código

Ejemplo 1: HTML básico a PDF

Antes (NReco PDF Generator):

// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        var htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
        var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
        File.WriteAllBytes("output.pdf", pdfBytes);
    }
}
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        var htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
        var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
        File.WriteAllBytes("output.pdf", pdfBytes);
    }
}
Imports NReco.PdfGenerator
Imports System.IO

Class Program
    Shared Sub Main()
        Dim htmlToPdf = New HtmlToPdfConverter()
        Dim htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>"
        Dim pdfBytes = htmlToPdf.GeneratePdf(htmlContent)
        File.WriteAllBytes("output.pdf", pdfBytes)
    End Sub
End Class
$vbLabelText   $csharpLabel

Después (IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
        var pdf = renderer.RenderHtmlAsPdf(htmlContent);
        pdf.SaveAs("output.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System.IO;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
        var pdf = renderer.RenderHtmlAsPdf(htmlContent);
        pdf.SaveAs("output.pdf");
    }
}
Imports IronPdf
Imports System.IO

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        Dim htmlContent = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>"
        Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
        pdf.SaveAs("output.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

La diferencia fundamental radica en el tipo de retorno y el patrón de guardado. El generador de PDF NReco HtmlToPdfConverter.GeneratePdf() devuelve un byte[] que debe escribir manualmente en el disco usando File.WriteAllBytes(). ChromePdfRenderer.RenderHtmlAsPdf() deIronPDFdevuelve un objeto PdfDocument con un método SaveAs() incorporado.

Este enfoque orientado a objetos ofrece ventajas adicionales: se puede manipular el PDF (añadir marcas de agua, fusionar documentos, añadir seguridad) antes de guardarlo. Si necesita los bytes sin procesar para compatibilidad con el código existente, utilice pdf.BinaryData. Consulte la documentación HTML a PDF para obtener más opciones de conversión.

Ejemplo 2: Tamaño de página personalizado con márgenes

Antes (NReco PDF Generator):

// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        htmlToPdf.PageWidth = 210;
        htmlToPdf.PageHeight = 297;
        htmlToPdf.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };
        var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
        var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
        File.WriteAllBytes("custom-size.pdf", pdfBytes);
    }
}
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        htmlToPdf.PageWidth = 210;
        htmlToPdf.PageHeight = 297;
        htmlToPdf.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };
        var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
        var pdfBytes = htmlToPdf.GeneratePdf(htmlContent);
        File.WriteAllBytes("custom-size.pdf", pdfBytes);
    }
}
Imports NReco.PdfGenerator
Imports System.IO

Class Program
    Shared Sub Main()
        Dim htmlToPdf = New HtmlToPdfConverter()
        htmlToPdf.PageWidth = 210
        htmlToPdf.PageHeight = 297
        htmlToPdf.Margins = New PageMargins With {.Top = 10, .Bottom = 10, .Left = 10, .Right = 10}
        Dim htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>"
        Dim pdfBytes = htmlToPdf.GeneratePdf(htmlContent)
        File.WriteAllBytes("custom-size.pdf", pdfBytes)
    End Sub
End Class
$vbLabelText   $csharpLabel

Después (IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 10;
        renderer.RenderingOptions.MarginBottom = 10;
        renderer.RenderingOptions.MarginLeft = 10;
        renderer.RenderingOptions.MarginRight = 10;
        var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
        var pdf = renderer.RenderHtmlAsPdf(htmlContent);
        pdf.SaveAs("custom-size.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
        renderer.RenderingOptions.MarginTop = 10;
        renderer.RenderingOptions.MarginBottom = 10;
        renderer.RenderingOptions.MarginLeft = 10;
        renderer.RenderingOptions.MarginRight = 10;
        var htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>";
        var pdf = renderer.RenderHtmlAsPdf(htmlContent);
        pdf.SaveAs("custom-size.pdf");
    }
}
Imports IronPdf
Imports IronPdf.Rendering

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
        renderer.RenderingOptions.MarginTop = 10
        renderer.RenderingOptions.MarginBottom = 10
        renderer.RenderingOptions.MarginLeft = 10
        renderer.RenderingOptions.MarginRight = 10
        Dim htmlContent = "<html><body><h1>Custom Page Size</h1><p>A4 size document with margins.</p></body></html>"
        Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
        pdf.SaveAs("custom-size.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

El generador de PDF NReco utiliza dimensiones numéricas (PageWidth = 210, PageHeight = 297) y un objeto PageMargins.IronPDFutiliza la enumeración PdfPaperSize (que incluye tamaños estándar como A4, Carta, Legal) y propiedades de margen individuales en el objeto RenderingOptions.

Los cambios clave de la migración:

  • PageHeightRenderingOptions.PaperSize = PdfPaperSize.A4
  • nuevo PageMargins { Top = 10, ... }→ Individual properties:RenderingOptions.MarginTop = 10`

Para tamaños de papel personalizados no cubiertos por la enumeración, utilice RenderingOptions.SetCustomPaperSizeinMilimeters(width, height). Más información sobre opciones de configuración de página.

Ejemplo 3: Conversión de URL a PDF

Antes (NReco PDF Generator):

// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        var pdfBytes = htmlToPdf.GeneratePdfFromFile("https://www.example.com", null);
        File.WriteAllBytes("webpage.pdf", pdfBytes);
    }
}
// NuGet: Install-Package NReco.PdfGenerator
using NReco.PdfGenerator;
using System.IO;

class Program
{
    static void Main()
    {
        var htmlToPdf = new HtmlToPdfConverter();
        var pdfBytes = htmlToPdf.GeneratePdfFromFile("https://www.example.com", null);
        File.WriteAllBytes("webpage.pdf", pdfBytes);
    }
}
Imports NReco.PdfGenerator
Imports System.IO

Class Program
    Shared Sub Main()
        Dim htmlToPdf As New HtmlToPdfConverter()
        Dim pdfBytes As Byte() = htmlToPdf.GeneratePdfFromFile("https://www.example.com", Nothing)
        File.WriteAllBytes("webpage.pdf", pdfBytes)
    End Sub
End Class
$vbLabelText   $csharpLabel

Después (IronPDF):

// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
        pdf.SaveAs("webpage.pdf");
    }
}
Imports IronPdf

Class Program
    Shared Sub Main()
        Dim renderer As New ChromePdfRenderer()
        Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
        pdf.SaveAs("webpage.pdf")
    End Sub
End Class
$vbLabelText   $csharpLabel

NReco PDF Generator utiliza el método GeneratePdfFromFile() que tiene un nombre confuso tanto para archivos locales como para URL, con un segundo parámetro que acepta valores nulos.IronPDFproporciona métodos dedicados: RenderUrlAsPdf() para URL y RenderHtmlFileAsPdf() para archivos HTML locales.

El enfoque deIronPDFes más limpio e intuitivo. Para aplicaciones web asíncronas, use await renderer.RenderUrlAsPdfAsync(url) para evitar el bloqueo de subprocesos, algo que el generador de PDF de NReco simplemente no puede hacer.


Notas de migración críticas

Conversión de valores de zoom

NReco PDF Generator utiliza valores flotantes (0,0-2,0), mientras queIronPDFutiliza enteros porcentuales:

// NReco PDF Generator: Zoom = 0.9f (90%)
// IronPDF: Zoom = 90

// Conversion formula:
int ironPdfZoom = (int)(nrecoZoom * 100);
// NReco PDF Generator: Zoom = 0.9f (90%)
// IronPDF: Zoom = 90

// Conversion formula:
int ironPdfZoom = (int)(nrecoZoom * 100);
' NReco PDF Generator: Zoom = 0.9F (90%)
' IronPDF: Zoom = 90

' Conversion formula:
Dim ironPdfZoom As Integer = CInt(nrecoZoom * 100)
$vbLabelText   $csharpLabel

Actualización de la sintaxis de los marcadores

Deben actualizarse todos los marcadores de posición de encabezado/pie de página:

Generador de PDF de NReco IronPDF
[page] {page}
[topage] {total-pages}
[date] {date}
[title] {html-title}
// NReco PDF Generator:
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";

// IronPDF:
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = "<div>Page {page} of {total-pages}</div>",
    MaxHeight = 20
};
// NReco PDF Generator:
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";

// IronPDF:
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = "<div>Page {page} of {total-pages}</div>",
    MaxHeight = 20
};
Imports NReco.PdfGenerator
Imports IronPdf

' NReco PDF Generator:
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>"

' IronPDF:
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
    .HtmlFragment = "<div>Page {page} of {total-pages}</div>",
    .MaxHeight = 20
}
$vbLabelText   $csharpLabel

Cambio de tipo de retorno

El generador de PDF NReco devuelve byte[] directamente;IronPDFdevuelve PdfDocument:

// Generador de PDF de NRecopattern:
byte[] pdfBytes = converter.GeneratePdf(html);
File.WriteAllBytes("output.pdf", pdfBytes);

//IronPDFpattern:
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");

// Or if you need bytes:
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
// Generador de PDF de NRecopattern:
byte[] pdfBytes = converter.GeneratePdf(html);
File.WriteAllBytes("output.pdf", pdfBytes);

//IronPDFpattern:
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");

// Or if you need bytes:
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
' Generador de PDF de NRecopattern:
Dim pdfBytes As Byte() = converter.GeneratePdf(html)
File.WriteAllBytes("output.pdf", pdfBytes)

' IronPDFpattern:
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")

' Or if you need bytes:
Dim pdfBytes As Byte() = renderer.RenderHtmlAsPdf(html).BinaryData
$vbLabelText   $csharpLabel

Seguridad y reutilización de hilos

NReco PDF Generator suele crear un nuevo conversor por llamada. El ChromePdfRenderer deIronPDFes seguro para subprocesos y se puede reutilizar:

// Generador de PDF de NRecopattern (creates new each time):
public byte[] Generate(string html)
{
    var converter = new HtmlToPdfConverter();
    return converter.GeneratePdf(html);
}

//IronPDFpattern (reuse renderer, thread-safe):
private readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();

public byte[] Generate(string html)
{
    return _renderer.RenderHtmlAsPdf(html).BinaryData;
}
// Generador de PDF de NRecopattern (creates new each time):
public byte[] Generate(string html)
{
    var converter = new HtmlToPdfConverter();
    return converter.GeneratePdf(html);
}

//IronPDFpattern (reuse renderer, thread-safe):
private readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();

public byte[] Generate(string html)
{
    return _renderer.RenderHtmlAsPdf(html).BinaryData;
}
' Generador de PDF de NRecopattern (creates new each time):
Public Function Generate(html As String) As Byte()
    Dim converter As New HtmlToPdfConverter()
    Return converter.GeneratePdf(html)
End Function

' IronPDFpattern (reuse renderer, thread-safe):
Private ReadOnly _renderer As New ChromePdfRenderer()

Public Function Generate(html As String) As Byte()
    Return _renderer.RenderHtmlAsPdf(html).BinaryData
End Function
$vbLabelText   $csharpLabel

Soporte asíncrono (nueva capacidad)

IronPDF admite patrones async/await que Generador de PDF de NRecono puede proporcionar:

// NReco PDF Generator: No async support available

// IronPDF: Full async support
public async Task<byte[]> GenerateAsync(string html)
{
    var pdf = await _renderer.RenderHtmlAsPdfAsync(html);
    return pdf.BinaryData;
}
// NReco PDF Generator: No async support available

// IronPDF: Full async support
public async Task<byte[]> GenerateAsync(string html)
{
    var pdf = await _renderer.RenderHtmlAsPdfAsync(html);
    return pdf.BinaryData;
}
Imports System.Threading.Tasks

' NReco PDF Generator: No async support available

' IronPDF: Full async support
Public Async Function GenerateAsync(html As String) As Task(Of Byte())
    Dim pdf = Await _renderer.RenderHtmlAsPdfAsync(html)
    Return pdf.BinaryData
End Function
$vbLabelText   $csharpLabel

Solución de problemas

Asunto 1: HtmlToPdfConverter no encontrado

Problema: la clase HtmlToPdfConverter no existe en IronPDF.

Solución: Utilice ChromePdfRenderer:

// NReco PDF Generator
var converter = new HtmlToPdfConverter();

// IronPDF
var renderer = new ChromePdfRenderer();
// NReco PDF Generator
var converter = new HtmlToPdfConverter();

// IronPDF
var renderer = new ChromePdfRenderer();
' NReco PDF Generator
Dim converter As New HtmlToPdfConverter()

' IronPDF
Dim renderer As New ChromePdfRenderer()
$vbLabelText   $csharpLabel

Asunto 2: GeneratePdf devuelve un tipo incorrecto

Problema: el código espera byte[] pero obtiene PdfDocument.

Solución: Acceder a la propiedad .BinaryData:

// NReco PDF Generator
byte[] pdfBytes = converter.GeneratePdf(html);

// IronPDF
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
// NReco PDF Generator
byte[] pdfBytes = converter.GeneratePdf(html);

// IronPDF
byte[] pdfBytes = renderer.RenderHtmlAsPdf(html).BinaryData;
' NReco PDF Generator
Dim pdfBytes As Byte() = converter.GeneratePdf(html)

' IronPDF
Dim pdfBytes As Byte() = renderer.RenderHtmlAsPdf(html).BinaryData
$vbLabelText   $csharpLabel

Edición 3: Objeto PageMargins no encontrado

Problema: la clase PageMargins no existe en IronPDF.

Solución: utilice propiedades de margen individuales:

// NReco PDF Generator
converter.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };

// IronPDF
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
// NReco PDF Generator
converter.Margins = new PageMargins { Top = 10, Bottom = 10, Left = 10, Right = 10 };

// IronPDF
renderer.RenderingOptions.MarginTop = 10;
renderer.RenderingOptions.MarginBottom = 10;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 10;
' NReco PDF Generator
converter.Margins = New PageMargins With {.Top = 10, .Bottom = 10, .Left = 10, .Right = 10}

' IronPDF
renderer.RenderingOptions.MarginTop = 10
renderer.RenderingOptions.MarginBottom = 10
renderer.RenderingOptions.MarginLeft = 10
renderer.RenderingOptions.MarginRight = 10
$vbLabelText   $csharpLabel

Cuestión 4: Los números de página no aparecen

Problema: los marcadores de posición [page] y [topage] no funcionan.

Solución: Actualizar la sintaxis del marcador de posiciónIronPDF:

// NReco PDF Generator
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";

// IronPDF
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = "<div>Page {page} of {total-pages}</div>",
    MaxHeight = 20
};
// NReco PDF Generator
converter.PageFooterHtml = "<div>Page [page] of [topage]</div>";

// IronPDF
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = "<div>Page {page} of {total-pages}</div>",
    MaxHeight = 20
};
Imports NReco.PdfGenerator
Imports IronPdf

converter.PageFooterHtml = "<div>Page [page] of [topage]</div>"

renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
    .HtmlFragment = "<div>Page {page} of {total-pages}</div>",
    .MaxHeight = 20
}
$vbLabelText   $csharpLabel

Cumplimiento Crea y Crece y SII: nuevas obligaciones para ISVs en España

La Ley Crea y Crece establece la obligación de factura electrónica B2B en España por fases: empresas con facturación superior a 8 millones de euros a partir de 2027, y el resto a partir de 2028. El formato exigido (Facturae XML con perfil CIUS-ES conforme a EN 16931) debe enviarse a través de FACe. Además, el SII (Suministro Inmediato de Información) de la AEAT requiere el reporte electrónico de libros de registro de IVA.

IronPDF facilita la transición de NReco PDF Generator a una arquitectura que soporta estos requisitos:

  • Facturae XML embebido en PDF/A-3: IronPDF genera PDFs que pueden incluir el XML de Facturae como adjunto conforme, para envío a FACe.
  • Firma digital PAdES: Las facturas deben llevar firma electrónica cualificada. IronPDF soporta firmas PAdES con certificados de la FNMT-RCM.
  • TicketBAI para el País Vasco: ISVs que distribuyan software a clientes en Bizkaia, Gipuzkoa o Araba deben implementar TicketBAI con firma XAdES. IronPDF incluye soporte de firma digital nativo.
  • VERI*FACTU con QR de la AEAT: La leyenda obligatoria VERI*FACTU y el QR de verificación de la AEAT deben renderizarse con precisión. El motor Chromium de IronPDF garantiza este renderizado.

Tabla de conformidad post-migración

Requisito regulatorio NReco PDF Generator IronPDF
VERI*FACTU leyenda CSS3 No garantizado (WebKit Qt 2012) Sí (Chromium)
QR AEAT renderizado Calidad impredecible
Firma XAdES TicketBAI No
Firma PAdES FNMT-RCM No
Sin CVE SSRF (LOPDGDD) No (CVE-2020-21365)
Facturae XML/FACe No Sí (PDF/A-3)
SII AEAT reporte Fuera de alcance Fuera de alcance
Crea y Crece B2B Incompleto Preparado

Lista de comprobación de la migración

Pre-Migración

  • Inventariar todos los usos de NReco.PdfGenerator en el código base
  • Documentar todos los valores CustomWkHtmlArgs y CustomWkHtmlPageArgs
  • Enumere todas las plantillas HTML de encabezado/pie de página con marcadores de posición
  • Identificar requisitos asincrónicos (controladores web, servicios)
  • Revisar la configuración de zoom y márgenes
  • Realice una copia de seguridad de las salidas PDF existentes para compararlas
  • Obtener la clave de licencia de IronPDF

Cambios en el paquete

  • Eliminar el paquete NuGet NReco.PdfGenerator
  • Instalar IronPdf el paquete NuGet : dotnet add package IronPdf
  • Actualizar las importaciones de espacios de nombres de using NReco.PdfGenerator; a using IronPdf;

Cambios de código

  • Agregar configuración de clave de licencia al inicio
  • Reemplace HtmlToPdfConverter con ChromePdfRenderer
  • Reemplace GeneratePdf(html) con RenderHtmlAsPdf(html)
  • Reemplace GeneratePdfFromFile(url, null) con RenderUrlAsPdf(url)
  • Convertir el objeto PageMargins en propiedades de margen individuales
  • Actualizar los valores de zoom de flotante a porcentaje
  • Actualizar la sintaxis del marcador de posición: [page]{page}, [topage]{total-pages}
  • Reemplace File.WriteAllBytes() con pdf.SaveAs()
  • Convertir llamadas sincrónicas en asincrónicas cuando sea beneficioso

Posmigración

  • Eliminar los binarios wkhtmltopdf del proyecto/implementación
  • Actualizar los archivos de Docker para eliminar la instalación de wkhtmltopdf
  • Ejecutar pruebas de regresión comparando la salida PDF
  • Verificar que los marcadores de posición de encabezado y pie de página se representen correctamente
  • Prueba en todas las plataformas de destino (Windows, Linux, macOS)
  • Actualizar la canalización CI/CD para eliminar los pasos wkhtmltopdf
  • Actualizar el análisis de seguridad para confirmar la eliminación de CVE (CVE-2020-21365, CVE-2022-35583, CVE-2022-35580)
  • Si el software gestiona facturación española: incorporar leyenda VERI*FACTU o Factura verificable en la sede electrónica de la AEAT con QR de la AEAT (requerido por RDL 15/2025)
  • Validar soporte TicketBAI (Bizkaia, Gipuzkoa, Araba) usando el motor Chromium moderno de IronPDF

Preguntas Frecuentes

¿Por qué NReco PDF Generator es un riesgo bajo VeriFactu?

NReco PDF Generator usa wkhtmltopdf, que tiene más de 20 CVEs sin parche, incluyendo CVE-2020-21365 (SSRF) y CVE-2022-35583 (lectura de archivos locales). El Real Decreto-Ley 15/2025 exige integridad en la cadena de generación de facturas VERI*FACTU. Un motor con SSRF activo rompe esa integridad y puede activar sanciones de hasta 150.000 €/año.

¿Cómo cumple IronPDF con la LOPDGDD al migrar desde NReco?

IronPDF procesa todos los PDFs localmente sin enviar datos a servidores externos. Esto facilita el cumplimiento del principio de seguridad por diseño de la LOPDGDD: los datos de NIF/CIF y datos fiscales de clientes permanecen en su infraestructura, supervisada por la AEPD.

¿Soporta IronPDF TicketBAI para Bizkaia, Gipuzkoa y Araba?

Sí. IronPDF incluye soporte nativo de firmas digitales XAdES y PAdES, necesarias para TicketBAI en los tres territorios históricos vascos. NReco PDF Generator no tiene capacidades de firma digital.

¿Puede IronPDF generar la leyenda VERI*FACTU con CSS3?

Sí. El motor Chromium de IronPDF soporta CSS3 completo (Flexbox, Grid, variables CSS). La leyenda VERI*FACTU con QR de la AEAT y el formato correcto se renderiza perfectamente. El motor WebKit Qt de NReco (circa 2012) no garantiza este soporte.

¿Qué certificados de firma soporta IronPDF para conformidad eIDAS en España?

IronPDF soporta firmas con certificados .pfx/.p12 emitidos por cualquier autoridad de certificación reconocida en España, incluyendo la FNMT-RCM (Fábrica Nacional de Moneda y Timbre). Los certificados emitidos por la FNMT-RCM son válidos para firma electrónica cualificada bajo eIDAS.

Curtis Chau
Escritor Técnico

Curtis Chau tiene una licenciatura en Ciencias de la Computación (Carleton University) y se especializa en el desarrollo front-end con experiencia en Node.js, TypeScript, JavaScript y React. Apasionado por crear interfaces de usuario intuitivas y estéticamente agradables, disfruta trabajando con frameworks modernos y creando manuales bien ...

Leer más

Equipo de soporte de Iron

Estamos disponibles online las 24 horas, 5 días a la semana.
Chat
Email
Llámame