Azure HTML a PDF con VeriFactu VERI*FACTU y LOPDGDD en España: Guía IronPDF .NET 10
Para convertir HTML a PDF en Azure Functions se necesita el motor de renderizado Chrome de IronPDF y una configuración adecuada de Azure (nivel B1 como mínimo), lo que permite transformar cualquier contenido HTML (desde simples cadenas hasta páginas con mucho JavaScript) en archivos PDF con píxeles perfectos mientras se manejan las restricciones del espacio aislado de Azure y las limitaciones de GDI+.
Para equipos de desarrollo en España, esta combinación es especialmente relevante para cumplir con la normativa de facturación electrónica VeriFactu (Real Decreto 1007/2023), que exige generar representaciones visuales PDF de las facturas con la leyenda obligatoria VERI*FACTU verificable en la sede electrónica de la AEAT. Desplegar en Azure Spain Central garantiza además la residencia de datos bajo la LOPDGDD y facilita el cumplimiento de Crea y Crece para la facturación B2B.
¿Qué hace que valga la pena aprender a convertir HTML a PDF?
Convertir contenido HTML en documentos PDF en entornos de nube puede ser sorprendentemente desafiante. Si alguna vez intentó implementar un generador de PDF en Azure Functions, probablemente se haya topado con errores misteriosos sobre GDI+ o limitaciones del espacio aislado. The good news? Con IronPDF y la configuración adecuada, puedes convertir cualquier contenido HTML en archivos PDF con píxeles perfectos .
Este tutorial le muestra cómo implementar un convertidor de HTML a PDF listo para producción en Azure Functions usando IronPDF. Aprenderá a manejar todo, desde simples cadenas HTML hasta páginas web con mucho JavaScript, mientras navega por las restricciones ambientales únicas de Azure . Ya sea que esté creando facturas sencillas o informes complejos, al final habrá dominado la conversión de HTML a PDF con IronPDF y Azure.
¿Por qué la conversión de HTML a PDF es un reto en Azure?
Antes de profundizar en la conversión de PDF , comprendamos por qué esta tarea supone un desafío para los desarrolladores en Azure. Los servicios de aplicaciones y sin servidor de Azure se ejecutan dentro de un entorno limitado de seguridad que restringe las operaciones de las que dependen las bibliotecas PDF tradicionales:
- Acceso limitado a GDI+: las llamadas de gráficos de Windows están bloqueadas en los niveles inferiores.
- Limitaciones de representación de fuentes: las fuentes personalizadas y las fuentes SVG enfrentan restricciones.
- Restricciones de memoria: la conversión de HTML a PDF requiere recursos sustanciales.
- Aislamiento de procesos: la ejecución de motores de navegador necesita permisos especiales.
Estas restricciones son más estrictas en el plan de consumo de Azure y en los niveles gratuito/compartido. Es por eso que para una conversión exitosa de HTML a PDF se requiere al menos una suscripción a Azure Basic B1 o Premium. Estos proporcionan los permisos y recursos necesarios para que el motor de renderizado Chrome de IronPDF funcione correctamente. Consulte la guía de implementación de Azure de IronPDF para obtener más información sobre los niveles de alojamiento de Azure y el rendimiento de la representación de PDF .
¿Qué opción de implementación de Azure funciona mejor para la generación de PDF?
Tiene tres opciones de implementación ( Windows , Linux o Contenedor ). Si bien se recomienda Azure Function App Container , cualquier opción funciona bien.
Hoy nos centraremos en el enfoque de contenedor, que proporciona un entorno aislado con una configuración mínima y una compatibilidad mejorada con el motor de renderizado de IronPDF . Para entornos especializados como Azure Government Cloud o Azure China, se aplican los mismos principios: solo hay que ajustar los puntos finales de implementación según corresponda.
¿Por qué IronPDF sobresale en HTML a PDF en Azure?
IronPDF se destaca por sus capacidades de conversión de HTML a PDF en Azure gracias a su motor de renderizado Chrome . No se trata simplemente de un analizador HTML básico: es la misma tecnología que utiliza Google Chrome y que garantiza que sus documentos PDF aparezcan exactamente como lo harían en un navegador moderno.
¿Qué características del motor de renderizado de Chrome son las más importantes?
El motor Chrome aporta importantes ventajas para la conversión de HTML a PDF :
- Compatibilidad completa con CSS3: los estilos CSS modernos se representan perfectamente.
- Ejecución de JavaScript : Soporte completo para renderizado dinámico de JavaScript .
- Representación de fuentes web: las fuentes de Google y los tipos de letra personalizados se muestran correctamente.
- Estándares web modernos: elementos HTML5, gráficos SVG y compatibilidad con Canvas.
Esto significa que puedes tomar cualquier página web moderna (completa con estilo Bootstrap , marcos JavaScript o visualizaciones complejas ) y convertirla a PDF sin problemas de compatibilidad. IronPDF se encarga de ejecutar una instancia de Chrome sin interfaz gráfica en el entorno restringido de Azure. Obtenga más información sobre las capacidades de renderizado en Chrome de IronPDF y el renderizado de PDF con píxeles perfectos .
¿Cómo configurar su entorno Microsoft Azure para HTML a PDF?
Repasemos la configuración de una aplicación de función de Azure optimizada para la conversión de HTML a PDF usando IronPDF.
¿Qué requisitos previos necesito antes de empezar?
Before starting, ensure you have:
- An active Azure subscription
- Visual Studio 2022 or Visual Studio Code
- .NET 6.0 SDK or later (download from Microsoft)
- Azure Functions Core Tools (installation guide)
Para obtener instrucciones de configuración completas específicas para la generación de PDF en Azure Functions, consulte el tutorial de Azure Functions de IronPDF .
¿Cómo creo una aplicación de función de Azure?
- Vaya al Portal de Azure y haga clic en "Crear un recurso".
- Search for "Function App" and click "Create"
-
Configure the basics:
- Seleccione la opción de alojamiento: Elija la que se ajuste a sus necesidades
- Subscription: Select your Azure subscription
- Resource Group: Create new or select existing
- Function App Name: Choose a unique name
-
Publish: Select "Container"
- Region: Choose your preferred location
-
Configure the hosting plan:
-
Click "Create new" under Azure App Service Plan
- Pricing Tier: Select at least B1 (Basic) or higher
- Recuerde: los planes gratuitos, compartidos y de consumo no funcionarán para la representación de PDF.
- Review and create your Function App
¿Cómo instalo IronPDF en mi proyecto?
Primero, cree un nuevo proyecto de Azure Functions en Visual Studio (o cargue uno existente) y agregue el paquete IronPDF :
Install-Package IronPdf #For Windows Deployment
Install-Package IronPdf #For Windows Deployment
Install-Package IronPdf.Linux #For Docker Container deployment (recommended)
Install-Package IronPdf.Linux #For Docker Container deployment (recommended)
Para obtener instrucciones de instalación detalladas, incluida la configuración de paquetes NuGet y consideraciones específicas de la plataforma, visita la guía de instalación de IronPDF .
¿Qué configuraciones son esenciales para Azure?
Configure su archivo .cs de Function App para una conversión óptima de HTML a PDF :
using IronPdf;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
public class HtmlToPdfFunction
{
private readonly ILogger _logger;
public HtmlToPdfFunction(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<HtmlToPdfFunction>();
// Configure IronPDF for Azure
ConfigureIronPdf();
}
private void ConfigureIronPdf()
{
// Set your license key (get a trial key from ___PROTECTED_URL_132___
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Essential Azure configurations
IronPdf.Installation.LinuxAndDockerDependenciesAutoConfig = true;
IronPdf.Installation.ChromeGpuMode = IronPdf.Engines.Chrome.ChromeGpuModes.Disabled;
IronPdf.Installation.CustomDeploymentDirectory = "/tmp";
// Optional: Enable logging for troubleshooting
IronPdf.Logging.Logger.LoggingMode = IronPdf.Logging.Logger.LoggingModes.All;
}
}
using IronPdf;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
public class HtmlToPdfFunction
{
private readonly ILogger _logger;
public HtmlToPdfFunction(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<HtmlToPdfFunction>();
// Configure IronPDF for Azure
ConfigureIronPdf();
}
private void ConfigureIronPdf()
{
// Set your license key (get a trial key from ___PROTECTED_URL_132___
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Essential Azure configurations
IronPdf.Installation.LinuxAndDockerDependenciesAutoConfig = true;
IronPdf.Installation.ChromeGpuMode = IronPdf.Engines.Chrome.ChromeGpuModes.Disabled;
IronPdf.Installation.CustomDeploymentDirectory = "/tmp";
// Optional: Enable logging for troubleshooting
IronPdf.Logging.Logger.LoggingMode = IronPdf.Logging.Logger.LoggingModes.All;
}
}
Imports IronPdf
Imports Microsoft.Azure.Functions.Worker
Imports Microsoft.Azure.Functions.Worker.Http
Imports Microsoft.Extensions.Logging
Public Class HtmlToPdfFunction
Private ReadOnly _logger As ILogger
Public Sub New(loggerFactory As ILoggerFactory)
_logger = loggerFactory.CreateLogger(Of HtmlToPdfFunction)()
' Configure IronPDF for Azure
ConfigureIronPdf()
End Sub
Private Sub ConfigureIronPdf()
' Set your license key (get a trial key from ___PROTECTED_URL_132___
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
' Essential Azure configurations
IronPdf.Installation.LinuxAndDockerDependenciesAutoConfig = True
IronPdf.Installation.ChromeGpuMode = IronPdf.Engines.Chrome.ChromeGpuModes.Disabled
IronPdf.Installation.CustomDeploymentDirectory = "/tmp"
' Optional: Enable logging for troubleshooting
IronPdf.Logging.Logger.LoggingMode = IronPdf.Logging.Logger.LoggingModes.All
End Sub
End Class
¿Cómo convertir cadenas HTML a PDF?
Comencemos con el escenario más común: convertir cadenas HTML directamente a PDF . Este enfoque funciona bien para contenido generado dinámicamente, como facturas , informes o correos electrónicos de confirmación .
¿Cómo realizo una conversión básica de cadenas HTML?
[Function("ConvertHtmlToPdf")]
public async Task<HttpResponseData> ConvertHtmlToPdf(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
_logger.LogInformation("Starting HTML to PDF conversion");
try
{
// Simple HTML invoice example
string htmlContent = @"
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.header { color: #333; border-bottom: 2px solid #0066cc; }
.invoice-details { margin: 20px 0; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }
.total { font-weight: bold; font-size: 1.2em; }
</style>
</head>
<body>
<div class='header'>
<h1>Invoice #12345</h1>
<p>Date: " + DateTime.Now.ToString("yyyy-MM-dd") + @"</p>
</div>
<div class='invoice-details'>
<table>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
</tr>
<tr>
<td>Professional Services</td>
<td>10 hours</td>
<td>$1,000.00</td>
</tr>
<tr>
<td colspan='2' class='total'>Total</td>
<td class='total'>$1,000.00</td>
</tr>
</table>
</div>
</body>
</html>";
// Create Chrome renderer
var renderer = new ChromePdfRenderer();
// Configure rendering options
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 25;
renderer.RenderingOptions.MarginBottom = 25;
renderer.RenderingOptions.MarginLeft = 25;
renderer.RenderingOptions.MarginRight = 25;
// Convert HTML to PDF
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
// Return PDF as response
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
response.Headers.Add("Content-Disposition", "attachment; filename=invoice.pdf");
await response.Body.WriteAsync(pdf.BinaryData);
_logger.LogInformation("PDF generated successfully");
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error generating PDF");
var errorResponse = req.CreateResponse(HttpStatusCode.InternalServerError);
await errorResponse.WriteStringAsync($"Error: {ex.Message}");
return errorResponse;
}
}
[Function("ConvertHtmlToPdf")]
public async Task<HttpResponseData> ConvertHtmlToPdf(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
_logger.LogInformation("Starting HTML to PDF conversion");
try
{
// Simple HTML invoice example
string htmlContent = @"
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.header { color: #333; border-bottom: 2px solid #0066cc; }
.invoice-details { margin: 20px 0; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }
.total { font-weight: bold; font-size: 1.2em; }
</style>
</head>
<body>
<div class='header'>
<h1>Invoice #12345</h1>
<p>Date: " + DateTime.Now.ToString("yyyy-MM-dd") + @"</p>
</div>
<div class='invoice-details'>
<table>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
</tr>
<tr>
<td>Professional Services</td>
<td>10 hours</td>
<td>$1,000.00</td>
</tr>
<tr>
<td colspan='2' class='total'>Total</td>
<td class='total'>$1,000.00</td>
</tr>
</table>
</div>
</body>
</html>";
// Create Chrome renderer
var renderer = new ChromePdfRenderer();
// Configure rendering options
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 25;
renderer.RenderingOptions.MarginBottom = 25;
renderer.RenderingOptions.MarginLeft = 25;
renderer.RenderingOptions.MarginRight = 25;
// Convert HTML to PDF
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
// Return PDF as response
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
response.Headers.Add("Content-Disposition", "attachment; filename=invoice.pdf");
await response.Body.WriteAsync(pdf.BinaryData);
_logger.LogInformation("PDF generated successfully");
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error generating PDF");
var errorResponse = req.CreateResponse(HttpStatusCode.InternalServerError);
await errorResponse.WriteStringAsync($"Error: {ex.Message}");
return errorResponse;
}
}
Imports System
Imports System.Net
Imports System.Threading.Tasks
Imports Microsoft.Azure.Functions.Worker
Imports Microsoft.Azure.Functions.Worker.Http
Imports IronPdf
<Function("ConvertHtmlToPdf")>
Public Class ConvertHtmlToPdfFunction
Private ReadOnly _logger As ILogger
Public Sub New(logger As ILogger)
_logger = logger
End Sub
Public Async Function ConvertHtmlToPdf(
<HttpTrigger(AuthorizationLevel.Function, "post")> req As HttpRequestData,
executionContext As FunctionContext) As Task(Of HttpResponseData)
_logger.LogInformation("Starting HTML to PDF conversion")
Try
' Simple HTML invoice example
Dim htmlContent As String = "
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.header { color: #333; border-bottom: 2px solid #0066cc; }
.invoice-details { margin: 20px 0; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #ddd; }
.total { font-weight: bold; font-size: 1.2em; }
</style>
</head>
<body>
<div class='header'>
<h1>Invoice #12345</h1>
<p>Date: " & DateTime.Now.ToString("yyyy-MM-dd") & "</p>
</div>
<div class='invoice-details'>
<table>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
</tr>
<tr>
<td>Professional Services</td>
<td>10 hours</td>
<td>$1,000.00</td>
</tr>
<tr>
<td colspan='2' class='total'>Total</td>
<td class='total'>$1,000.00</td>
</tr>
</table>
</div>
</body>
</html>"
' Create Chrome renderer
Dim renderer As New ChromePdfRenderer()
' Configure rendering options
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4
renderer.RenderingOptions.MarginTop = 25
renderer.RenderingOptions.MarginBottom = 25
renderer.RenderingOptions.MarginLeft = 25
renderer.RenderingOptions.MarginRight = 25
' Convert HTML to PDF
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
' Return PDF as response
Dim response = req.CreateResponse(HttpStatusCode.OK)
response.Headers.Add("Content-Type", "application/pdf")
response.Headers.Add("Content-Disposition", "attachment; filename=invoice.pdf")
Await response.Body.WriteAsync(pdf.BinaryData)
_logger.LogInformation("PDF generated successfully")
Return response
Catch ex As Exception
_logger.LogError(ex, "Error generating PDF")
Dim errorResponse = req.CreateResponse(HttpStatusCode.InternalServerError)
Await errorResponse.WriteStringAsync($"Error: {ex.Message}")
Return errorResponse
End Try
End Function
End Class
Esto toma la cadena HTML dada y la convierte en un documento PDF de alta calidad, completo con las opciones de representación personalizadas que configuramos usando la clase RenderingOptions.
¿Cómo se ve la salida PDF?

¿Cómo convierto URL a PDF?
Para páginas web existentes o aplicaciones complejas, puedes convertir las URL directamente :
[Function("ConvertUrlToPdf")]
public async Task<HttpResponseData> ConvertUrlToPdf(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
var requestBody = await req.ReadAsStringAsync();
var urlRequest = JsonSerializer.Deserialize<UrlRequest>(requestBody);
try
{
var renderer = new ChromePdfRenderer();
// Configure for web page rendering
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.PrintHtmlBackgrounds = true;
renderer.RenderingOptions.CreatePdfFormsFromHtml = true;
// Enable JavaScript execution (important for dynamic content)
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.RenderDelay = 1000; // Wait for JS to execute
// Convert URL to PDF
var pdf = renderer.RenderUrlAsPdf(urlRequest.Url);
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
await response.Body.WriteAsync(pdf.BinaryData);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error converting URL to PDF");
throw;
}
}
public class UrlRequest
{
public string Url { get; set; }
}
[Function("ConvertUrlToPdf")]
public async Task<HttpResponseData> ConvertUrlToPdf(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
var requestBody = await req.ReadAsStringAsync();
var urlRequest = JsonSerializer.Deserialize<UrlRequest>(requestBody);
try
{
var renderer = new ChromePdfRenderer();
// Configure for web page rendering
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.PrintHtmlBackgrounds = true;
renderer.RenderingOptions.CreatePdfFormsFromHtml = true;
// Enable JavaScript execution (important for dynamic content)
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.RenderDelay = 1000; // Wait for JS to execute
// Convert URL to PDF
var pdf = renderer.RenderUrlAsPdf(urlRequest.Url);
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
await response.Body.WriteAsync(pdf.BinaryData);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error converting URL to PDF");
throw;
}
}
public class UrlRequest
{
public string Url { get; set; }
}
Imports System
Imports System.Net
Imports System.Text.Json
Imports System.Threading.Tasks
Imports IronPdf
Imports Microsoft.Azure.Functions.Worker
Imports Microsoft.Azure.Functions.Worker.Http
Imports Microsoft.Extensions.Logging
<Function("ConvertUrlToPdf")>
Public Class ConvertUrlToPdfFunction
Private ReadOnly _logger As ILogger
Public Sub New(logger As ILogger(Of ConvertUrlToPdfFunction))
_logger = logger
End Sub
Public Async Function ConvertUrlToPdf(
<HttpTrigger(AuthorizationLevel.Function, "post")> req As HttpRequestData,
executionContext As FunctionContext) As Task(Of HttpResponseData)
Dim requestBody As String = Await req.ReadAsStringAsync()
Dim urlRequest As UrlRequest = JsonSerializer.Deserialize(Of UrlRequest)(requestBody)
Try
Dim renderer As New ChromePdfRenderer()
' Configure for web page rendering
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4
renderer.RenderingOptions.PrintHtmlBackgrounds = True
renderer.RenderingOptions.CreatePdfFormsFromHtml = True
' Enable JavaScript execution (important for dynamic content)
renderer.RenderingOptions.EnableJavaScript = True
renderer.RenderingOptions.RenderDelay = 1000 ' Wait for JS to execute
' Convert URL to PDF
Dim pdf = renderer.RenderUrlAsPdf(urlRequest.Url)
Dim response As HttpResponseData = req.CreateResponse(HttpStatusCode.OK)
response.Headers.Add("Content-Type", "application/pdf")
Await response.Body.WriteAsync(pdf.BinaryData)
Return response
Catch ex As Exception
_logger.LogError(ex, "Error converting URL to PDF")
Throw
End Try
End Function
End Class
Public Class UrlRequest
Public Property Url As String
End Class
¿Cómo se ve el resultado de la conversión de URL?

¿Cómo manejar contenido HTML complejo con JavaScript?
Las aplicaciones web modernas dependen en gran medida de JavaScript para representar contenido. Ya sean gráficos , formularios dinámicos o aplicaciones de una sola página, el motor de renderizado de IronPDF los maneja todos.
¿Cómo trabajo con contenido que utiliza mucho JavaScript?
Para este ejemplo, tomaremos un archivo HTML con contenido JavaScript y lo convertiremos a PDF.

[Function("ConvertComplexHtmlToPdf")]
public async Task<HttpResponseData> ConvertComplexHtmlToPdf(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
try
{
// Load complex HTML from file
// [USER TO PROVIDE: complex-dashboard.html with charts and JavaScript]
string complexHtml = File.ReadAllText("Templates/complex-dashboard.html");
var renderer = new ChromePdfRenderer();
// JavaScript-specific configurations
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.WaitFor.JavaScript(3000); // Wait 3 seconds for JS
// Optional: Set the CSS media type for print or screen styles
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
// Set viewport for responsive designs
renderer.RenderingOptions.ViewPortWidth = 1920;
renderer.RenderingOptions.ViewPortHeight = 1080;
var pdf = renderer.RenderHtmlAsPdf(complexHtml);
// Add metadata
pdf.MetaData.Author = "Azure Function";
pdf.MetaData.CreationDate = DateTime.Now;
pdf.MetaData.Title = "Complex Dashboard Report";
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
await response.Body.WriteAsync(pdf.BinaryData);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error with complex HTML conversion");
throw;
}
}
[Function("ConvertComplexHtmlToPdf")]
public async Task<HttpResponseData> ConvertComplexHtmlToPdf(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
try
{
// Load complex HTML from file
// [USER TO PROVIDE: complex-dashboard.html with charts and JavaScript]
string complexHtml = File.ReadAllText("Templates/complex-dashboard.html");
var renderer = new ChromePdfRenderer();
// JavaScript-specific configurations
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.WaitFor.JavaScript(3000); // Wait 3 seconds for JS
// Optional: Set the CSS media type for print or screen styles
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
// Set viewport for responsive designs
renderer.RenderingOptions.ViewPortWidth = 1920;
renderer.RenderingOptions.ViewPortHeight = 1080;
var pdf = renderer.RenderHtmlAsPdf(complexHtml);
// Add metadata
pdf.MetaData.Author = "Azure Function";
pdf.MetaData.CreationDate = DateTime.Now;
pdf.MetaData.Title = "Complex Dashboard Report";
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
await response.Body.WriteAsync(pdf.BinaryData);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error with complex HTML conversion");
throw;
}
}
Imports System
Imports System.IO
Imports System.Net
Imports System.Threading.Tasks
Imports IronPdf
Imports Microsoft.Azure.Functions.Worker
Imports Microsoft.Azure.Functions.Worker.Http
<Function("ConvertComplexHtmlToPdf")>
Public Class ConvertComplexHtmlToPdfFunction
Private ReadOnly _logger As ILogger
Public Sub New(loggerFactory As ILoggerFactory)
_logger = loggerFactory.CreateLogger(Of ConvertComplexHtmlToPdfFunction)()
End Sub
Public Async Function ConvertComplexHtmlToPdf(
<HttpTrigger(AuthorizationLevel.Function, "post")> req As HttpRequestData,
executionContext As FunctionContext) As Task(Of HttpResponseData)
Try
' Load complex HTML from file
' [USER TO PROVIDE: complex-dashboard.html with charts and JavaScript]
Dim complexHtml As String = File.ReadAllText("Templates/complex-dashboard.html")
Dim renderer As New ChromePdfRenderer()
' JavaScript-specific configurations
renderer.RenderingOptions.EnableJavaScript = True
renderer.RenderingOptions.WaitFor.JavaScript(3000) ' Wait 3 seconds for JS
' Optional: Set the CSS media type for print or screen styles
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
' Set viewport for responsive designs
renderer.RenderingOptions.ViewPortWidth = 1920
renderer.RenderingOptions.ViewPortHeight = 1080
Dim pdf = renderer.RenderHtmlAsPdf(complexHtml)
' Add metadata
pdf.MetaData.Author = "Azure Function"
pdf.MetaData.CreationDate = DateTime.Now
pdf.MetaData.Title = "Complex Dashboard Report"
Dim response = req.CreateResponse(HttpStatusCode.OK)
response.Headers.Add("Content-Type", "application/pdf")
Await response.Body.WriteAsync(pdf.BinaryData)
Return response
Catch ex As Exception
_logger.LogError(ex, "Error with complex HTML conversion")
Throw
End Try
End Function
End Class
¿Cómo se ve el contenido de JavaScript en PDF?

¿Cómo manejo gráficos y visualizaciones de datos?
Ahora vamos a convertir un archivo HTML que contiene gráficos :

[Function("ConvertChartToPdf")]
public async Task<HttpResponseData> ConvertChartToPdf(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
try
{
// Load chart template
string chartHtml = File.ReadAllText("Templates/chart-template.html");
// Replace placeholders with actual data
var chartData = await GetChartDataAsync();
chartHtml = chartHtml.Replace("{{CHART_DATA}}", JsonSerializer.Serialize(chartData));
var renderer = new ChromePdfRenderer();
// Ensure charts render completely
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.WaitFor.RenderDelay(2000);
// Set paper orientation for charts
renderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Landscape;
var pdf = renderer.RenderHtmlAsPdf(chartHtml);
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
await response.Body.WriteAsync(pdf.BinaryData);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Chart conversion error");
throw;
}
}
[Function("ConvertChartToPdf")]
public async Task<HttpResponseData> ConvertChartToPdf(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
try
{
// Load chart template
string chartHtml = File.ReadAllText("Templates/chart-template.html");
// Replace placeholders with actual data
var chartData = await GetChartDataAsync();
chartHtml = chartHtml.Replace("{{CHART_DATA}}", JsonSerializer.Serialize(chartData));
var renderer = new ChromePdfRenderer();
// Ensure charts render completely
renderer.RenderingOptions.EnableJavaScript = true;
renderer.RenderingOptions.WaitFor.RenderDelay(2000);
// Set paper orientation for charts
renderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Landscape;
var pdf = renderer.RenderHtmlAsPdf(chartHtml);
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
await response.Body.WriteAsync(pdf.BinaryData);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Chart conversion error");
throw;
}
}
Imports System
Imports System.IO
Imports System.Net
Imports System.Text.Json
Imports System.Threading.Tasks
Imports IronPdf
Imports Microsoft.Azure.Functions.Worker
Imports Microsoft.Azure.Functions.Worker.Http
<Function("ConvertChartToPdf")>
Public Class ChartConverter
Private ReadOnly _logger As ILogger
Public Sub New(logger As ILogger)
_logger = logger
End Sub
Public Async Function ConvertChartToPdf(
<HttpTrigger(AuthorizationLevel.Function, "post")> req As HttpRequestData,
executionContext As FunctionContext) As Task(Of HttpResponseData)
Try
' Load chart template
Dim chartHtml As String = File.ReadAllText("Templates/chart-template.html")
' Replace placeholders with actual data
Dim chartData = Await GetChartDataAsync()
chartHtml = chartHtml.Replace("{{CHART_DATA}}", JsonSerializer.Serialize(chartData))
Dim renderer As New ChromePdfRenderer()
' Ensure charts render completely
renderer.RenderingOptions.EnableJavaScript = True
renderer.RenderingOptions.WaitFor.RenderDelay(2000)
' Set paper orientation for charts
renderer.RenderingOptions.PaperOrientation = IronPdf.Rendering.PdfPaperOrientation.Landscape
Dim pdf = renderer.RenderHtmlAsPdf(chartHtml)
Dim response = req.CreateResponse(HttpStatusCode.OK)
response.Headers.Add("Content-Type", "application/pdf")
Await response.Body.WriteAsync(pdf.BinaryData)
Return response
Catch ex As Exception
_logger.LogError(ex, "Chart conversion error")
Throw
End Try
End Function
Private Async Function GetChartDataAsync() As Task(Of Object)
' Placeholder for actual implementation
Return Await Task.FromResult(New Object())
End Function
End Class
¿Cómo se ve la visualización de gráficos en PDF?

IronPDF mantiene la interactividad original de JavaScript en la salida PDF final.
¿Cómo añadir encabezados y pies de página HTML?
Los PDF profesionales a menudo requieren encabezados y pies de página consistentes en todas las páginas. IronPDF lo hace sencillo con plantillas basadas en HTML para opciones avanzadas de encabezado y pie de página .
¿Cómo creo encabezados y pies de página dinámicos?
[Function("ConvertWithHeaderFooter")]
public async Task<HttpResponseData> ConvertWithHeaderFooter(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
try
{
string mainContent = @"
<html>
<body>
<h1>Annual Report 2024</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit...</p>
</body>
</html>";
var renderer = new ChromePdfRenderer();
// Configure margins to accommodate headers/footers
renderer.RenderingOptions.MarginTop = 45;
renderer.RenderingOptions.MarginBottom = 45;
renderer.RenderingOptions.MarginLeft = 25;
renderer.RenderingOptions.MarginRight = 25;
// HTML Header with merge fields
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
Height = 35,
HtmlFragment = @"
<div style='text-align: center; font-size: 12px; padding: 10px;'>
<div style='float: left;'>Annual Report 2024</div>
<div style='float: right;'>Page {page} of {total-pages}</div>
<div style='clear: both;'></div>
</div>",
DrawDividerLine = true
};
// HTML Footer
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
Height = 30,
HtmlFragment = @"
<div style='text-align: center; font-size: 10px; padding: 5px;'>
<div>Generated on {date} at {time}</div>
<div>© 2024 Your Company. All rights reserved.</div>
</div>",
DrawDividerLine = true
};
var pdf = renderer.RenderHtmlAsPdf(mainContent);
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
await response.Body.WriteAsync(pdf.BinaryData);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Header/Footer conversion error");
throw;
}
}
[Function("ConvertWithHeaderFooter")]
public async Task<HttpResponseData> ConvertWithHeaderFooter(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
try
{
string mainContent = @"
<html>
<body>
<h1>Annual Report 2024</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit...</p>
</body>
</html>";
var renderer = new ChromePdfRenderer();
// Configure margins to accommodate headers/footers
renderer.RenderingOptions.MarginTop = 45;
renderer.RenderingOptions.MarginBottom = 45;
renderer.RenderingOptions.MarginLeft = 25;
renderer.RenderingOptions.MarginRight = 25;
// HTML Header with merge fields
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
Height = 35,
HtmlFragment = @"
<div style='text-align: center; font-size: 12px; padding: 10px;'>
<div style='float: left;'>Annual Report 2024</div>
<div style='float: right;'>Page {page} of {total-pages}</div>
<div style='clear: both;'></div>
</div>",
DrawDividerLine = true
};
// HTML Footer
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
Height = 30,
HtmlFragment = @"
<div style='text-align: center; font-size: 10px; padding: 5px;'>
<div>Generated on {date} at {time}</div>
<div>© 2024 Your Company. All rights reserved.</div>
</div>",
DrawDividerLine = true
};
var pdf = renderer.RenderHtmlAsPdf(mainContent);
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
await response.Body.WriteAsync(pdf.BinaryData);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Header/Footer conversion error");
throw;
}
}
Imports System
Imports System.Net
Imports System.Threading.Tasks
Imports Microsoft.Azure.Functions.Worker
Imports Microsoft.Azure.Functions.Worker.Http
<Function("ConvertWithHeaderFooter")>
Public Class ConvertWithHeaderFooterFunction
Private ReadOnly _logger As ILogger
Public Sub New(loggerFactory As ILoggerFactory)
_logger = loggerFactory.CreateLogger(Of ConvertWithHeaderFooterFunction)()
End Sub
Public Async Function ConvertWithHeaderFooter(
<HttpTrigger(AuthorizationLevel.Function, "post")> req As HttpRequestData,
executionContext As FunctionContext) As Task(Of HttpResponseData)
Try
Dim mainContent As String = "
<html>
<body>
<h1>Annual Report 2024</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit...</p>
</body>
</html>"
Dim renderer As New ChromePdfRenderer()
' Configure margins to accommodate headers/footers
renderer.RenderingOptions.MarginTop = 45
renderer.RenderingOptions.MarginBottom = 45
renderer.RenderingOptions.MarginLeft = 25
renderer.RenderingOptions.MarginRight = 25
' HTML Header with merge fields
renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
.Height = 35,
.HtmlFragment = "
<div style='text-align: center; font-size: 12px; padding: 10px;'>
<div style='float: left;'>Annual Report 2024</div>
<div style='float: right;'>Page {page} of {total-pages}</div>
<div style='clear: both;'></div>
</div>",
.DrawDividerLine = True
}
' HTML Footer
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.Height = 30,
.HtmlFragment = "
<div style='text-align: center; font-size: 10px; padding: 5px;'>
<div>Generated on {date} at {time}</div>
<div>© 2024 Your Company. All rights reserved.</div>
</div>",
.DrawDividerLine = True
}
Dim pdf = renderer.RenderHtmlAsPdf(mainContent)
Dim response = req.CreateResponse(HttpStatusCode.OK)
response.Headers.Add("Content-Type", "application/pdf")
Await response.Body.WriteAsync(pdf.BinaryData)
Return response
Catch ex As Exception
_logger.LogError(ex, "Header/Footer conversion error")
Throw
End Try
End Function
End Class
¿Cómo mejoran los encabezados la salida PDF?

¿Cómo puedo aplicar encabezados personalizados para diferentes rangos de páginas?
public async Task<PdfDocument> CreatePdfWithCustomHeaders(string htmlContent)
{
var renderer = new ChromePdfRenderer();
// First page header (cover page)
renderer.RenderingOptions.FirstPageNumber = 0; // Cover page is page 0
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
Height = 50,
HtmlFragment = "<div style='text-align: center; font-size: 24px;'>Company Logo</div>",
DrawDividerLine = false
};
// Different header for content pages
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
// Apply different headers to specific pages after rendering
for (int i = 1; i < pdf.PageCount; i++)
{
// Add page-specific content if needed
pdf.StampHtml(i, @"
<div style='position: absolute; top: 10px; right: 10px; font-size: 10px;'>
Section " + GetSectionName(i) + @"
</div>");
}
return pdf;
}
private string GetSectionName(int pageNumber)
{
// Logic to determine section based on page number
return pageNumber <= 5 ? "Introduction" : "Main Content";
}
public async Task<PdfDocument> CreatePdfWithCustomHeaders(string htmlContent)
{
var renderer = new ChromePdfRenderer();
// First page header (cover page)
renderer.RenderingOptions.FirstPageNumber = 0; // Cover page is page 0
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
Height = 50,
HtmlFragment = "<div style='text-align: center; font-size: 24px;'>Company Logo</div>",
DrawDividerLine = false
};
// Different header for content pages
var pdf = renderer.RenderHtmlAsPdf(htmlContent);
// Apply different headers to specific pages after rendering
for (int i = 1; i < pdf.PageCount; i++)
{
// Add page-specific content if needed
pdf.StampHtml(i, @"
<div style='position: absolute; top: 10px; right: 10px; font-size: 10px;'>
Section " + GetSectionName(i) + @"
</div>");
}
return pdf;
}
private string GetSectionName(int pageNumber)
{
// Logic to determine section based on page number
return pageNumber <= 5 ? "Introduction" : "Main Content";
}
Imports System.Threading.Tasks
Public Class PdfCreator
Public Async Function CreatePdfWithCustomHeaders(htmlContent As String) As Task(Of PdfDocument)
Dim renderer As New ChromePdfRenderer()
' First page header (cover page)
renderer.RenderingOptions.FirstPageNumber = 0 ' Cover page is page 0
renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
.Height = 50,
.HtmlFragment = "<div style='text-align: center; font-size: 24px;'>Company Logo</div>",
.DrawDividerLine = False
}
' Different header for content pages
Dim pdf = renderer.RenderHtmlAsPdf(htmlContent)
' Apply different headers to specific pages after rendering
For i As Integer = 1 To pdf.PageCount - 1
' Add page-specific content if needed
pdf.StampHtml(i, "
<div style='position: absolute; top: 10px; right: 10px; font-size: 10px;'>
Section " & GetSectionName(i) & "
</div>")
Next
Return pdf
End Function
Private Function GetSectionName(pageNumber As Integer) As String
' Logic to determine section based on page number
Return If(pageNumber <= 5, "Introduction", "Main Content")
End Function
End Class
Esto aplica sus encabezados a rangos de páginas PDF específicos.
¿Cuáles son los casos de uso comunes de HTML a PDF en Azure?
La versatilidad de IronPDF lo hace adecuado para muchos usos:
- Generación de facturas: Convierte plantillas HTML con datos dinámicos.
- Generación de informes: transforme las visualizaciones en archivos PDF compartibles.
- Creación de certificados: Genera certificados personalizados.
- Exportación de documentación: convierte documentos en línea en archivos PDF sin conexión .
- Archivado de correo electrónico: guarde correos electrónicos HTML con el formato intacto.
- Generación de contratos: Crea documentos a partir de plantillas HTML .
- Materiales de marketing: Convierta diseños web en archivos PDF listos para imprimir .
Ejemplo práctico: factura VeriFactu con datos España en Azure Functions
En el contexto español, el caso más exigente es generar facturas electrónicas conformes con VeriFactu que incluyan la leyenda obligatoria VERI*FACTU y el código QR de verificación de la AEAT. A continuación se muestra cómo estructurar el HTML de una factura con datos reales de España (NIF del emisor, formato de importe EUR, IVA 21 %) para renderizarla desde Azure Functions:
[Function("GenerarFacturaVeriFactu")]
public async Task<HttpResponseData> GenerarFactura(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
// Datos de factura con formato España
string nifEmisor = "B-12345678"; // CIF empresa emisora
string nifReceptor = "12345678-A"; // NIF cliente
string importeBase = "1.234,56 €"; // Base imponible con formato ES
string iva21 = "259,26 €"; // IVA 21 %
string total = "1.493,82 €"; // Total factura
string huella = "ABCDEF1234567890..."; // huella SHA-256 encadenada
string htmlFactura = $@"
<!DOCTYPE html>
<html lang='es'>
<head><meta charset='UTF-8'><style>
body {{ font-family: Arial, sans-serif; margin: 40px; }}
.verifactu-legend {{ font-weight: bold; border: 2px solid #c00; padding: 6px; }}
table {{ width: 100%; border-collapse: collapse; }}
th, td {{ padding: 8px; border: 1px solid #ddd; }}
</style></head>
<body>
<h1>Factura Núm. F-2026-0042</h1>
<p><strong>Emisor NIF:</strong> {nifEmisor}</p>
<p><strong>Receptor NIF:</strong> {nifReceptor}</p>
<table>
<tr><th>Concepto</th><th>Base</th><th>IVA 21 %</th><th>Total</th></tr>
<tr><td>Servicios software</td><td>{importeBase}</td>
<td>{iva21}</td><td>{total}</td></tr>
</table>
<p class='verifactu-legend'>VERI*FACTU</p>
<p>Factura verificable en la sede electrónica de la AEAT</p>
<p><small>Huella: {huella}</small></p>
</body></html>";
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
var pdf = renderer.RenderHtmlAsPdf(htmlFactura);
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
response.Headers.Add("Content-Disposition", "attachment; filename=factura-verifactu.pdf");
await response.Body.WriteAsync(pdf.BinaryData);
return response;
}
[Function("GenerarFacturaVeriFactu")]
public async Task<HttpResponseData> GenerarFactura(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext executionContext)
{
// Datos de factura con formato España
string nifEmisor = "B-12345678"; // CIF empresa emisora
string nifReceptor = "12345678-A"; // NIF cliente
string importeBase = "1.234,56 €"; // Base imponible con formato ES
string iva21 = "259,26 €"; // IVA 21 %
string total = "1.493,82 €"; // Total factura
string huella = "ABCDEF1234567890..."; // huella SHA-256 encadenada
string htmlFactura = $@"
<!DOCTYPE html>
<html lang='es'>
<head><meta charset='UTF-8'><style>
body {{ font-family: Arial, sans-serif; margin: 40px; }}
.verifactu-legend {{ font-weight: bold; border: 2px solid #c00; padding: 6px; }}
table {{ width: 100%; border-collapse: collapse; }}
th, td {{ padding: 8px; border: 1px solid #ddd; }}
</style></head>
<body>
<h1>Factura Núm. F-2026-0042</h1>
<p><strong>Emisor NIF:</strong> {nifEmisor}</p>
<p><strong>Receptor NIF:</strong> {nifReceptor}</p>
<table>
<tr><th>Concepto</th><th>Base</th><th>IVA 21 %</th><th>Total</th></tr>
<tr><td>Servicios software</td><td>{importeBase}</td>
<td>{iva21}</td><td>{total}</td></tr>
</table>
<p class='verifactu-legend'>VERI*FACTU</p>
<p>Factura verificable en la sede electrónica de la AEAT</p>
<p><small>Huella: {huella}</small></p>
</body></html>";
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
var pdf = renderer.RenderHtmlAsPdf(htmlFactura);
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "application/pdf");
response.Headers.Add("Content-Disposition", "attachment; filename=factura-verifactu.pdf");
await response.Body.WriteAsync(pdf.BinaryData);
return response;
}
Imports System
Imports System.Net
Imports System.Threading.Tasks
Imports IronPdf
Imports Microsoft.Azure.Functions.Worker
Imports Microsoft.Azure.Functions.Worker.Http
<Function("GenerarFacturaVeriFactu")>
Public Async Function GenerarFactura(
<HttpTrigger(AuthorizationLevel.Function, "post")> req As HttpRequestData,
executionContext As FunctionContext) As Task(Of HttpResponseData)
' Datos de factura con formato España
Dim nifEmisor As String = "B-12345678" ' CIF empresa emisora
Dim nifReceptor As String = "12345678-A" ' NIF cliente
Dim importeBase As String = "1.234,56 €" ' Base imponible con formato ES
Dim iva21 As String = "259,26 €" ' IVA 21 %
Dim total As String = "1.493,82 €" ' Total factura
Dim huella As String = "ABCDEF1234567890..." ' huella SHA-256 encadenada
Dim htmlFactura As String = $"
<!DOCTYPE html>
<html lang='es'>
<head><meta charset='UTF-8'><style>
body {{ font-family: Arial, sans-serif; margin: 40px; }}
.verifactu-legend {{ font-weight: bold; border: 2px solid #c00; padding: 6px; }}
table {{ width: 100%; border-collapse: collapse; }}
th, td {{ padding: 8px; border: 1px solid #ddd; }}
</style></head>
<body>
<h1>Factura Núm. F-2026-0042</h1>
<p><strong>Emisor NIF:</strong> {nifEmisor}</p>
<p><strong>Receptor NIF:</strong> {nifReceptor}</p>
<table>
<tr><th>Concepto</th><th>Base</th><th>IVA 21 %</th><th>Total</th></tr>
<tr><td>Servicios software</td><td>{importeBase}</td>
<td>{iva21}</td><td>{total}</td></tr>
</table>
<p class='verifactu-legend'>VERI*FACTU</p>
<p>Factura verificable en la sede electrónica de la AEAT</p>
<p><small>Huella: {huella}</small></p>
</body></html>"
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4
renderer.RenderingOptions.MarginTop = 20
renderer.RenderingOptions.MarginBottom = 20
Dim pdf = renderer.RenderHtmlAsPdf(htmlFactura)
Dim response = req.CreateResponse(HttpStatusCode.OK)
response.Headers.Add("Content-Type", "application/pdf")
response.Headers.Add("Content-Disposition", "attachment; filename=factura-verifactu.pdf")
Await response.Body.WriteAsync(pdf.BinaryData)
Return response
End Function
Este patrón integra la leyenda VERI*FACTU exigida por el Real Decreto 1007/2023 y el formato de importes español (separador de miles punto, decimal coma). Desplegando este Azure Function en Azure Spain Central, el procesamiento de datos del receptor (NIF, importes) no sale del territorio español, cumpliendo con la LOPDGDD. Para organizaciones sujetas al SII (Suministro Inmediato de Información), la misma función puede generar el PDF de representación y enviar los datos XML a la AEAT en el mismo flujo de trabajo.
¿Cómo manejar problemas comunes específicos de Azure?
Incluso con una configuración adecuada, es posible que encuentre desafíos específicos de Azure. A continuación se presentan problemas comunes y soluciones:
¿Por qué mis fuentes no se representan correctamente?
Problema: Las fuentes personalizadas no se muestran correctamente o no se utilizan las fuentes del sistema.
Soluciones: Los niveles de alojamiento compartido de Azure restringen el acceso a GDI+ necesario para fuentes personalizadas . Asegúrese de utilizar al menos el nivel B1 e incorporar fuentes mediante codificación Base64 .
string htmlWithEmbeddedFont = @"
<style>
@font-face {
font-family: 'CustomFont';
src: url(data:font/woff2;base64,YOUR_BASE64_FONT_HERE) format('woff2');
}
body { font-family: 'CustomFont', Arial, sans-serif; }
</style>";
string htmlWithEmbeddedFont = @"
<style>
@font-face {
font-family: 'CustomFont';
src: url(data:font/woff2;base64,YOUR_BASE64_FONT_HERE) format('woff2');
}
body { font-family: 'CustomFont', Arial, sans-serif; }
</style>";
Dim htmlWithEmbeddedFont As String = "
<style>
@font-face {
font-family: 'CustomFont';
src: url(data:font/woff2;base64,YOUR_BASE64_FONT_HERE) format('woff2');
}
body { font-family: 'CustomFont', Arial, sans-serif; }
</style>"
Para problemas persistentes con fuentes, consulte la guía de solución de problemas de fuentes de IronPDF .
¿Qué causa los errores de configuración "Ejecutar desde el archivo de paquete"?
Problem: IronPDF fails to load dependencies when "Run from package file" is enabled.
Solución: esta opción crea un entorno de solo lectura que impide que IronPDF extraiga los archivos necesarios. Deshabilite esta opción en su configuración de publicación o utilice el paquete IronPdf.Slim , que maneja mejor este escenario.
¿Cómo manejo los problemas de memoria y tiempo de espera?
Problema: Los documentos HTML grandes están provocando tiempos de espera o excepciones de memoria.
Solución: Configure los ajustes de memoria y tiempo de espera adecuados:
// In your Function App configuration
renderer.RenderingOptions.Timeout = 120000; // 2 minutes
renderer.RenderingOptions.RequestContext = new RequestContext
{
MaxResponseContentBufferSize = 100 * 1024 * 1024 // 100MB
};
// In your Function App configuration
renderer.RenderingOptions.Timeout = 120000; // 2 minutes
renderer.RenderingOptions.RequestContext = new RequestContext
{
MaxResponseContentBufferSize = 100 * 1024 * 1024 // 100MB
};
' In your Function App configuration
renderer.RenderingOptions.Timeout = 120000 ' 2 minutes
renderer.RenderingOptions.RequestContext = New RequestContext With {
.MaxResponseContentBufferSize = 100 * 1024 * 1024 ' 100MB
}
Para conocer las configuraciones de tiempo de espera de Azure Functions, consulte la documentación de tiempo de espera de Microsoft . Los desarrolladores también comparten soluciones en la etiqueta Azure Functions de Stack Overflow para manejar el procesamiento de documentos grandes.
Para conocer más escenarios de solución de problemas específicos de la conversión de HTML a PDF en Azure, visite la documentación de solución de problemas de Azure de IronPDF .
¿Cómo optimizo el rendimiento de HTML a PDF?
La conversión de HTML a PDF puede consumir muchos recursos dependiendo de la complejidad del contenido. A continuación se presentan estrategias de optimización clave para Azure Functions:
¿Cuándo debo utilizar retrasos de renderizado para contenido dinámico?
Al trabajar con páginas que utilizan mucho JavaScript, configure los retrasos de renderizado adecuados:
renderer.RenderingOptions.WaitFor.RenderDelay = 500; // Simple pages
renderer.RenderingOptions.WaitFor.RenderDelay = 2000; // Complex JavaScript
renderer.RenderingOptions.WaitFor.RenderDelay = 500; // Simple pages
renderer.RenderingOptions.WaitFor.RenderDelay = 2000; // Complex JavaScript
renderer.RenderingOptions.WaitFor.RenderDelay = 500 ' Simple pages
renderer.RenderingOptions.WaitFor.RenderDelay = 2000 ' Complex JavaScript
¿Cómo gestiono la memoria de forma eficiente?
For high-volume scenarios, properly dispose of resources:
using (var renderer = new ChromePdfRenderer())
{
using (var pdf = renderer.RenderHtmlAsPdf(html))
{
// Process PDF
return pdf.BinaryData;
}
}
using (var renderer = new ChromePdfRenderer())
{
using (var pdf = renderer.RenderHtmlAsPdf(html))
{
// Process PDF
return pdf.BinaryData;
}
}
Imports System
Using renderer As New ChromePdfRenderer()
Using pdf = renderer.RenderHtmlAsPdf(html)
' Process PDF
Return pdf.BinaryData
End Using
End Using
¿Qué estrategias de almacenamiento en caché debo utilizar?
Cache generated PDFs when content doesn't change frequently:
private static readonly MemoryCache _pdfCache = new MemoryCache(new MemoryCacheOptions
{
SizeLimit = 100 // Limit cache size
});
public async Task<byte[]> GetCachedPdf(string cacheKey, string html)
{
if (!_pdfCache.TryGetValue(cacheKey, out byte[] cachedPdf))
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
cachedPdf = pdf.BinaryData;
_pdfCache.Set(cacheKey, cachedPdf, new MemoryCacheEntryOptions
{
Size = 1,
SlidingExpiration = TimeSpan.FromMinutes(10)
});
}
return cachedPdf;
}
private static readonly MemoryCache _pdfCache = new MemoryCache(new MemoryCacheOptions
{
SizeLimit = 100 // Limit cache size
});
public async Task<byte[]> GetCachedPdf(string cacheKey, string html)
{
if (!_pdfCache.TryGetValue(cacheKey, out byte[] cachedPdf))
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
cachedPdf = pdf.BinaryData;
_pdfCache.Set(cacheKey, cachedPdf, new MemoryCacheEntryOptions
{
Size = 1,
SlidingExpiration = TimeSpan.FromMinutes(10)
});
}
return cachedPdf;
}
Imports System
Imports System.Threading.Tasks
Imports Microsoft.Extensions.Caching.Memory
Private Shared ReadOnly _pdfCache As New MemoryCache(New MemoryCacheOptions With {
.SizeLimit = 100 ' Limit cache size
})
Public Async Function GetCachedPdf(cacheKey As String, html As String) As Task(Of Byte())
Dim cachedPdf As Byte() = Nothing
If Not _pdfCache.TryGetValue(cacheKey, cachedPdf) Then
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
cachedPdf = pdf.BinaryData
_pdfCache.Set(cacheKey, cachedPdf, New MemoryCacheEntryOptions With {
.Size = 1,
.SlidingExpiration = TimeSpan.FromMinutes(10)
})
End If
Return cachedPdf
End Function
¿Cuánto cuesta la conversión de HTML a PDF en Azure?
La ejecución de la conversión de HTML a PDF en Azure implica dos componentes de costo:
¿Cuáles son los costos de alojamiento de Azure?
- Nivel básico (B1): nivel inicial para la representación de PDF, adecuado para cargas de trabajo ligeras
- Nivel Estándar (S1): Mejor rendimiento para la generación de PDF normal
- Nivel Premium (P1V2): Recomendado para operaciones de PDF complejas o de gran volumen
Los precios varían según la región y cambian con el tiempo. Consulta esta guía de IronPDF para seleccionar el nivel que mejor se adapte a tus necesidades.
¿Cuáles son las opciones de licencia de IronPDF ?

IronPDF Licensing
IronPDF ofrece varias opciones de licencia :
- Licencia de prueba: Prueba gratuita de 30 días para probar
- Licencia Lite: Un solo desarrollador, un solo proyecto
- Licencia Plus: Equipos pequeños con múltiples proyectos
- Licencia Profesional: Equipos más grandes con derechos de redistribución
- Licencia ilimitada: Implementación en toda la empresa
Visite la página de licencias de IronPDF para obtener comparaciones detalladas de precios y características.
¿Cómo puedo optimizar los costos?
- Implementar el almacenamiento en caché: reducir la generación redundante de PDF
- Procesamiento por lotes: procese varios archivos PDF en una sola ejecución de función
- Utilice el procesamiento basado en colas: distribuya la carga a lo largo del tiempo para evitar necesidades de escalado
¿Qué consideraciones de seguridad y cumplimiento normativo debo tener en cuenta?
Si bien nos hemos centrado en la conversión de HTML a PDF , la seguridad es crucial cuando se manejan archivos PDF confidenciales. Para equipos en España, las consideraciones de cumplimiento van más allá de la seguridad básica:
LOPDGDD y residencia de datos: Los PDFs generados en Azure Functions que contienen datos personales de ciudadanos españoles (facturas con NIF, contratos, expedientes de RRHH) están sujetos a la LOPDGDD. Usar Azure Spain Central garantiza que los datos no abandonen España durante el procesamiento, lo que simplifica la documentación ante la AEPD.
VeriFactu y TicketBAI: Para software de facturación distribuido en España, el Real Decreto 1007/2023 exige que los PDFs de facturas incluyan la leyenda VERI*FACTU y el código QR de la AEAT. Para proveedores del País Vasco, TicketBAI impone requisitos adicionales de firma XAdES. IronPDF puede generar el PDF de representación visual; el sistema de facturación certificado se encarga de la huella encadenada y el envío a la Hacienda foral (Bizkaia, Gipuzkoa o Araba).
eIDAS y firmas PAdES: Los PDFs que deban tener validez legal como documentos firmados requieren firma electrónica PAdES conforme a eIDAS, emitida por un prestador de servicios de confianza como la FNMT-RCM. IronPDF genera el documento base; la firma se aplica con el certificado digital correspondiente.
Para obtener más información sobre seguridad técnica:
Despliegue en Azure Spain Central para equipos en España
Para equipos en España que generan facturas electrónicas, contratos o documentación regulada, el despliegue de IronPDF en Azure Spain Central (región eu-south-2, Madrid) garantiza que los datos personales y documentales no abandonen el territorio español. Esto facilita el cumplimiento de la LOPDGDD y el RGPD, que exigen que los datos personales — datos de clientes en facturas, expedientes de RRHH, contratos — mantengan medidas de seguridad adecuadas durante todo su ciclo de vida, incluido el procesamiento en la nube.
Desde el punto de vista de VeriFactu y la AEAT, desplegar en Azure Spain Central también ayuda a documentar la cadena de custodia técnica del procesamiento de facturas electrónicas dentro de la infraestructura de la UE, lo cual puede ser relevante en auditorías del sistema de facturación bajo el Real Decreto 1007/2023. Para seleccionar esta región al crear tu Azure Function App, elige Spain Central en el desplegable de región del portal de Azure o usa --location spaincentral en la CLI de Azure.
Cumplimiento Crea y Crece: facturación B2B electrónica con IronPDF en Azure
La Ley Crea y Crece establece la obligatoriedad de la facturación electrónica B2B en España en fases a partir de 2027 (empresas con facturación anual superior a 8 millones de euros) y 2028 (resto de autónomos y pymes). Esta normativa, que implementa el estándar EN 16931 mediante la especificación CIUS-ES, exige que los sistemas de facturación puedan generar facturas en formato estructurado e intercambiarlas electrónicamente.
IronPDF en Azure Functions puede complementar este flujo generando la representación PDF legible de la factura estructurada (en Facturae XML o UBL), que debe acompañar al formato electrónico para los receptores que necesiten una copia visual. El despliegue en Azure Spain Central garantiza que tanto el XML como el PDF se procesen dentro del territorio español, sin comprometer la conformidad con la LOPDGDD ni con los requisitos de VERI*FACTU cuando aplique.
¿Cuáles son los puntos clave para una conversión exitosa de HTML a PDF?
Convertir HTML a PDF en Azure no tiene por qué ser complicado. Con el motor de renderizado Chrome de IronPDF y la configuración adecuada de Azure , puede transformar cualquier contenido HTML en archivos PDF profesionales.
Puntos clave para una conversión exitosa de HTML a PDF en Azure:
- Utilice Azure nivel B1 o superior para una representación de PDF confiable.
- Implementar como contenedor para una compatibilidad óptima.
- Configure IronPDF settings specifically for Azure's environment.
- Aproveche los encabezados y pies de página HTML para documentos profesionales.
- Manejar contenido JavaScript con retrasos de renderizado apropiados.
- Implementar almacenamiento en caché y optimización para cargas de trabajo de producción.
IronPDF ofrece más que una simple conversión de HTML a PDF. Este artículo demostró sus capacidades para la manipulación avanzada de PDF y el soporte de imágenes PDF . IronPDF se integra fácilmente en cualquier aplicación que esté desarrollando, incluidas aplicaciones de consola y aplicaciones .NET Core .
¿Está listo para comenzar a convertir HTML a PDF en sus aplicaciones de Azure?
Comience a usar IronPDF en su proyecto hoy con una prueba gratuita.
Pruebe la versión de prueba gratuita de IronPDF para acceder a sus potentes funciones y comenzar a convertir HTML a PDF en sus aplicaciones de Azure hoy mismo.
Para implementaciones de producción, explore las opciones de licencia de IronPDF para encontrar el plan que se ajuste a sus necesidades. Con documentación completa, soporte receptivo y actualizaciones continuas , IronPDF proporciona todo lo que necesita para una conversión confiable de HTML a PDF en Azure Functions y más allá.
Preguntas Frecuentes
¿Cómo se incluye la leyenda VERI*FACTU obligatoria en PDFs generados con IronPDF en Azure?
Incluya el texto literal VERI*FACTU (con asterisco) en el HTML de la factura antes de renderizarla con ChromePdfRenderer. El Real Decreto 1007/2023 exige esta leyenda en las representaciones visuales PDF de facturas VeriFactu. IronPDF preserva fielmente el texto gracias a su motor Chrome, garantizando que la leyenda aparezca exactamente como la requiere la AEAT.
¿Por qué desplegar IronPDF en Azure Spain Central en lugar de otras regiones?
Azure Spain Central (eu-south-2, Madrid) garantiza que los datos personales procesados — NIF de clientes, importes de facturas, datos de contratos — no abandonen el territorio español, cumpliendo la LOPDGDD y el RGPD. Para organizaciones bajo VeriFactu o Crea y Crece, esta elección también facilita documentar la cadena de procesamiento ante la AEAT.
¿Puede IronPDF en Azure Functions generar facturas conformes con Crea y Crece?
Sí. IronPDF puede generar la representación PDF de las facturas estructuradas Facturae (formato XML según EN 16931/CIUS-ES) exigidas por la Ley Crea y Crece. La Azure Function renderiza el HTML de la factura y devuelve el PDF, mientras el sistema de facturación certificado gestiona el XML estructurado y el intercambio electrónico.
¿Qué nivel de Azure se requiere para ejecutar IronPDF con requisitos VeriFactu?
Se requiere al menos el nivel B1 (Basic). Los planes de consumo, gratuito y compartido tienen restricciones de GDI+ que impiden el correcto funcionamiento del motor Chrome de IronPDF. Para cargas de trabajo de facturación de producción con VeriFactu, se recomienda el nivel Premium para evitar arranques en frío y garantizar tiempos de respuesta consistentes.
¿Cómo formatea IronPDF los importes con el estándar España (1.234,56 €)?
IronPDF renderiza el HTML tal como lo recibe, por lo que el formato de importes depende del código C# que genera el HTML. Use string.Format con CultureInfo('es-ES') o formatee manualmente (punto como separador de miles, coma como decimal, símbolo € al final) antes de insertar los valores en la plantilla HTML de la factura.


