IRONSOFTWAREHOME
VIDEOS

Migración de iText a IronPDF bajo VeriFactu: eliminar la exposición AGPL en software de facturación español

Curtis Chau
Curtis Chau
Updated: 19 de julio de 2026

Para el ISV español que usa iText 7 en su software de facturación, 2026 marca un punto de inflexión. La licencia AGPL de iText 7 — que exige publicar el código fuente de toda la aplicación si se distribuye o se presta como servicio — se intersecta con el régimen VeriFactu: la AEAT puede sancionar con hasta €150.000/año a los proveedores de software de facturación no conforme. El componente que genera los PDFs de factura (iText o cualquier alternativa) está en el centro de esa exposición dual.

Esta guía proporciona la ruta de migración completa de iText 7 a IronPDF con foco en las obligaciones del mercado español: generación de facturas con VERI*FACTU y QR de verificación AEAT, firmado PAdES bajo eIDAS con certificados FNMT para TicketBAI (Bizkaia/BATUZ, Gipuzkoa, Araba), archivado PDF/A-3 para Facturae/FACe bajo Crea y Crece, y procesamiento de volumen compatible con el SII.

La exposición AGPL × VeriFactu que hace urgente la migración

La licencia AGPL impone la divulgación del código fuente a cualquier receptor del software o del servicio. Para un ISV de facturación, esto significa:

Si distribuye software de facturación instalable: Cualquier cliente que recibe el producto puede exigir el código fuente completo bajo AGPL — incluyendo los algoritmos de generación de huella encadenada para VeriFactu, la lógica de integración con la AEAT y las rutinas de cálculo fiscal propietarias.

Si presta el servicio de facturación en la nube (SaaS): La AGPL cierra la laguna "ASP loophole" — ofrecer el servicio en red sin distribuir binarios también activa la obligación copyleft. Un SaaS de facturación VeriFactu construido sobre iText 7 AGPL es incompatible con un modelo de negocio propietario.

La intersección con VeriFactu: El régimen VeriFactu sanciona al proveedor del software de facturación — no al usuario final. Si el ISV distribuye software de facturación con iText 7 AGPL sin licencia comercial y sin publicar el código fuente, acumula simultáneamente riesgo de incumplimiento copyleft y riesgo de sanción regulatoria sobre el mismo componente.

La migración a IronPDF elimina el riesgo copyleft: la licencia comercial de IronPDF no impone obligaciones de código abierto sobre el software que lo incorpora.

Cambio de paradigma: de construcción programática a HTML-first

iText 7 requiere construir los documentos PDF con objetos Paragraph, Table, Cell y un sistema de coordenadas propio. IronPDF adopta un paradigma HTML-first: el documento se define en HTML/CSS y el motor Chromium lo renderiza en PDF.

Para el ISV de facturación, este cambio tiene una ventaja concreta: las plantillas de factura con los literales obligatorios VeriFactu (VERI*FACTU, Factura verificable en la sede electrónica de la AEAT) y el código QR de la AEAT se pueden mantener en HTML por el equipo de producto o el departamento de diseño, sin tocar el código C# cada vez que cambia el layout.

Auditoría previa a la migración

Antes de migrar, identificar el alcance del uso de iText en el proyecto:

# En PowerShell — identifica referencias iText en el proyecto
Select-String -Path "**/*.cs" -Pattern "using iText" -Recurse
Select-String -Path "**/*.cs" -Pattern "PdfWriter|PdfDocument|HtmlConverter|PdfMerger" -Recurse
Select-String -Path "**/*.cs" -Pattern "iText\.Signatures|PdfSigner|PrivateKeySignature" -Recurse
PowerShell

Cambio de paquetes NuGet

# Package Manager Console de Visual Studio
Uninstall-Package itext7
Uninstall-Package itext7.pdfhtml
Uninstall-Package iTextSharp

Install-Package IronPdf
PowerShell

Equivalencias API completas: iText 7 → IronPDF

Generación de factura VeriFactu: HTML-first con literales AEAT

// iText 7 AGPL: construcción programática — requiere pdfHTML para HTML-to-PDF
using iText.Html2pdf;

// pdfHTML NO incluido en itext7 base — licencia y paquete separado
using (FileStream htmlSrc  = File.Open("factura.html", FileMode.Open))
using (FileStream pdfDest  = File.Open("factura.pdf",  FileMode.Create))
{
    ConverterProperties props = new ConverterProperties();
    // CSS limitado: no renderiza flexbox ni grid correctamente
    // Los literales VERI*FACTU en HTML pueden no preservarse con fidelidad
    HtmlConverter.ConvertToPdf(htmlSrc, pdfDest, props);
}

// IronPDF: motor Chromium integrado — sin complemento adicional
using IronPdf;

string facturaHtml = @"
<!DOCTYPE html>
<html lang='es'>
<head>
    <style>
        body { font-family: Arial; font-size: 11px; margin: 30px; }
        .encabezado { background: #1a3a5c; color: #fff; padding: 15px; }
        table { width: 100%; border-collapse: collapse; margin: 15px 0; }
        th { background: #2c3e50; color: #fff; padding: 6px; text-align: left; }
        td { padding: 6px; border: 1px solid #ddd; }
        .total-row td { font-weight: bold; background: #f0f0f0; }
        .leyenda-verifactu {
            border: 2px solid #1a3a5c; padding: 10px;
            text-align: center; font-weight: bold;
            margin-top: 20px; font-size: 10px;
        }
        .qr-aeat { float: right; margin-left: 15px; }
    </style>
</head>
<body>
    <div class='encabezado'>
        <h2>FACTURA NÚM. {{NumeroFactura}}</h2>
        <p>{{NombreEmisor}} — NIF: {{NifEmisor}}</p>
        <p>Fecha: {{FechaFactura}} | Hora: {{HoraFactura}}</p>
    </div>

    <table>
        <thead>
            <tr><th>Descripción</th><th>Cant.</th><th>Precio unit.</th><th>IVA %</th><th>Total</th></tr>
        </thead>
        <tbody>{{FilasFactura}}</tbody>
        <tfoot>
            <tr class='total-row'><td colspan='4'>Base imponible</td><td>{{BaseImponible}} €</td></tr>
            <tr class='total-row'><td colspan='4'>IVA ({{TipoIva}} %)</td><td>{{CuotaIva}} €</td></tr>
            <tr class='total-row'><td colspan='4'><strong>TOTAL</strong></td><td><strong>{{TotalFactura}} €</strong></td></tr>
        </tfoot>
    </table>

    <!-- QR AEAT: imagen generada con IronQR apuntando al endpoint de verificación -->
    <img class='qr-aeat' src='data:image/png;base64,{{QrAeatBase64}}'
         width='90' height='90' alt='QR verificación AEAT' />

    <!-- Literales VeriFactu obligatorios — preservar verbatim -->
    <div class='leyenda-verifactu'>
        VERI*FACTU<br/>
        Factura verificable en la sede electrónica de la AEAT
    </div>

    <!-- Huella encadenada (visible en la representación impresa) -->
    <p style='font-size:8px;margin-top:15px;'>
        Huella: {{HuellaEncadenada}}
    </p>
</body>
</html>";

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;

string html = facturaHtml
    .Replace("{{NumeroFactura}}", registro.NumeroFactura)
    .Replace("{{NifEmisor}}", registro.NifEmisor)
    .Replace("{{NombreEmisor}}", registro.NombreEmisor)
    .Replace("{{FechaFactura}}", registro.FechaFactura.ToString("dd/MM/yyyy"))
    .Replace("{{HoraFactura}}", registro.FechaFactura.ToString("HH:mm:ss"))
    .Replace("{{QrAeatBase64}}", qrAeatBase64)
    .Replace("{{HuellaEncadenada}}", registro.HuellaEncadenada);
// ... resto de sustituciones de líneas y totales

using var pdfFactura = renderer.RenderHtmlAsPdf(html);
pdfFactura.SaveAs($"factura_{registro.NumeroFactura}.pdf");
C#

Firma PAdES con certificado FNMT para TicketBAI en los tres territorios vascos

TicketBAI es obligatorio en Bizkaia (con BATUZ), Gipuzkoa y Araba. Cada registro debe ir firmado con XAdES; el PDF de acompañamiento usa PAdES bajo eIDAS. Los certificados válidos son de CA acreditadas como FNMT (Fábrica Nacional de Moneda y Timbre):

// iText 7: firma digital (requiere Bouncy Castle y configuración compleja)
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;

Pkcs12Store ks = new Pkcs12Store(new FileStream("cert_fnmt.pfx", FileMode.Open),
    "password".ToCharArray());
string alias = ks.Aliases.Cast<string>().First(ks.IsKeyEntry);
ICipherParameters pk = ks.GetKey(alias).Key;
X509CertificateEntry[] chain = ks.GetCertificateChain(alias);

using (PdfReader reader = new PdfReader("factura.pdf"))
using (PdfWriter writer = new PdfWriter("factura_firmada.pdf"))
using (PdfDocument pdfDoc = new PdfDocument(reader, writer))
{
    PdfSigner signer = new PdfSigner(pdfDoc, writer, new StampingProperties().UseAppendMode());
    signer.GetSignatureAppearance()
        .SetReason("TicketBAI — Bizkaia BATUZ")
        .SetLocation("Bilbao, Bizkaia");
    IExternalSignature pks = new PrivateKeySignature(pk, "SHA-256");
    signer.SignDetached(pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
}

// IronPDF: PdfSignature — API directa, sin Bouncy Castle
using IronPdf;
using IronPdf.Signing;
using System.Security.Cryptography.X509Certificates;

// Certificado FNMT — gestión segura en producción (Azure Key Vault, HSM)
var certFNMT = new X509Certificate2(
    "cert_fnmt.pfx", "password", X509KeyStorageFlags.Exportable);

var firmaPAdES = new PdfSignature(certFNMT)
{
    SigningContact  = "facturacion@empresa.es",
    SigningLocation = "Bilbao, Bizkaia — TicketBAI/BATUZ",
    SigningReason   = "Factura electrónica TicketBAI — VeriFactu"
};

var pdf = PdfDocument.FromFile("factura.pdf");
pdf.Sign(firmaPAdES);
pdf.SaveAs("factura_firmada_ticketbai.pdf");

La diferencia de complejidad es significativa: iText 7 requiere Bouncy Castle para gestionar el keystore PKCS12 y construir manualmente la cadena de certificados. IronPDF usa directamente X509Certificate2 del runtime .NET.

Fusión de PDFs para facturas con anexos

// iText 7: PdfMerger
using iText.Kernel.Pdf;
using iText.Kernel.Utils;

PdfDocument resultado = new PdfDocument(new PdfWriter("factura_completa.pdf"));
PdfMerger merger = new PdfMerger(resultado);
string[] archivos = { "factura_principal.pdf", "anexo_desglose.pdf" };
foreach (string archivo in archivos)
{
    PdfDocument src = new PdfDocument(new PdfReader(archivo));
    merger.Merge(src, 1, src.GetNumberOfPages());
    src.Close();
}
resultado.Close();

// IronPDF: Merge estático
using IronPdf;

var pdfs = new[] { "factura_principal.pdf", "anexo_desglose.pdf" }
    .Select(PdfDocument.FromFile).ToList();
var fusionado = PdfDocument.Merge(pdfs);
fusionado.SaveAs("factura_completa.pdf");
pdfs.ForEach(p => p.Dispose());

Archivado PDF/A-3 para Facturae + FACe (Crea y Crece)

La ley Crea y Crece obliga a la facturación electrónica B2B. El calendario (>8 M€ en 2027; todos los demás en 2028) implica que los ISVs deben soportar PDF/A-3 con XML Facturae 3.2.2 embebido, conforme con EN 16931 / CIUS-ES:

// iText 7: PDF/A (sin soporte directo para PDF/A-3 con adjuntos en versión base)
// Requiere configuración adicional de PdfOutputIntent

// IronPDF: PDF/A-3B con archivo embebido — más directo
using IronPdf;

var pdf = PdfDocument.FromFile("factura_base.pdf");

// Embeber XML Facturae 3.2.2 firmado con XAdES
byte[] xmlFacturae = File.ReadAllBytes("factura_B12345678_2027001234.xml");
pdf.EmbedFile(xmlFacturae, "factura.xml", "application/xml");

// Convertir a PDF/A-3B — permite adjuntos y es el formato requerido por FACe
pdf.SaveAsPdfA("factura_face_pdfa3b.pdf", PdfAVersions.PdfA3B);

Cifrado bajo LOPDGDD para protección de datos personales

// iText 7: WriterProperties + EncryptionConstants
using iText.Kernel.Pdf;

byte[] ownerPwd = System.Text.Encoding.UTF8.GetBytes("admin-password");
byte[] userPwd  = System.Text.Encoding.UTF8.GetBytes("user-password");

WriterProperties wp = new WriterProperties()
    .SetStandardEncryption(
        userPwd, ownerPwd,
        EncryptionConstants.ALLOW_PRINTING,
        EncryptionConstants.ENCRYPTION_AES_256);

using (PdfDocument pdfDoc = new PdfDocument(new PdfReader("factura.pdf"),
    new PdfWriter("factura_protegida.pdf", wp)))
{
    pdfDoc.Close();
}

// IronPDF: SecuritySettings — más legible
using IronPdf;

var pdfSec = PdfDocument.FromFile("factura.pdf");
pdfSec.SecuritySettings.OwnerPassword = "admin-password";
pdfSec.SecuritySettings.UserPassword  = "user-password";
pdfSec.SecuritySettings.AllowUserPrinting       = IronPdf.Security.PdfPrintSecurity.FullPrintRights;
pdfSec.SecuritySettings.AllowUserCopyPasteContent = false;
pdfSec.SecuritySettings.AllowUserAnnotations     = false;
pdfSec.SaveAs("factura_protegida_lopdgdd.pdf");

Extracción de texto (validación de registros VeriFactu)

// iText 7: PdfTextExtractor
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas.Parser;

using (PdfDocument pdfDoc = new PdfDocument(new PdfReader("factura.pdf")))
{
    for (int i = 1; i <= pdfDoc.GetNumberOfPages(); i++)
    {
        string texto = PdfTextExtractor.GetTextFromPage(pdfDoc.GetPage(i));
        // Validar que VERI*FACTU está presente en el texto extraído
        if (!texto.Contains("VERI*FACTU"))
            throw new InvalidOperationException($"Leyenda VeriFactu ausente en página {i}");
    }
}

// IronPDF: ExtractAllText o acceso por página
using IronPdf;

var pdf = PdfDocument.FromFile("factura.pdf");
string textoCompleto = pdf.ExtractAllText();
if (!textoCompleto.Contains("VERI*FACTU"))
    throw new InvalidOperationException("Leyenda VERI*FACTU no encontrada en el PDF");

Tabla de referencia: mapeo de clases y namespaces

iText 7IronPDFObservación
PdfWriterChromePdfRendererParadigma HTML-first
PdfDocument (escritura)ChromePdfRenderer.RenderHtmlAsPdf()
PdfDocument (lectura)PdfDocument.FromFile()
DocumentHTML template
Paragraph<p>, <h1>, etc. en HTML
Table + Cell<table>, <td> en HTML
PdfReaderPdfDocument.FromFile()
PdfMergerPdfDocument.Merge()
PdfTextExtractorpdf.ExtractAllText()
PdfSigner + Bouncy CastlePdfSignature(X509Certificate2)API más directa
HtmlConverter (pdfHTML)Incluido en ChromePdfRendererSin paquete separado
iText.Kernel.Pdf namespaceIronPdf namespace
iText.Layout namespaceHTML/CSS
iText.Html2Pdf namespaceIronPdf (integrado)
iText.Signatures namespaceIronPdf.Signing
Páginas 1-indexedPáginas 0-indexedCambio crítico en la migración

Rendimiento para SII: generación de alto volumen

El Suministro Inmediato de Información (SII) exige comunicar el detalle de facturas en tiempo casi real a la AEAT. Los ISVs que sirven a empresas con obligación SII deben generar miles de PDFs en el plazo de 4 días hábiles. El patrón recomendado con IronPDF reutiliza el renderer para minimizar la inicialización del motor Chromium:

// Servicio de generación para pipelines de alto volumen (SII / Crea y Crece)
public class ServicioFacturacionVeriFactu
{
    // Instancia estática — inicialización única del motor Chromium
    private static readonly ChromePdfRenderer _renderer = new ChromePdfRenderer
    {
        RenderingOptions = new ChromePdfRenderOptions
        {
            PaperSize        = IronPdf.Rendering.PdfPaperSize.A4,
            EnableJavaScript = false,  // No necesario para facturas HTML estático
            Timeout          = 8000    // 8 segundos por factura
        }
    };

    private readonly IPlantillaService _plantillas;

    public ServicioFacturacionVeriFactu(IPlantillaService plantillas)
    {
        _plantillas = plantillas;
    }

    public async Task<byte[]> GenerarPdfFacturaAsync(RegistroVeriFactu registro)
    {
        // La plantilla incluye literales VERI*FACTU y placeholder de QR AEAT
        string html = await _plantillas.RenderizarFacturaAsync(registro);
        using var pdf = _renderer.RenderHtmlAsPdf(html);
        return pdf.BinaryData;
    }

    public async Task<string> GenerarYFirmarAsync(RegistroVeriFactu registro,
        X509Certificate2 certFNMT, string outputPath)
    {
        byte[] pdfBytes = await GenerarPdfFacturaAsync(registro);
        using var pdf = PdfDocument.FromBytes(pdfBytes);

        var firma = new PdfSignature(certFNMT)
        {
            SigningReason = $"TicketBAI — {registro.ProvinciaVasca}"
        };
        pdf.Sign(firma);
        pdf.SaveAs(outputPath);
        return outputPath;
    }
}

Checklist de migración

  • Reemplazar itext7 y itext7.pdfhtml en el archivo .csproj
  • Instalar IronPdf y configurar la clave de licencia
  • Migrar constructores HTML (HtmlConverter) a ChromePdfRenderer.RenderHtmlAsPdf()
  • Actualizar indexación de páginas: iText 1-indexed → IronPDF 0-indexed
  • Migrar firmas de Bouncy Castle + PdfSigner a PdfSignature(X509Certificate2)
  • Implementar SaveAsPdfA(PdfAVersions.PdfA3B) con EmbedFile() para XML Facturae
  • Validar literales VERI*FACTU y Factura verificable en la sede electrónica de la AEAT en las plantillas HTML
  • Verificar formato español de números (1.234,56 €) en las plantillas
  • Migrar cifrado iText (EncryptionConstants) a IronPDF (SecuritySettings)
  • Ejecutar tests de regresión sobre PDFs de factura generados

Recursos para el mercado español

Inicia tu evaluación técnica con acceso completo 30 días para validar la migración en tu arquitectura VeriFactu.

Por favor nota: iText es una marca registrada de sus respectivos propietarios. Este sitio no está afiliado, patrocinado ni respaldado por iText Group. Todos los nombres de producto, logotipos y marcas son propiedad de sus respectivos dueños. Las comparaciones son a título informativo. IronPDF es un componente de software que se integra dentro de sistemas de facturación; no es en sí mismo un sistema de facturación certificado bajo VeriFactu.
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 estructurados y visualmente atractivos.

...
Leer más

Artículos Relacionados

Key in blue circle

Obtenga su clave de prueba gratuita de 30 días al instante.

Your trial license will be sent to your email address

Sin limitaciones. 100 % desbloqueado. Sin tarjeta de crédito.

bullet_checkedNo se requiere tarjeta de crédito ni creación de cuentaSin limitaciones. 100 % desbloqueado. Sin tarjeta de crédito.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Reserve su Demostración en Vivo gratuita
Booking Badge

Confiado por millones de ingenieros en todo el mundo

Logos de clientes de Iron Software
Obtén tu Consulta Sin Compromiso
Completa el formulario a continuación o envía un correo a sales@ironsoftware.com
Tus detalles siempre serán mantenidos confidenciales.
Confiado por millones de ingenieros en todo el mundo
Logos de clientes de Iron Software
Obtenga su Clave de Prueba de 30 días gratis al instante.
No se requiere tarjeta de crédito ni creación de cuenta