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

Migrar de PrinceXML a IronPDF: VeriFactu, LOPDGDD y Sin Licencia por Servidor en .NET

La migración de PrinceXML a IronPDF transforma su flujo de trabajo de generación de PDF de un proceso de línea de comandos externo a una biblioteca .NET nativa. Para los ISVs españoles que operan bajo el régimen VeriFactu (Real Decreto-Ley 15/2025), PrinceXML introduce riesgos regulatorios significativos: la generación de facturas mediante un proceso externo con latencia variable dificulta la integridad de la cadena de facturación requerida para la leyenda VERI*FACTU, el modelo de licencia por servidor ($495+/servidor) encarece la arquitectura en entornos de producción escalables, y PrinceXML no soporta firmas XAdES para TicketBAI (Bizkaia, Gipuzkoa, Araba) ni firma PAdES conforme a eIDAS con certificados de la FNMT-RCM.

Adicionalmente, la LOPDGDD y la AEPD exigen medidas de seguridad adecuadas para el tratamiento de datos fiscales de clientes. Un proceso externo que recibe datos de facturas —NIF/CIF, importes en EUR, datos de identificación— amplía la superficie de ataque frente a una biblioteca que procesa todo en memoria. IronPDF procesa completamente en proceso, sin dependencias externas, sin instalación por servidor.

Por qué migrar de PrinceXML a IronPDF en España: VeriFactu, LOPDGDD y costes por servidor

Entender PrinceXML

PrinceXML es una sofisticada herramienta diseñada para convertir contenidos HTML en documentos PDF perfectos para la impresión gracias a su compatibilidad con las especificaciones CSS Paged Media. Esta especialización permite a PrinceXMLrenderizar documentos con gran fidelidad a los diseños de impresión previstos, un atributo valioso para sectores que requieren un estilo de impresión detallado, como el editorial o la documentación jurídica.

Sin embargo, PrinceXMLno es una biblioteca .NET y funciona como una herramienta de línea de comandos independiente, lo que puede complicar la integración para entornos que prefieren soluciones .NET puras. Su dependencia de un proceso de servidor independiente implica una gestión adicional de los recursos del sistema y una complejidad potencialmente mayor para la implantación de los proyectos.

El problema del proceso externo

PrinceXML funciona como un ejecutable de línea de comandos independiente que crea importantes retos arquitectónicos para las aplicaciones .NET:

  1. Gastos generales de gestión de procesos: se deben generar, supervisar y finalizar procesos externos.

  2. Sin integración nativa con .NET : comunicarse a través de stdin/stdout o archivos temporales.

  3. Complejidad de implementación: requiere la instalación de Prince en cada servidor.

  4. Licencia por servidor: cada implementación necesita una licencia independiente ($495+).

  5. Dificultad de manejo de errores: analizar la salida de texto para detectar errores.

  6. No Async/Await: No se requieren llamadas bloqueadoras ni envoltorios asíncronos complejos.

  7. Dependencias de ruta: debe ubicar el ejecutable de Prince en PATH o en la ruta absoluta.

Comparación entre PrinceXMLe IronPDF

Aspecto PrinceXML IronPDF
Arquitectura Proceso externo Biblioteca .NET nativa
Integración Línea de comandos API directa
Despliegue Instalar en todos los servidores Paquete NuGet único
Manejo de errores Análisis de texto excepciones de .NET
Soporte Async Envoltorios manuales Async/await nativo
Manipulación de PDF Sólo generación Manipulación completa (combinar, dividir, editar)
Licencias Por servidor ($495+) Por desarrollador
Actualizaciones Reinstalación manual Actualización de NuGet
Depuración Difícil Compatibilidad total con depuradores
Firmas digitales No
Formularios No
Soporte Docker Complejo Simple
Funciones en la nube Difícil Fácil

IronPDF ofrece una alternativa con sus capacidades nativas .NET, que van más allá de la mera conversión de HTML a PDF para incluir tareas avanzadas de manipulación de PDF, como edición, fusión y firmas digitales. La API deIronPDFestá diseñada para ofrecer simplicidad y facilidad de uso, permitiendo a los desarrolladores realizar conversiones y manipulaciones con un mínimo de código repetitivo.

Para los equipos que planifican la adopción de .NET 10 y C# 14 hasta 2025 y 2026, la perfecta implementación deIronPDFno requiere dependencias externas ni procesos de servidor, por lo que alivia la carga de la integración en .NET Framework.


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

# Install IronPDF
dotnet add package IronPdf

# Remove Prince wrapper if using one
dotnet remove package PrinceXMLWrapper
# Install IronPDF
dotnet add package IronPdf

# Remove Prince wrapper if using one
dotnet remove package PrinceXMLWrapper
SHELL

Configuración de licencias

// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

Buscar uso de PrinceXML

# Find Prince process calls
grep -r "prince" --include="*.cs" .
grep -r "Process.Start" --include="*.cs" . | grep -i prince
grep -r "@page" --include="*.css" .
grep -r "prince-" --include="*.css" .
# Find Prince process calls
grep -r "prince" --include="*.cs" .
grep -r "Process.Start" --include="*.cs" . | grep -i prince
grep -r "@page" --include="*.css" .
grep -r "prince-" --include="*.css" .
SHELL

Referencia completa de la API

Cambios en el espacio de nombres

// Before: PrinceXML
using PrinceXMLWrapper;
using System.Diagnostics;
using System.IO;

// After: IronPDF
using IronPdf;
// Before: PrinceXML
using PrinceXMLWrapper;
using System.Diagnostics;
using System.IO;

// After: IronPDF
using IronPdf;
' Before: PrinceXML
Imports PrinceXMLWrapper
Imports System.Diagnostics
Imports System.IO

' After: IronPDF
Imports IronPdf
$vbLabelText   $csharpLabel

Mapeo de línea de comandos a método

Comando Prince Equivalente de IronPDF
prince input.html -o output.pdf renderer.RenderHtmlFileAsPdf("input.html").SaveAs("output.pdf")
prince --style=custom.css input.html Incluya CSS en HTML o use RenderingOptions
prince --javascript renderer.RenderingOptions.EnableJavaScript = true
prince --no-javascript renderer.RenderingOptions.EnableJavaScript = false
prince --page-size=Letter renderer.RenderingOptions.PaperSize = PdfPaperSize.Letter
prince --page-margin=1in renderer.RenderingOptions.MarginTop = 72 (72 puntos = 1 pulgada)
prince --encrypt pdf.SecuritySettings.OwnerPassword = "..."
prince --user-password=pw pdf.SecuritySettings.UserPassword = "pw"
prince --disallow-print pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.NoPrint
prince --disallow-copy pdf.SecuritySettings.AllowUserCopyPasteContent = false
prince --baseurl=http://... renderer.RenderingOptions.BaseUrl = new Uri("http://...")
prince --media=print renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Print
prince --media=screen renderer.RenderingOptions.CssMediaType = PdfCssMediaType.Screen

CSS @page a RenderingOptions Mapping

Propiedad CSS @page Equivalente de IronPDF
size: A4 PaperSize = PdfPaperSize.A4
size: Letter PaperSize = PdfPaperSize.Letter
size: A4landscape PaperSize = PdfPaperSize.A4 + PaperOrientation = Landscape
margin: 2cm MarginTop/Bottom/Left/Right = 56
margin-top: 1in MarginTop = 72
@top-center { content: "..." } HtmlHeader con div centrado
@bottom-right { content: counter(page) } HtmlFooter con marcador de posición {page}

Conversiones de tamaño de página

Tamaño Puntos Milímetros
Carta 612 x 792 216 x 279
A4 595 x 842 210 x 297
Aviso legal 612 x 1008 216 x 356
2,5 cm 72 25.4
1 cm 28.35 10

Ejemplos de migración de código

Ejemplo 1: Conversión de un archivo HTML a PDF

Antes (PrinceXML):

// NuGet: Install-Package PrinceXMLWrapper
using PrinceXMLWrapper;
using System;

class Program
{
    static void Main()
    {
        Prince prince = new Prince("C:\\Program Files\\Prince\\engine\\bin\\prince.exe");
        prince.Convert("input.html", "output.pdf");
        Console.WriteLine("PDF created successfully");
    }
}
// NuGet: Install-Package PrinceXMLWrapper
using PrinceXMLWrapper;
using System;

class Program
{
    static void Main()
    {
        Prince prince = new Prince("C:\\Program Files\\Prince\\engine\\bin\\prince.exe");
        prince.Convert("input.html", "output.pdf");
        Console.WriteLine("PDF created successfully");
    }
}
Imports PrinceXMLWrapper
Imports System

Module Program
    Sub Main()
        Dim prince As New Prince("C:\Program Files\Prince\engine\bin\prince.exe")
        prince.Convert("input.html", "output.pdf")
        Console.WriteLine("PDF created successfully")
    End Sub
End Module
$vbLabelText   $csharpLabel

Después (IronPDF):

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

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlFileAsPdf("input.html");
        pdf.SaveAs("output.pdf");
        Console.WriteLine("PDF created successfully");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlFileAsPdf("input.html");
        pdf.SaveAs("output.pdf");
        Console.WriteLine("PDF created successfully");
    }
}
Imports IronPdf
Imports System

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        Dim pdf = renderer.RenderHtmlFileAsPdf("input.html")
        pdf.SaveAs("output.pdf")
        Console.WriteLine("PDF created successfully")
    End Sub
End Class
$vbLabelText   $csharpLabel

Este ejemplo demuestra la diferencia arquitectónica fundamental. PrinceXMLrequiere instanciar un objeto Prince con la ruta completa al ejecutable ("C:\\Program Files\\Prince\\engine\\bin\\prince.exe") y luego llamar a Convert() con las rutas de entrada y salida.

IronPDF elimina por completo las dependencias de rutas: crea un ChromePdfRenderer, llama a RenderHtmlFileAsPdf() con la ruta del archivo HTML y SaveAs() para escribir el resultado. No hay rutas ejecutables, ni gestión de procesos, ni dependencias de rutas. Consulte la documentación HTML a PDF para ver ejemplos completos.

Ejemplo 2: Conversión de URL a PDF con opciones

Antes (PrinceXML):

// NuGet: Install-Package PrinceXMLWrapper
using PrinceXMLWrapper;
using System;

class Program
{
    static void Main()
    {
        Prince prince = new Prince("C:\\Program Files\\Prince\\engine\\bin\\prince.exe");
        prince.SetJavaScript(true);
        prince.SetEncrypt(true);
        prince.SetPDFTitle("Website Export");
        prince.Convert("https://example.com", "webpage.pdf");
        Console.WriteLine("URL converted to PDF");
    }
}
// NuGet: Install-Package PrinceXMLWrapper
using PrinceXMLWrapper;
using System;

class Program
{
    static void Main()
    {
        Prince prince = new Prince("C:\\Program Files\\Prince\\engine\\bin\\prince.exe");
        prince.SetJavaScript(true);
        prince.SetEncrypt(true);
        prince.SetPDFTitle("Website Export");
        prince.Convert("https://example.com", "webpage.pdf");
        Console.WriteLine("URL converted to PDF");
    }
}
Imports PrinceXMLWrapper
Imports System

Class Program
    Shared Sub Main()
        Dim prince As New Prince("C:\Program Files\Prince\engine\bin\prince.exe")
        prince.SetJavaScript(True)
        prince.SetEncrypt(True)
        prince.SetPDFTitle("Website Export")
        prince.Convert("https://example.com", "webpage.pdf")
        Console.WriteLine("URL converted to PDF")
    End Sub
End Class
$vbLabelText   $csharpLabel

Después (IronPDF):

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

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.EnableJavaScript = true;
        renderer.RenderingOptions.PdfTitle = "Website Export";

        var pdf = renderer.RenderUrlAsPdf("https://example.com");
        pdf.Encrypt("password");
        pdf.SaveAs("webpage.pdf");
        Console.WriteLine("URL converted to PDF");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        var renderer = new ChromePdfRenderer();
        renderer.RenderingOptions.EnableJavaScript = true;
        renderer.RenderingOptions.PdfTitle = "Website Export";

        var pdf = renderer.RenderUrlAsPdf("https://example.com");
        pdf.Encrypt("password");
        pdf.SaveAs("webpage.pdf");
        Console.WriteLine("URL converted to PDF");
    }
}
Imports IronPdf
Imports System

Class Program
    Shared Sub Main()
        Dim renderer = New ChromePdfRenderer()
        renderer.RenderingOptions.EnableJavaScript = True
        renderer.RenderingOptions.PdfTitle = "Website Export"

        Dim pdf = renderer.RenderUrlAsPdf("https://example.com")
        pdf.Encrypt("password")
        pdf.SaveAs("webpage.pdf")
        Console.WriteLine("URL converted to PDF")
    End Sub
End Class
$vbLabelText   $csharpLabel

Este ejemplo muestra cómo las opciones de PrinceXMLse corresponden con las propiedades de IronPDF. PrinceXMLutiliza métodos setter (SetJavaScript(), SetEncrypt(), SetPDFTitle()) antes de la conversión.IronPDFutiliza propiedades RenderingOptions para configuraciones de pre-renderizado y métodos posteriores al renderizado como Encrypt() en el objeto PdfDocument.

Asignaciones clave:

  • prince.SetJavaScript(true)renderer.RenderingOptions.EnableJavaScript = true
  • prince.SetPDFTitle("...")renderer.RenderingOptions.PdfTitle = "..."
  • prince.SetEncrypt(true)pdf.Encrypt("password") (IronPDF requiere una contraseña)

Más información en nuestros tutoriales.

Ejemplo 3: Conversión de cadenas HTML a PDF

Antes (PrinceXML):

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

class Program
{
    static void Main()
    {
        string html = "<html><head><style>body { font-family: Arial; color: blue; }</style></head><body><h1>Hello World</h1></body></html>";
        File.WriteAllText("temp.html", html);

        Prince prince = new Prince("C:\\Program Files\\Prince\\engine\\bin\\prince.exe");
        prince.Convert("temp.html", "styled-output.pdf");
        Console.WriteLine("Styled PDF created");
    }
}
// NuGet: Install-Package PrinceXMLWrapper
using PrinceXMLWrapper;
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string html = "<html><head><style>body { font-family: Arial; color: blue; }</style></head><body><h1>Hello World</h1></body></html>";
        File.WriteAllText("temp.html", html);

        Prince prince = new Prince("C:\\Program Files\\Prince\\engine\\bin\\prince.exe");
        prince.Convert("temp.html", "styled-output.pdf");
        Console.WriteLine("Styled PDF created");
    }
}
Imports PrinceXMLWrapper
Imports System
Imports System.IO

Module Program
    Sub Main()
        Dim html As String = "<html><head><style>body { font-family: Arial; color: blue; }</style></head><body><h1>Hello World</h1></body></html>"
        File.WriteAllText("temp.html", html)

        Dim prince As New Prince("C:\Program Files\Prince\engine\bin\prince.exe")
        prince.Convert("temp.html", "styled-output.pdf")
        Console.WriteLine("Styled PDF created")
    End Sub
End Module
$vbLabelText   $csharpLabel

Después (IronPDF):

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

class Program
{
    static void Main()
    {
        string html = "<html><head><style>body { font-family: Arial; color: blue; }</style></head><body><h1>Hello World</h1></body></html>";

        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("styled-output.pdf");
        Console.WriteLine("Styled PDF created");
    }
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;

class Program
{
    static void Main()
    {
        string html = "<html><head><style>body { font-family: Arial; color: blue; }</style></head><body><h1>Hello World</h1></body></html>";

        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(html);
        pdf.SaveAs("styled-output.pdf");
        Console.WriteLine("Styled PDF created");
    }
}
Imports IronPdf
Imports System

Class Program
    Shared Sub Main()
        Dim html As String = "<html><head><style>body { font-family: Arial; color: blue; }</style></head><body><h1>Hello World</h1></body></html>"

        Dim renderer = New ChromePdfRenderer()
        Dim pdf = renderer.RenderHtmlAsPdf(html)
        pdf.SaveAs("styled-output.pdf")
        Console.WriteLine("Styled PDF created")
    End Sub
End Class
$vbLabelText   $csharpLabel

Este ejemplo resalta una diferencia crítica: PrinceXMLrequiere la entrada de un archivo, por lo que debe crear un archivo temporal (File.WriteAllText("temp.html", html)) antes de la conversión. RenderHtmlAsPdf() deIronPDFacepta cadenas HTML directamente: sin archivos temporales, sin código de limpieza, sin sobrecarga de E/S de disco.


Migración de medios paginados CSS

Aunque la compatibilidad con CSS Paged Mediade PrinceXMLes potente, crea un bloqueo de proveedor con CSS específico de Prince que no funcionará en ningún otro sitio:

CSS de PrinceXML:

@page {
    size: A4;
    margin: 2cm;
    @top-center {
        content: "Document Title";
    }
    @bottom-right {
        content: counter(page);
    }
}

/* Prince-specific extensions */
prince-pdf-page-label: "Chapter " counter(chapter);
prince-pdf-destination: attr(id);

IronPDF C# (equivalente):

renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 56;    // ~2cm
renderer.RenderingOptions.MarginBottom = 56;
renderer.RenderingOptions.MarginLeft = 56;
renderer.RenderingOptions.MarginRight = 56;

renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = "<div style='text-align:center;'>Document Title</div>",
    MaxHeight = 40
};

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = "<div style='text-align:right;'>Page {page} of {total-pages}</div>",
    MaxHeight = 25
};
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 56;    // ~2cm
renderer.RenderingOptions.MarginBottom = 56;
renderer.RenderingOptions.MarginLeft = 56;
renderer.RenderingOptions.MarginRight = 56;

renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = "<div style='text-align:center;'>Document Title</div>",
    MaxHeight = 40
};

renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
    HtmlFragment = "<div style='text-align:right;'>Page {page} of {total-pages}</div>",
    MaxHeight = 25
};
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
renderer.RenderingOptions.MarginTop = 56    ' ~2cm
renderer.RenderingOptions.MarginBottom = 56
renderer.RenderingOptions.MarginLeft = 56
renderer.RenderingOptions.MarginRight = 56

renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
    .HtmlFragment = "<div style='text-align:center;'>Document Title</div>",
    .MaxHeight = 40
}

renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
    .HtmlFragment = "<div style='text-align:right;'>Page {page} of {total-pages}</div>",
    .MaxHeight = 25
}
$vbLabelText   $csharpLabel

Problemas comunes de migración de CSS

Cuestión 1: La @página CSS no funciona

IronPDF utiliza Chromium, que tiene una compatibilidad limitada con @page. Convertir reglas CSS en RenderingOptions.

Asunto 2: Faltan cuadros de margen de página

Los cuadros de margen CSS (@top-center, @bottom-right) son específicos de Prince. Utilice HtmlFooter en su lugar.

Asunto 3: string-set/content no funciona

La propiedad CSS string-set es específica de Prince. Utilice el marcador de posición {html-title} de la etiqueta <title>:

<title>Chapter 1: Introduction</title>
<title>Chapter 1: Introduction</title>
HTML
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = "<div>{html-title}</div>"
};
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
    HtmlFragment = "<div>{html-title}</div>"
};
$vbLabelText   $csharpLabel

Edición 4: contador (páginas) incorrecto

Utilice el marcador de posición {total-pages} deIronPDFen lugar de contadores CSS.


Comparación de prestaciones

Operación PrinceXML IronPDF
HTML sencillo ~400ms ~300ms
CSS complejo ~600ms ~400ms
Páginas de JavaScript Limitado ~500ms
Documentos de gran tamaño ~1500ms ~1000ms
Concurrente (10) ~4000ms ~1500ms
Sobrecarga inicial ~200ms ~50ms

Nuevas capacidades tras la migración

Después de migrar a IronPDF, obtendrá capacidades que PrinceXMLno puede proporcionar:

Fusión de PDF

var pdf1 = PdfDocument.FromFile("chapter1.pdf");
var pdf2 = PdfDocument.FromFile("chapter2.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("complete_book.pdf");
var pdf1 = PdfDocument.FromFile("chapter1.pdf");
var pdf2 = PdfDocument.FromFile("chapter2.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("complete_book.pdf");
Dim pdf1 = PdfDocument.FromFile("chapter1.pdf")
Dim pdf2 = PdfDocument.FromFile("chapter2.pdf")
Dim merged = PdfDocument.Merge(pdf1, pdf2)
merged.SaveAs("complete_book.pdf")
$vbLabelText   $csharpLabel

Marcas de agua

pdf.ApplyWatermark("<h1 style='color:red; opacity:0.3;'>DRAFT</h1>");
pdf.ApplyWatermark("<h1 style='color:red; opacity:0.3;'>DRAFT</h1>");
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

Firmas digitales

var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);
var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);
Dim signature = New PdfSignature("certificate.pfx", "password")
pdf.Sign(signature)
$vbLabelText   $csharpLabel

Relleno de formularios

var pdf = PdfDocument.FromFile("form.pdf");
pdf.Form.GetFieldByName("Name").Value = "John Doe";
pdf.SaveAs("filled_form.pdf");
var pdf = PdfDocument.FromFile("form.pdf");
pdf.Form.GetFieldByName("Name").Value = "John Doe";
pdf.SaveAs("filled_form.pdf");
Dim pdf = PdfDocument.FromFile("form.pdf")
pdf.Form.GetFieldByName("Name").Value = "John Doe"
pdf.SaveAs("filled_form.pdf")
$vbLabelText   $csharpLabel

Resumen comparativo de características

Característica PrinceXML IronPDF
.NET nativo No
Proceso externo Requerido No
Soporte de Async Envoltorio del manual Async/await nativo
CSS Paged Media Se admite A través de RenderingOptions
CSS Grid
Flexbox
JavaScript Limitado ES2024 completo
Generación
Combinar No
Dividir No
Editar No
Marcas de agua Sólo CSS HTML/CSS + API
Firmas digitales No
PDF/A
Cifrado
Formularios No
Paquete NuGet No
Instalación del servidor Requerido No

Conformidad Crea y Crece y Facturae: IronPDF como alternativa a PrinceXML

La Ley Crea y Crece obliga a la factura electrónica B2B en España (a partir de 2027 para grandes empresas, 2028 para el resto). El formato requerido —Facturae XML con perfil CIUS-ES conforme a EN 16931— debe enviarse a través de FACe. PrinceXML no soporta la generación de PDF/A-3 con XML embebido, necesaria para este formato.

IronPDF cubre esta brecha completamente:

Ejemplo: factura VeriFactu con datos fiscales españoles en IronPDF (sin proceso externo)

using IronPdf;

// Sin proceso externo, sin latencia de spawn, sin licencia por servidor
var renderer = new ChromePdfRenderer();
var html = @"
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .cabecera { display: flex; justify-content: space-between; }
        .fiscal { font-size: 11px; color: #555; }
        .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='cabecera'>
        <div>
            <strong>Proveedor Software S.A.</strong><br>
            <span class='fiscal'>NIF: A-12345678 | IBAN: ES91 2100 0418 4502 0005 1332</span>
        </div>
        <div>
            <strong>FACTURA Nº 2026-0101</strong><br>
            <span class='fiscal'>Fecha: 28/05/2026 | Vence: 27/06/2026</span>
        </div>
    </div>
    <table>
        <tr><th>Concepto</th><th>Base</th><th>IVA 21%</th><th>Total</th></tr>
        <tr><td>Licencia IronPDF Enterprise — anual</td><td>2.000,00 €</td><td>420,00 €</td><td>2.420,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]
    </div>
</body>
</html>";

var pdf = renderer.RenderHtmlAsPdf(html);
// Firma PAdES con certificado FNMT-RCM — no disponible en PrinceXML
// pdf.Sign(new PdfSignature("fnmt-rcm-cert.pfx", "password"));
pdf.SaveAs("factura-verifactu-2026-0101.pdf");
using IronPdf;

// Sin proceso externo, sin latencia de spawn, sin licencia por servidor
var renderer = new ChromePdfRenderer();
var html = @"
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <style>
        body { font-family: Arial, sans-serif; margin: 40px; }
        .cabecera { display: flex; justify-content: space-between; }
        .fiscal { font-size: 11px; color: #555; }
        .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='cabecera'>
        <div>
            <strong>Proveedor Software S.A.</strong><br>
            <span class='fiscal'>NIF: A-12345678 | IBAN: ES91 2100 0418 4502 0005 1332</span>
        </div>
        <div>
            <strong>FACTURA Nº 2026-0101</strong><br>
            <span class='fiscal'>Fecha: 28/05/2026 | Vence: 27/06/2026</span>
        </div>
    </div>
    <table>
        <tr><th>Concepto</th><th>Base</th><th>IVA 21%</th><th>Total</th></tr>
        <tr><td>Licencia IronPDF Enterprise — anual</td><td>2.000,00 €</td><td>420,00 €</td><td>2.420,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]
    </div>
</body>
</html>";

var pdf = renderer.RenderHtmlAsPdf(html);
// Firma PAdES con certificado FNMT-RCM — no disponible en PrinceXML
// pdf.Sign(new PdfSignature("fnmt-rcm-cert.pfx", "password"));
pdf.SaveAs("factura-verifactu-2026-0101.pdf");
Imports IronPdf

' Sin proceso externo, sin latencia de spawn, sin licencia por servidor
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; }
        .cabecera { display: flex; justify-content: space-between; }
        .fiscal { font-size: 11px; color: #555; }
        .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='cabecera'>
        <div>
            <strong>Proveedor Software S.A.</strong><br>
            <span class='fiscal'>NIF: A-12345678 | IBAN: ES91 2100 0418 4502 0005 1332</span>
        </div>
        <div>
            <strong>FACTURA Nº 2026-0101</strong><br>
            <span class='fiscal'>Fecha: 28/05/2026 | Vence: 27/06/2026</span>
        </div>
    </div>
    <table>
        <tr><th>Concepto</th><th>Base</th><th>IVA 21%</th><th>Total</th></tr>
        <tr><td>Licencia IronPDF Enterprise — anual</td><td>2.000,00 €</td><td>420,00 €</td><td>2.420,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]
    </div>
</body>
</html>"

Dim pdf = renderer.RenderHtmlAsPdf(html)
' Firma PAdES con certificado FNMT-RCM — no disponible en PrinceXML
' pdf.Sign(New PdfSignature("fnmt-rcm-cert.pfx", "password"))
pdf.SaveAs("factura-verifactu-2026-0101.pdf")
$vbLabelText   $csharpLabel

Tabla de conformidad regulatoria

Requisito PrinceXML IronPDF
VERI*FACTU leyenda CSS3 Sí (CSS Print Media) Sí (Chromium)
QR AEAT renderizado Limitado
Firma XAdES TicketBAI Bizkaia/Gipuzkoa/Araba No
Firma PAdES FNMT-RCM eIDAS No
PDF/A-3 para Facturae/FACe Parcial
Sin proceso externo (integridad VeriFactu) No
Sin licencia por servidor No ($495+)
LOPDGDD procesamiento local Parcial
Crea y Crece B2B XML embebido No

Lista de comprobación de la migración

Pre-Migración

  • Identificar todas las invocaciones de la línea de comandos de Prince
  • Documentar las reglas CSS @page utilizadas
  • Lista de propiedades CSS específicas de Prince (prince-*, string-set)
  • Tenga en cuenta todas las funciones de JavaScriptde Prince
  • Identificar las características PDF utilizadas (cifrado, metadatos)
  • Obtenga la clave de licencia deIronPDFen IronPDF

Cambios de código

  • Eliminar el paquete NuGet PrinceXMLWrapper
  • Instalar el paquete NuGet IronPdf
  • Actualizar las importaciones de espacios de nombres
  • Reemplace la instanciación Prince con ChromePdfRenderer
  • Reemplace prince.Convert() con RenderHtmlFileAsPdf() o RenderHtmlAsPdf()
  • Convertir métodos setter en propiedades RenderingOptions
  • Migrar CSS de @page a RenderingOptions
  • Reemplace los cuadros de margen con HtmlFooter
  • Convertir contadores CSS en marcadores de posición {total-pages}
  • Eliminar el manejo de archivos temporales para cadenas HTML
  • Agregar inicialización de licencia al iniciar la aplicación

Posmigración

  • Probar la conversión de archivos HTML
  • Probar la conversión de cadenas HTML
  • Prueba de conversión de URL
  • Verificar que los tamaños de página coincidan
  • Verificar que los márgenes coincidan
  • Encabezados y pies de página de prueba
  • Verificar números de página
  • Probar el cifrado/seguridad
  • Eliminar la instalación de Prince de los servidores
  • Actualizar scripts de implementación

Contexto regulatorio español: proceso externo y flujos VeriFactu

Para los ISVs españoles, usar PrinceXML en sistemas de facturación VeriFactu presenta riesgos arquitectónicos específicos que IronPDF resuelve.

El problema del proceso externo con VeriFactu

El régimen VeriFactu (Real Decreto-Ley 15/2025) exige que la generación de facturas con leyenda VERI*FACTU se realice con integridad garantizada. PrinceXML introduce tres problemas:

  1. Latencia de proceso: Cada factura requiere lanzar un proceso externo, lo que añade latencia variable e incontrolable en la cadena de generación.
  2. Licencia por servidor: Cada servidor de producción necesita una licencia PrinceXML independiente ($495+). En entornos multi-servidor (balanceo de carga, contenedores), el coste es multiplicado.
  3. Dependencia de instalación: PrinceXML debe instalarse en cada servidor de despliegue. En entornos Docker/Kubernetes para arquitecturas VeriFactu escalables, esto aumenta la complejidad operativa.

Generación local de facturas VeriFactu con IronPDF

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; }
        .factura-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='factura-header'>
        <strong>FACTURA Nº 2026-0001</strong>
        <span>Fecha: 20/05/2026</span>
    </div>
    <table>
        <tr><th>Concepto</th><th>Total</th></tr>
        <tr><td>Licencia software</td><td>1.210,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]
    </div>
</body>
</html>";

// Sin proceso externo — en proceso, sin latencia de spawn
// Sin licencia por servidor — licencia por desarrollador
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("factura-verifactu-2026-0001.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; }
        .factura-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='factura-header'>
        <strong>FACTURA Nº 2026-0001</strong>
        <span>Fecha: 20/05/2026</span>
    </div>
    <table>
        <tr><th>Concepto</th><th>Total</th></tr>
        <tr><td>Licencia software</td><td>1.210,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]
    </div>
</body>
</html>";

// Sin proceso externo — en proceso, sin latencia de spawn
// Sin licencia por servidor — licencia por desarrollador
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("factura-verifactu-2026-0001.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; }
        .factura-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='factura-header'>
        <strong>FACTURA Nº 2026-0001</strong>
        <span>Fecha: 20/05/2026</span>
    </div>
    <table>
        <tr><th>Concepto</th><th>Total</th></tr>
        <tr><td>Licencia software</td><td>1.210,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]
    </div>
</body>
</html>"

' Sin proceso externo — en proceso, sin latencia de spawn
' Sin licencia por servidor — licencia por desarrollador
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("factura-verifactu-2026-0001.pdf")
$vbLabelText   $csharpLabel

Lista de comprobación de conformidad VeriFactu post-migración

  • [ ] Eliminar instalación de PrinceXML de servidores de producción
  • [ ] Implementar leyenda VERI*FACTU en plantillas HTML de facturas
  • [ ] Añadir QR de la AEAT con URL de verificación
  • [ ] Verificar generación en proceso sin proceso externo
  • [ ] Configurar firma TicketBAI XAdES si aplica (Bizkaia, Gipuzkoa, Araba)
  • [ ] Integrar Facturae XML para envío a FACe si procede
  • [ ] Revisar ahorro de coste: licencia IronPDF por desarrollador vs PrinceXML por servidor

Preguntas Frecuentes

¿Por qué PrinceXML es problemático para flujos VeriFactu en producción?

PrinceXML opera como proceso externo con licencia por servidor ($495+). En arquitecturas VeriFactu con balanceo de carga o contenedores, cada servidor requiere su propia licencia. La latencia de proceso externo puede comprometer la integridad de la cadena de generación de facturas requerida por el Real Decreto-Ley 15/2025.

¿Soporta IronPDF las firmas digitales requeridas por TicketBAI en España?

Sí. IronPDF incluye soporte nativo de firmas XAdES para TicketBAI en Bizkaia, Gipuzkoa y Araba, y firmas PAdES conformes con eIDAS usando certificados de la FNMT-RCM (Fábrica Nacional de Moneda y Timbre). PrinceXML no tiene capacidades de firma digital.

¿Cómo mejora IronPDF el cumplimiento LOPDGDD respecto a PrinceXML?

IronPDF procesa completamente en memoria, sin archivos temporales externos ni transferencias de datos. Esto simplifica el cumplimiento de la LOPDGDD supervisada por la AEPD: los datos de NIF/CIF y datos fiscales de clientes permanecen en su infraestructura.

¿Puede IronPDF generar facturas Facturae XML para FACe sin proceso externo?

Sí. IronPDF genera PDF/A-3 con Facturae XML embebido directamente desde C#, sin proceso externo ni herramientas adicionales. Esto cubre los requisitos de la Ley Crea y Crece para factura electrónica B2B enviada a FACe.

¿Cuánto se puede ahorrar eliminando la licencia por servidor de PrinceXML?

PrinceXML cobra $495+ por servidor de producción. En arquitecturas con múltiples servidores (alta disponibilidad, Kubernetes), el coste se multiplica. IronPDF ofrece licencia por desarrollador, sin coste adicional por servidor, lo que puede suponer un ahorro significativo en entornos de producción escalables.

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