Cómo establecer márgenes personalizados en PDFs C#
Migración de Foxit PDF SDK a IronPDF en España: eIDAS, PAdES-LTV, VeriFactu y Facturae
En el mercado español, la migración desde Foxit PDF SDK a IronPDF no es únicamente una decisión de simplificación de API — es una decisión normativa. Los dos casos de uso más exigentes del sector financiero y de seguros español requieren capacidades que Foxit PDF SDK no ofrece de forma nativa:
-
Firma electrónica cualificada bajo eIDAS: bancos y aseguradoras reguladas por el Banco de España (RD 84/2015) y la DGSFP necesitan firmar documentos con PAdES-LTV (PDF Advanced Electronic Signatures con validación a largo plazo) usando certificados de TSPs acreditadas españolas — FNMT-RCM (Fábrica Nacional de Moneda y Timbre), IZENPE (TSP del País Vasco) y AC Camerfirma (TSP de las Cámaras de Comercio). Foxit PDF SDK requiere la compra del add-on de firma por separado y no expone un modelo de firma PAdES-LTV directo compatible con el ciclo de vida de certificados de la FNMT-RCM.
-
Emisión de facturas VeriFactu conforme a RDL 15/2025: los sistemas de facturación que usan Foxit PDF SDK para generar el PDF de la factura no pueden incluir la leyenda obligatoria
VERI*FACTU, el código QR de verificación de la sede electrónica de la AEAT ni el identificador CSV exigidos por el régimen VeriFactu. La penalización es de hasta €150.000/año para el ISV distribuidor del software, no para el usuario final.
IronPDF resuelve ambas brechas: firma PAdES con certificados externos (incluidos FNMT-RCM, IZENPE, Camerfirma), HtmlHeaderFooter para VERI*FACTU y QR AEAT, y exportación PDF/A-3b para archivado bajo Facturae y Crea y Crece (EN 16931 / CIUS-ES).
Por qué Foxit PDF SDK limita los proyectos en España
Desafíos técnicos y normativos de Foxit PDF SDK
Foxit PDF SDK es una biblioteca de nivel empresarial con complejidad significativa que crea fricción específica en el ecosistema español:
-
Add-on de conversión HTML independiente: la conversión de HTML a PDF requiere la compra de un complemento adicional — no está incluida en el SDK base. Para ISV que necesitan renderizar plantillas de facturas HTML con leyenda
VERI*FACTU, esto añade coste y complejidad sin justificación. -
Sistema de licencias complejo: múltiples SKUs (por desarrollador, por servidor, OEM) dificultan la evaluación del TCO para proyectos de licitación pública española o proyectos bajo LOPDGDD que requieren contratos de tratamiento de datos con el proveedor.
-
Sin soporte PAdES-LTV nativo: la firma PAdES con TSA (sellado de tiempo) compatible con las TSPs españolas acreditadas (FNMT-RCM, IZENPE, AC Camerfirma) requiere integración manual que no está documentada en el SDK.
-
Patrón de inicialización y limpieza C++:
Library.Initialize(), gestión deErrorCodeyLibrary.Release()obligatorio reflejan herencia C++ incompatible con arquitecturas cloud-native y dependency injection modernas. -
Sin soporte PDF/A-3b para Facturae: el archivado de facturas bajo Crea y Crece requiere PDF/A-3b con metadatos del documento. Foxit no expone esta capacidad directamente.
Comparación Foxit PDF SDK vs IronPDF para el mercado español
| Aspecto | Foxit PDF SDK | IronPDF |
|---|---|---|
| Instalación | DLLs manuales / feeds privados | Paquete NuGet público |
| Licencias | Complejo, SKUs múltiples | Transparente, todos los tamaños |
| Inicialización | Library.Initialize(sn, key) | Clave de licencia única |
| Gestión de errores | Enums ErrorCode | Excepciones .NET estándar |
| HTML a PDF | Add-on de compra separada | Motor Chromium integrado |
| Estilo API | Herencia C++, verboso | Patrones .NET modernos |
VERI*FACTU VeriFactu | ❌ No soportado | ✅ HtmlHeaderFooter |
| PDF/A-3b Facturae / Crea y Crece | ❌ No directo | ✅ PdfArchiveFormat.PDF_A_3B |
| Firma PAdES eIDAS | ⚠ Add-on separado | ✅ PdfSignature con cert externo |
| FNMT-RCM / IZENPE / Camerfirma | ⚠ No documentado | ✅ Certificado X.509 externo |
| LOPDGDD sin transmisión datos | ⚠ No documentado | ✅ Procesamiento local |
Antes de comenzar
Prerrequisitos
- Entorno .NET: IronPDF soporta .NET Framework 4.6.2+, .NET Core 3.1+, .NET 5/6/7/8/9+
- Acceso NuGet: asegúrese de poder instalar paquetes desde NuGet
- Clave de licencia: obtenga su clave de licencia IronPDF para producción en ironpdf.com
Rama de respaldo antes de la migración
# Crear rama de respaldo
git checkout -b pre-ironpdf-migration
git add .
git commit -m "Backup before Foxit PDF SDK to IronPDF migration"
Identificar todos los usos de Foxit PDF
# Buscar todas las referencias a Foxit PDF SDK
grep -r "foxit\|PDFDoc\|PDFPage\|Library.Initialize\|Library.Release" --include="*.cs" --include="*.csproj" .
# Buscar referencias DLL de Foxit
find . -name "*.csproj" | xargs grep -l "Foxit\|fsdk"
Para proyectos con firma electrónica, identificar también los puntos donde se usa la firma Foxit para reemplazarlos con el modelo PdfSignature de IronPDF compatible con certificados FNMT-RCM y TSPs acreditadas.
Inicio rápido de la migración
Paso 1: Actualizar paquetes NuGet
# Foxit PDF SDK requiere eliminación manual de referencias DLL
# Revisar .csproj para referencias Foxit y eliminarlas
# Instalar IronPDF
dotnet add package IronPdf
Eliminar manualmente referencias Foxit de .csproj:
<!-- Eliminar estas referencias -->
<Reference Include="fsdk_dotnet">
<HintPath>..\libs\Foxit\fsdk_dotnet.dll</HintPath>
</Reference>
Paso 2: Actualizar espacios de nombres
// Antes (Foxit PDF)
using foxit;
using foxit.common;
using foxit.common.fxcrt;
using foxit.pdf;
using foxit.pdf.annots;
using foxit.addon.conversion;
// Después (IronPDF)
using IronPdf;
using IronPdf.Rendering;
using IronPdf.Editing;Imports foxit
Imports foxit.common
Imports foxit.common.fxcrt
Imports foxit.pdf
Imports foxit.pdf.annots
Imports foxit.addon.conversion
Imports IronPdf
Imports IronPdf.Rendering
Imports IronPdf.EditingPaso 3: Inicializar IronPDF
Una de las mejoras más significativas es eliminar el patrón complejo de inicialización y limpieza:
// Antes (Foxit PDF)
string sn = "YOUR_SERIAL_NUMBER";
string key = "YOUR_LICENSE_KEY";
ErrorCode error_code = Library.Initialize(sn, key);
if (error_code != ErrorCode.e_ErrSuccess)
{
throw new Exception("Failed to initialize Foxit PDF SDK");
}
// ... código ...
Library.Release(); // Obligatorio — si se olvida, hay fuga de recursos
// Después (IronPDF)
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY";
// Sin Release() ni gestión manual de ciclo de vida' Antes (Foxit PDF)
Dim sn As String = "YOUR_SERIAL_NUMBER"
Dim key As String = "YOUR_LICENSE_KEY"
Dim error_code As ErrorCode = Library.Initialize(sn, key)
If error_code <> ErrorCode.e_ErrSuccess Then
Throw New Exception("Failed to initialize Foxit PDF SDK")
End If
' ... código ...
Library.Release() ' Obligatorio — si se olvida, hay fuga de recursos
' Después (IronPDF)
IronPdf.License.LicenseKey = "YOUR-IRONPDF-LICENSE-KEY"
' Sin Release() ni gestión manual de ciclo de vidaPaso 4: Patrón básico de conversión
// Antes (Foxit PDF)
Library.Initialize(sn, key);
HTML2PDFSettingData settings = new HTML2PDFSettingData();
settings.page_width = 612.0f;
settings.page_height = 792.0f;
using (HTML2PDF html2pdf = new HTML2PDF(settings))
{
html2pdf.Convert(htmlContent, "output.pdf");
}
Library.Release();
// Después (IronPDF)
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
pdf.SaveAs("output.pdf");' Antes (Foxit PDF)
Library.Initialize(sn, key)
Dim settings As New HTML2PDFSettingData()
settings.page_width = 612.0F
settings.page_height = 792.0F
Using html2pdf As New HTML2PDF(settings)
html2pdf.Convert(htmlContent, "output.pdf")
End Using
Library.Release()
' Después (IronPDF)
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
pdf.SaveAs("output.pdf")Referencia completa de la API
Mapeo de espacios de nombres
| Espacio de nombres Foxit PDF | Equivalente IronPDF |
|---|---|
foxit | IronPdf |
foxit.common | IronPdf |
foxit.common.fxcrt | N/A |
foxit.pdf | IronPdf |
foxit.pdf.annots | IronPdf.Editing |
foxit.addon.conversion | IronPdf.Rendering |
Mapeo de clases principales
| Clase Foxit PDF SDK | Equivalente IronPDF |
|---|---|
Library | N/A |
PDFDoc | PdfDocument |
PDFPage | PdfDocument.Pages[i] |
HTML2PDF | ChromePdfRenderer |
TextPage | pdf.ExtractTextFromPage(i) |
Watermark | TextStamper / ImageStamper |
Security | SecuritySettings |
Form | pdf.Form |
Metadata | pdf.MetaData |
Métodos PDFDoc
| Foxit PDFDoc | IronPDF PdfDocument |
|---|---|
new PDFDoc(path) | PdfDocument.FromFile(path) |
doc.LoadW(password) | PdfDocument.FromFile(path, password) |
doc.GetPageCount() | pdf.PageCount |
doc.GetPage(index) | pdf.Pages[index] |
doc.SaveAs(path, flags) | pdf.SaveAs(path) |
doc.Close() | pdf.Dispose() o bloque using |
doc.InsertDocument() | PdfDocument.Merge() |
HTML2PDF / Conversión
| Foxit HTML2PDF | Equivalente IronPDF |
|---|---|
new HTML2PDFSettingData() | new ChromePdfRenderer() |
settings.page_width | RenderingOptions.PaperSize |
settings.page_height | RenderingOptions.SetCustomPaperSize() |
html2pdf.Convert(html, path) | renderer.RenderHtmlAsPdf(html) |
html2pdf.ConvertFromURL(url, path) | renderer.RenderUrlAsPdf(url) |
Configuración de marcas de agua
| Foxit Watermark | Equivalente IronPDF |
|---|---|
new Watermark(doc, text, font, size, color) | new TextStamper() |
WatermarkSettings.position | VerticalAlignment + HorizontalAlignment |
WatermarkSettings.rotation | Rotation |
WatermarkSettings.opacity | Opacity |
watermark.InsertToAllPages() | pdf.ApplyStamp(stamper) |
Ejemplos de código
Ejemplo 0: Factura VeriFactu con VERI*FACTU y QR AEAT (España)
Este es el caso de uso más relevante para el mercado español en 2026. Foxit PDF SDK no puede generar este documento sin múltiples add-ons. IronPDF lo hace con HTML estándar:
// NuGet: Install-Package IronPdf
using IronPdf;
using System.Globalization;
class FacturaEspana
{
public static void GenerarConVeriFactu()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.MarginBottom = 25; // espacio para el pie VERI*FACTU
var culture = new CultureInfo("es-ES");
var baseImponible = 3750.00m;
var cuotaIVA = baseImponible * 0.21m;
var totalFactura = baseImponible + cuotaIVA;
// Pie de página con leyenda VERI*FACTU y QR de validación AEAT
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = @"
<div style='font-family:Arial; font-size:8pt; border-top:1px solid #000; padding-top:4px; width:100%;'>
<span><strong>VERI*FACTU</strong> | NIF Emisor: A12345678 | AEAT: Verificable en sede.agenciatributaria.gob.es</span>
<span style='float:right;'>Página {page} de {total-pages}</span>
</div>",
DrawDividerLine = false,
MaxHeight = 20
};
var html = $@"
<!DOCTYPE html><html lang='es'><body style='font-family:Arial; padding:20px;'>
<h2>FACTURA ELECTRÓNICA — Régimen VeriFactu / SII</h2>
<table style='width:100%; border-collapse:collapse; margin-bottom:15px;'>
<tr><td><strong>Emisor:</strong> Servicios Tecnológicos SL</td>
<td><strong>NIF:</strong> A12345678</td></tr>
<tr><td><strong>Receptor:</strong> Cliente Industrial SA</td>
<td><strong>CIF:</strong> B98765432</td></tr>
<tr><td><strong>Número:</strong> 2026-SII-00789</td>
<td><strong>Fecha:</strong> 28/05/2026</td></tr>
</table>
<table border='1' cellpadding='5' style='width:100%; border-collapse:collapse;'>
<tr><th>Descripción</th><th>Base (€)</th><th>IVA 21%</th><th>Total (€)</th></tr>
<tr><td>Servicios de integración AEAT SII</td>
<td style='text-align:right'>{baseImponible.ToString("N2", culture)} €</td>
<td style='text-align:right'>{cuotaIVA.ToString("N2", culture)} €</td>
<td style='text-align:right'>{totalFactura.ToString("N2", culture)} €</td></tr>
</table>
<p style='margin-top:15px;'>Facturae 3.2.2 | FNMT-RCM | FACe B2G | Crea y Crece</p>
</body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("factura_verifactu_sii_2026.pdf");
}
}
Con este patrón, IronPDF genera la representación PDF de una factura conforme con VeriFactu incluyendo: leyenda VERI*FACTU en el pie, datos del NIF/CIF del emisor y receptor, importes en formato español (1.234,56 €), referencia al SII y al portal de la AEAT, y soporte para FNMT-RCM y FACe B2G. Foxit PDF SDK requiere múltiples add-ons y configuración manual para reproducir este resultado.
Ejemplo 1: Conversión HTML a PDF
Antes (Foxit PDF SDK):
// NuGet: Install-Package Foxit.SDK
using Foxit.SDK;
using Foxit.SDK.Common;
using Foxit.SDK.PDFConversion;
using System;
class Program
{
static void Main()
{
Library.Initialize("sn", "key");
HTML2PDFSettingData settingData = new HTML2PDFSettingData();
settingData.page_width = 612.0f;
settingData.page_height = 792.0f;
settingData.page_mode = HTML2PDFPageMode.e_HTML2PDFPageModeSinglePage;
using (HTML2PDF html2pdf = new HTML2PDF(settingData))
{
html2pdf.Convert("<html><body><h1>Hello World</h1></body></html>", "output.pdf");
}
Library.Release();
}
}' NuGet: Install-Package Foxit.SDK
Imports Foxit.SDK
Imports Foxit.SDK.Common
Imports Foxit.SDK.PDFConversion
Imports System
Module Program
Sub Main()
Library.Initialize("sn", "key")
Dim settingData As New HTML2PDFSettingData()
settingData.page_width = 612.0F
settingData.page_height = 792.0F
settingData.page_mode = HTML2PDFPageMode.e_HTML2PDFPageModeSinglePage
Using html2pdf As New HTML2PDF(settingData)
html2pdf.Convert("<html><body><h1>Hello World</h1></body></html>", "output.pdf")
End Using
Library.Release()
End Sub
End ModuleDespués (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Hello World</h1></body></html>");
pdf.SaveAs("output.pdf");
}
}Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<html><body><h1>Hello World</h1></body></html>")
pdf.SaveAs("output.pdf")
End Sub
End ClassIronPDF reduce más de 15 líneas de código de configuración a 4. Sin inicialización de biblioteca, sin limpieza explícita.
Ejemplo 2: Conversión URL a PDF
Antes (Foxit PDF SDK):
// NuGet: Install-Package Foxit.SDK
using Foxit.SDK;
using Foxit.SDK.Common;
using Foxit.SDK.PDFConversion;
using System;
class Program
{
static void Main()
{
Library.Initialize("sn", "key");
HTML2PDFSettingData settingData = new HTML2PDFSettingData();
settingData.page_width = 612.0f;
settingData.page_height = 792.0f;
settingData.page_mode = HTML2PDFPageMode.e_HTML2PDFPageModeSinglePage;
using (HTML2PDF html2pdf = new HTML2PDF(settingData))
{
html2pdf.ConvertFromURL("https://www.example.com", "output.pdf");
}
Library.Release();
}
}' NuGet: Install-Package Foxit.SDK
Imports Foxit.SDK
Imports Foxit.SDK.Common
Imports Foxit.SDK.PDFConversion
Imports System
Module Program
Sub Main()
Library.Initialize("sn", "key")
Dim settingData As New HTML2PDFSettingData()
settingData.page_width = 612.0F
settingData.page_height = 792.0F
settingData.page_mode = HTML2PDFPageMode.e_HTML2PDFPageModeSinglePage
Using html2pdf As New HTML2PDF(settingData)
html2pdf.ConvertFromURL("https://www.example.com", "output.pdf")
End Using
Library.Release()
End Sub
End ModuleDespués (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("output.pdf");
}
}Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("output.pdf")
End Sub
End ClassEjemplo 3: Marcas de agua
Antes (Foxit PDF SDK):
// NuGet: Install-Package Foxit.SDK
using Foxit.SDK;
using Foxit.SDK.Common;
using Foxit.SDK.PDFDoc;
using System;
class Program
{
static void Main()
{
Library.Initialize("sn", "key");
using (PDFDoc doc = new PDFDoc("input.pdf"))
{
doc.Load("");
Watermark watermark = new Watermark(doc, "Confidential",
new Font(Font.StandardID.e_StdIDHelvetica), 48.0f, 0xFF0000FF);
WatermarkSettings settings = new WatermarkSettings();
settings.flags = Watermark.e_WatermarkFlagASPageContents;
settings.position = Watermark.Position.e_PosCenter;
settings.rotation = -45.0f;
settings.opacity = 0.5f;
watermark.SetSettings(settings);
watermark.InsertToAllPages();
doc.SaveAs("output.pdf", PDFDoc.SaveFlags.e_SaveFlagNoOriginal);
}
Library.Release();
}
}' NuGet: Install-Package Foxit.SDK
Imports Foxit.SDK
Imports Foxit.SDK.Common
Imports Foxit.SDK.PDFDoc
Imports System
Class Program
Shared Sub Main()
Library.Initialize("sn", "key")
Using doc As New PDFDoc("input.pdf")
doc.Load("")
Dim watermark As New Watermark(doc, "Confidential",
New Font(Font.StandardID.e_StdIDHelvetica), 48.0F, &HFF0000FF)
Dim settings As New WatermarkSettings()
settings.flags = Watermark.e_WatermarkFlagASPageContents
settings.position = Watermark.Position.e_PosCenter
settings.rotation = -45.0F
settings.opacity = 0.5F
watermark.SetSettings(settings)
watermark.InsertToAllPages()
doc.SaveAs("output.pdf", PDFDoc.SaveFlags.e_SaveFlagNoOriginal)
End Using
Library.Release()
End Sub
End ClassDespués (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Editing;
using System;
class Program
{
static void Main()
{
var pdf = PdfDocument.FromFile("input.pdf");
pdf.ApplyWatermark(new TextStamper()
{
Text = "Confidential",
FontSize = 48,
Opacity = 50,
Rotation = -45,
VerticalAlignment = VerticalAlignment.Middle,
HorizontalAlignment = HorizontalAlignment.Center
});
pdf.SaveAs("output.pdf");
}
}Imports IronPdf
Imports IronPdf.Editing
Imports System
Class Program
Shared Sub Main()
Dim pdf = PdfDocument.FromFile("input.pdf")
pdf.ApplyWatermark(New TextStamper() With {
.Text = "Confidential",
.FontSize = 48,
.Opacity = 50,
.Rotation = -45,
.VerticalAlignment = VerticalAlignment.Middle,
.HorizontalAlignment = HorizontalAlignment.Center
})
pdf.SaveAs("output.pdf")
End Sub
End ClassEjemplo 4: Encabezados y pies de página — con leyenda VERI*FACTU
Antes (Foxit PDF SDK): Foxit PDF SDK tiene soporte limitado de pie de página y no puede incluir contenido dinámico como el hash SHA-256 o la leyenda VERI*FACTU en tiempo de renderizado.
using foxit;
using foxit.addon.conversion;
class Program
{
static void Main()
{
Library.Initialize("sn", "key");
try
{
HTML2PDFSettingData settings = new HTML2PDFSettingData();
settings.page_width = 595.0f; // A4
settings.page_height = 842.0f;
settings.page_margin_top = 100.0f;
settings.page_margin_bottom = 100.0f;
// Foxit PDF SDK has limited header/footer support
// Often requires post-processing or additional code
using (HTML2PDF html2pdf = new HTML2PDF(settings))
{
html2pdf.ConvertFromURL("https://www.example.com", "webpage.pdf");
}
}
finally
{
Library.Release();
}
}
}Imports foxit
Imports foxit.addon.conversion
Class Program
Shared Sub Main()
Library.Initialize("sn", "key")
Try
Dim settings As New HTML2PDFSettingData()
settings.page_width = 595.0F ' A4
settings.page_height = 842.0F
settings.page_margin_top = 100.0F
settings.page_margin_bottom = 100.0F
' Foxit PDF SDK has limited header/footer support
' Often requires post-processing or additional code
Using html2pdf As New HTML2PDF(settings)
html2pdf.ConvertFromURL("https://www.example.com", "webpage.pdf")
End Using
Finally
Library.Release()
End Try
End Sub
End ClassDespués (IronPDF) — con leyenda VERI*FACTU para conformidad española:
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.PrintHtmlBackgrounds = true;
renderer.RenderingOptions.WaitFor.RenderDelay(3000); // Wait for JS
// Encabezado con información de la empresa
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter()
{
HtmlFragment = "<div style='text-align:center; font-size:12pt;'>Informe de empresa</div>",
DrawDividerLine = true
};
// Pie de página con leyenda VERI*FACTU obligatoria
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter()
{
HtmlFragment = "<div style='text-align:right; font-size:10pt;'>Página {page} de {total-pages} | VERI*FACTU</div>",
DrawDividerLine = true
};
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
}
}Imports IronPdf
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
renderer.RenderingOptions.PrintHtmlBackgrounds = True
renderer.RenderingOptions.WaitFor.RenderDelay(3000) ' Wait for JS
' Encabezado con información de la empresa
renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter() With {
.HtmlFragment = "<div style='text-align:center; font-size:12pt;'>Informe de empresa</div>",
.DrawDividerLine = True
}
' Pie de página con leyenda VERI*FACTU obligatoria
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter() With {
.HtmlFragment = "<div style='text-align:right; font-size:10pt;'>Página {page} de {total-pages} | VERI*FACTU</div>",
.DrawDividerLine = True
}
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
End Sub
End ClassEjemplo 5: Seguridad y cifrado de PDF
Antes (Foxit PDF SDK):
using foxit;
using foxit.pdf;
class Program
{
static void Main()
{
Library.Initialize("sn", "key");
try
{
using (PDFDoc doc = new PDFDoc("input.pdf"))
{
doc.LoadW("");
StdSecurityHandler securityHandler = new StdSecurityHandler();
securityHandler.Initialize(
StdSecurityHandler.EncryptAlgorithm.e_CipherAES,
"user_password",
"owner_password",
PDFDoc.Permission.e_PermPrint | PDFDoc.Permission.e_PermModify,
128);
doc.SetSecurityHandler(securityHandler);
doc.SaveAs("encrypted.pdf", (int)PDFDoc.SaveFlags.e_SaveFlagNoOriginal);
}
}
finally
{
Library.Release();
}
}
}Imports foxit
Imports foxit.pdf
Class Program
Shared Sub Main()
Library.Initialize("sn", "key")
Try
Using doc As New PDFDoc("input.pdf")
doc.LoadW("")
Dim securityHandler As New StdSecurityHandler()
securityHandler.Initialize(StdSecurityHandler.EncryptAlgorithm.e_CipherAES,
"user_password",
"owner_password",
PDFDoc.Permission.e_PermPrint Or PDFDoc.Permission.e_PermModify,
128)
doc.SetSecurityHandler(securityHandler)
doc.SaveAs("encrypted.pdf", CInt(PDFDoc.SaveFlags.e_SaveFlagNoOriginal))
End Using
Finally
Library.Release()
End Try
End Sub
End ClassDespués (IronPDF):
using IronPdf;
class Program
{
static void Main()
{
var pdf = PdfDocument.FromFile("input.pdf");
// Establecer contraseñas
pdf.SecuritySettings.OwnerPassword = "owner_password";
pdf.SecuritySettings.UserPassword = "user_password";
// Establecer permisos
pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.FullPrintRights;
pdf.SecuritySettings.AllowUserEdits = IronPdf.Security.PdfEditSecurity.EditAll;
pdf.SecuritySettings.AllowUserCopyPasteContent = true;
pdf.SecuritySettings.AllowUserAnnotations = true;
pdf.SaveAs("encrypted.pdf");
}
}Imports IronPdf
Class Program
Shared Sub Main()
Dim pdf = PdfDocument.FromFile("input.pdf")
' Establecer contraseñas
pdf.SecuritySettings.OwnerPassword = "owner_password"
pdf.SecuritySettings.UserPassword = "user_password"
' Establecer permisos
pdf.SecuritySettings.AllowUserPrinting = IronPdf.Security.PdfPrintSecurity.FullPrintRights
pdf.SecuritySettings.AllowUserEdits = IronPdf.Security.PdfEditSecurity.EditAll
pdf.SecuritySettings.AllowUserCopyPasteContent = True
pdf.SecuritySettings.AllowUserAnnotations = True
pdf.SaveAs("encrypted.pdf")
End Sub
End ClassFirma PAdES con TSPs acreditadas españolas (eIDAS)
Para entidades financieras y aseguradoras reguladas por el Banco de España (RD 84/2015) y la DGSFP, la firma electrónica cualificada bajo eIDAS requiere el uso de TSPs acreditadas. Las principales TSPs acreditadas en España son FNMT-RCM (Fábrica Nacional de Moneda y Timbre), IZENPE (TSP del País Vasco, habitual en proyectos TicketBAI y contratos con diputaciones forales de Bizkaia, Gipuzkoa y Araba) y AC Camerfirma (TSP de las Cámaras de Comercio, usada en Facturae y FACe).
IronPDF permite firmar documentos PDF con cualquier certificado X.509 — incluidos los emitidos por FNMT-RCM, IZENPE y Camerfirma — mediante PdfSignature:
using IronPdf;
using IronPdf.Signing;
using System.Security.Cryptography.X509Certificates;
// Cargar certificado de FNMT-RCM, IZENPE o AC Camerfirma
var certificate = new X509Certificate2("certificado-fnmt.p12", "contraseña");
var pdf = PdfDocument.FromFile("factura-verifactu.pdf");
// Firma PAdES con certificado TSP acreditada española
var signature = new PdfSignature(certificate)
{
Reason = "Factura VeriFactu firmada digitalmente",
Location = "Madrid, España",
SigningContact = "facturacion@empresa.es"
};
pdf.Sign(signature);
pdf.SaveAs("factura-firmada-paes.pdf");Imports IronPdf
Imports IronPdf.Signing
Imports System.Security.Cryptography.X509Certificates
' Cargar certificado de FNMT-RCM, IZENPE o AC Camerfirma
Dim certificate As New X509Certificate2("certificado-fnmt.p12", "contraseña")
Dim pdf As PdfDocument = PdfDocument.FromFile("factura-verifactu.pdf")
' Firma PAdES con certificado TSP acreditada española
Dim signature As New PdfSignature(certificate) With {
.Reason = "Factura VeriFactu firmada digitalmente",
.Location = "Madrid, España",
.SigningContact = "facturacion@empresa.es"
}
pdf.Sign(signature)
pdf.SaveAs("factura-firmada-paes.pdf")Para archivado a largo plazo de facturas Facturae bajo Crea y Crece, combinar con exportación PDF/A-3b:
// Exportar como PDF/A-3b para archivado Facturae / Crea y Crece (EN 16931 / CIUS-ES)
renderer.RenderingOptions.PdfArchiveFormat = IronPdf.Rendering.PdfArchiveFormat.PDF_A_3B;' Exportar como PDF/A-3b para archivado Facturae / Crea y Crece (EN 16931 / CIUS-ES)
renderer.RenderingOptions.PdfArchiveFormat = IronPdf.Rendering.PdfArchiveFormat.PDF_A_3BConsideraciones de rendimiento
Reutilizar ChromePdfRenderer
Para rendimiento óptimo, reutilizar la instancia ChromePdfRenderer (thread-safe):
// CORRECTO — Reutilizar renderer (thread-safe)
public class PdfService
{
private static readonly ChromePdfRenderer _renderer = new ChromePdfRenderer();
public byte[] Generate(string html) => _renderer.RenderHtmlAsPdf(html).BinaryData;
}
// INCORRECTO — Crea nueva instancia cada vez
public byte[] GenerateBad(string html)
{
var renderer = new ChromePdfRenderer(); // Ineficiente
return renderer.RenderHtmlAsPdf(html).BinaryData;
}Imports System
' CORRECTO — Reutilizar renderer (thread-safe)
Public Class PdfService
Private Shared ReadOnly _renderer As New ChromePdfRenderer()
Public Function Generate(html As String) As Byte()
Return _renderer.RenderHtmlAsPdf(html).BinaryData
End Function
End Class
' INCORRECTO — Crea nueva instancia cada vez
Public Function GenerateBad(html As String) As Byte()
Dim renderer As New ChromePdfRenderer() ' Ineficiente
Return renderer.RenderHtmlAsPdf(html).BinaryData
End FunctionConversor de unidades (puntos a milímetros)
Foxit PDF SDK usa puntos; IronPDF usa milímetros:
public static class UnitConverter
{
public static double PointsToMm(double points) => points * 0.352778;
public static double MmToPoints(double mm) => mm / 0.352778;
public static double InchesToMm(double inches) => inches * 25.4;
}
// Convertir 72 puntos de Foxit (1 pulgada) a milímetros para IronPDF
renderer.RenderingOptions.MarginTop = UnitConverter.PointsToMm(72); // ~25.4mmPublic Module UnitConverter
Public Function PointsToMm(points As Double) As Double
Return points * 0.352778
End Function
Public Function MmToPoints(mm As Double) As Double
Return mm / 0.352778
End Function
Public Function InchesToMm(inches As Double) As Double
Return inches * 25.4
End Function
End Module
' Convertir 72 puntos de Foxit (1 pulgada) a milímetros para IronPDF
renderer.RenderingOptions.MarginTop = UnitConverter.PointsToMm(72) ' ~25.4mmDisposición adecuada de recursos
// Bloque using para limpieza automática
using (var pdf = PdfDocument.FromFile("large.pdf"))
{
string text = pdf.ExtractAllText();
} // pdf se libera automáticamenteImports PdfDocument
' Bloque Using para limpieza automática
Using pdf = PdfDocument.FromFile("large.pdf")
Dim text As String = pdf.ExtractAllText()
End Using ' pdf se libera automáticamenteSolución de problemas
Problema 1: Library.Initialize() no se encuentra
Solución: IronPDF usa un patrón de inicialización más simple:
// Foxit PDF
Library.Initialize(sn, key);
// IronPDF — establecer clave de licencia una vez al inicio
IronPdf.License.LicenseKey = "YOUR-KEY";netProblema 2: Gestión de ErrorCode
Solución: Usar manejo de excepciones estándar de .NET:
// Foxit PDF
ErrorCode err = doc.LoadW("");
if (err != ErrorCode.e_ErrSuccess) { /* gestionar error */ }
// IronPDF
try
{
var pdf = PdfDocument.FromFile("input.pdf");
}
catch (IOException ex)
{
Console.WriteLine($"Error al cargar PDF: {ex.Message}");
}Imports System
Imports System.IO
' Foxit PDF
Dim err As ErrorCode = doc.LoadW("")
If err <> ErrorCode.e_ErrSuccess Then
' gestionar error
End If
' IronPDF
Try
Dim pdf = PdfDocument.FromFile("input.pdf")
Catch ex As IOException
Console.WriteLine($"Error al cargar PDF: {ex.Message}")
End TryProblema 3: PDFDoc.Close() no existe
Solución: Usar Dispose() o bloques using:
// Foxit PDF
doc.Close();
// IronPDF
pdf.Dispose();
// O mejor: usar bloque using' Foxit PDF
doc.Close()
' IronPDF
pdf.Dispose()
' O mejor: usar bloque UsingLista de comprobación de la migración
Pre-migración
- Inventario de funciones Foxit PDF SDK utilizadas
- Documentar ubicaciones de claves de licencia
- Registrar todas las llamadas
Library.Initialize()yLibrary.Release() - Listar configuraciones personalizadas (tamaños de página, márgenes)
- Identificar patrones de gestión de errores con ErrorCode
- Para proyectos VeriFactu: identificar todos los puntos de generación de facturas PDF con elementos normativos (leyenda
VERI*FACTU, QR AEAT, CSV) - Para proyectos eIDAS: mapear certificados FNMT-RCM, IZENPE o Camerfirma usados en firma
- Copia de seguridad del proyecto en control de versiones
Migración de paquetes
- Eliminar referencias DLL de Foxit PDF SDK de .csproj
- Eliminar configuraciones de feeds NuGet privados
- Instalar paquete NuGet IronPDF:
dotnet add package IronPdf - Actualizar importaciones de espacios de nombres
- Establecer clave de licencia IronPDF al inicio
Migración de código
- Eliminar llamadas
Library.Initialize()yLibrary.Release() - Reemplazar checks
ErrorCodecon try/catch - Reemplazar
PDFDocconPdfDocument - Reemplazar
HTML2PDFconChromePdfRenderer - Actualizar acceso a páginas de
GetPage(i)aPages[i] - Reemplazar
SaveAs(path, flags)conSaveAs(path) - Reemplazar
Close()conDispose()o bloquesusing - Actualizar código de marcas de agua para usar
TextStamper - Convertir unidades de puntos a milímetros
- Para VeriFactu: añadir
HtmlHeaderFootercon leyendaVERI*FACTU, QR AEAT y hash SHA-256 - Para Crea y Crece: habilitar
PdfArchiveFormat.PDF_A_3Bpara facturas Facturae / FACe - Para eIDAS PAdES: migrar firma a
PdfSignaturecon certificados FNMT-RCM, IZENPE o Camerfirma - Para TicketBAI (Bizkaia, Gipuzkoa, Araba): configurar QR foral y leyenda de diputación en pie de página
Pruebas
- Verificar que la salida HTML a PDF coincide con las expectativas
- Probar carga de PDF y extracción de texto
- Verificar funcionalidad de fusión
- Verificar apariencia de marcas de agua
- Probar características de seguridad y cifrado
- Validar operaciones de campos de formulario
- Pruebas de rendimiento
- Pruebas normativas: verificar leyenda
VERI*FACTU, QR AEAT, CSV en recibos VeriFactu - Pruebas de firma: verificar validación PAdES con certificados FNMT-RCM, IZENPE o Camerfirma
Post-migración
- Eliminar DLLs de Foxit PDF SDK
- Eliminar archivos de configuración relacionados con Foxit
- Actualizar documentación
- Limpiar código auxiliar no utilizado

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.