
Cuando tu aplicación React genera PDFs sobre la marcha —una factura que necesita el logo de la empresa, un informe con un gráfico incrustado, un certificado que lleva una firma— tienes que colocar imágenes de mapa de bits en la página de forma programática. El JavaScript puro no puede escribir en la estructura interna de un PDF, y levantar un backend solo para estampar un logo es excesivo para lo que en realidad es una tarea del lado del cliente.
Spire.PDF for JavaScript compila un motor PDF completo a WebAssembly, por lo que tu aplicación React puede crear, editar y guardar PDFs enteramente en el navegador. Los archivos se mueven por un sistema de archivos virtual (VFS) dentro del navegador, por lo que no hay ningún viaje de ida y vuelta a la red. Con PdfImage y el método DrawImage del lienzo de la página, controlas exactamente dónde y con qué tamaño aparece cada imagen.
En este artículo aprenderás a:
- Cargar una imagen en el VFS y convertirla en un objeto
PdfImage - Dibujarla en una página PDF en una posición y tamaño elegidos
- Añadir imágenes tanto a documentos PDF nuevos como existentes
- Escalar, centrar y repetir imágenes en varias páginas
- Provocar la descarga en el navegador del PDF final
¿Por qué generar PDFs en el navegador?
La alternativa habitual es una biblioteca del lado del servidor (iText, PDFBox y similares): el navegador sube los archivos, el servidor los procesa y el resultado regresa. Eso funciona, pero para la inserción de imágenes añade fricción:
- Latencia — cada renderizado espera una ida y vuelta a la red, algo que penaliza en el caso de archivos grandes o conexiones lentas.
- Privacidad — los documentos e imágenes de origen salen del equipo del usuario, un problema para cualquier información sensible.
- Costo — el renderizado de PDF consume mucha CPU y no escala de forma gratuita.
Con Spire.PDF for JavaScript, todo el trabajo se ejecuta en el navegador gracias a WebAssembly. Una vez cargado el módulo WASM, el renderizado es local e instantáneo, el archivo nunca sale del dispositivo y no pagas nada por tiempo de servidor.
Requisitos previos
Este tutorial asume que ya tienes un proyecto React con Spire.PDF for JavaScript instalado y el módulo WASM inicializado. Si no es así, sigue primero la guía Integración de Spire.PDF for JavaScript en un proyecto React.
Necesitarás:
- Los archivos
spire.pdf.base.jsyspire.pdf.base.wasmen la carpetapublicde tu proyecto - El módulo WASM accesible a través de
window.wasmModule.spirepdf - Una imagen para incrustar (PNG, JPEG, etc.) colocada donde el VFS pueda cargarla
Añadir una imagen a un PDF nuevo
El escenario más sencillo: crear un documento PDF nuevo y dibujar una imagen en su primera página. Los pasos principales son:
-
Cargar la imagen en el VFS usando
window.spire.FetchFileToVFS -
Crear un
PdfDocumenty añadir una página en blanco -
Crear un
PdfImagea partir del archivo cargado conPdfImage.FromFile -
Dibujar la imagen en el lienzo de la página con
page.Canvas.DrawImage - Guardar y descargar el resultado
function App() {
const addImageToPdf = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check if the WASM module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the image into VFS
const inputImageName = 'TreePic.png';
await window.spire.FetchFileToVFS(inputImageName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object
let doc = new pdfModule.PdfDocument();
// Add a page
let page = doc.Pages.Add();
// Load the image and scale its display size proportionally
let image = pdfModule.PdfImage.FromFile(inputImageName);
let width = image.Width * 0.6;
let height = image.Height * 0.6;
// Calculate the horizontal center position and set the vertical position
let x = (page.Canvas.ClientSize.Width - width) / 2;
let y = 60;
// Draw the image at the specified position on the page
page.Canvas.DrawImage({ image: image, x: x, y: y, width: width, height: height });
// Define the output file name in PDF format
const outputFileName = 'AddImage.pdf';
// Save as PDF format
doc.SaveToFile({ fileName: outputFileName });
doc.Close();
// Read the generated PDF file from VFS and trigger download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Add Image To PDF</h1>
<button onClick={addImageToPdf}>
Generate
</button>
</div>
);
}
export default App;
Documento PDF generado después de añadir una imagen

Qué hace el código:
-
PdfImage.FromFile(inputImageName)lee la imagen del VFS y crea un objetoPdfImage. Las dimensiones originales en píxeles están disponibles medianteimage.Widthyimage.Height. -
page.Canvas.DrawImage(...)dibuja la imagen en la página. Los parámetrosxeyestablecen la posición de la esquina superior izquierda, ywidthyheightcontrolan el tamaño de visualización. - La imagen se escala al 60% de su tamaño original (
* 0.6) y se centra horizontalmente usando(page.Canvas.ClientSize.Width - width) / 2.
Añadir una imagen a un PDF existente
Añadir una imagen a un documento existente sigue el mismo patrón: la única diferencia es que, en lugar de crear un PdfDocument nuevo, cargas uno desde el VFS y seleccionas la página de destino.
const addImageToExistingPdf = async () => {
const pdfModule = window.wasmModule?.spirepdf;
if (!pdfModule) return;
// Load both the PDF and the image into VFS
await window.spire.FetchFileToVFS('Report.pdf', "", `${process.env.PUBLIC_URL}/data/`);
await window.spire.FetchFileToVFS('Logo.png', "", `${process.env.PUBLIC_URL}/data/`);
// Load the existing PDF
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile('Report.pdf');
// Get the first page (or any page you want)
let page = doc.Pages.get_Item(0);
// Load the image and draw it at the top-right corner
let image = pdfModule.PdfImage.FromFile('Logo.png');
let imgWidth = 80;
let imgHeight = 40;
let x = page.Canvas.ClientSize.Width - imgWidth - 30; // 30pt margin from right edge
let y = 30; // 30pt from top
page.Canvas.DrawImage({ image: image, x: x, y: y, width: imgWidth, height: imgHeight });
// Save and download
const outputFileName = 'ReportWithLogo.pdf';
doc.SaveToFile({ fileName: outputFileName });
doc.Close();
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
Diferencia clave con respecto al ejemplo de documento nuevo: doc.LoadFromFile('Report.pdf') carga un PDF existente en lugar de empezar de cero, y doc.Pages.get_Item(0) obtiene una página del documento cargado. El resto de la lógica de dibujo es idéntica.
Si la página ya contiene una imagen que necesitas cambiar en lugar de superponer una nueva, consulta Reemplazo y eliminación de imágenes de PDF en JavaScript (React).
Escalado y posición
El método DrawImage te da control total sobre dónde y con qué tamaño aparece la imagen. Estos son los patrones más comunes:
Escalado proporcional — multiplica ambas dimensiones por el mismo factor para mantener la relación de aspecto:
let scale = 0.5; // 50% of original size
let width = image.Width * scale;
let height = image.Height * scale;
Ancho fijo, altura automática — establece el ancho y calcula la altura para mantener la relación de aspecto:
let targetWidth = 200;
let width = targetWidth;
let height = image.Height * (targetWidth / image.Width);
Centrado horizontal — coloca la imagen a la misma distancia de los márgenes izquierdo y derecho de la página:
let x = (page.Canvas.ClientSize.Width - width) / 2;
Centrado vertical — coloca la imagen a la misma distancia de la parte superior e inferior de la página:
let y = (page.Canvas.ClientSize.Height - height) / 2;
Posición personalizada — usa coordenadas absolutas (el origen está en la esquina superior izquierda; las unidades son puntos; 1 punto = 1/72 pulgada):
let x = 72; // 1 inch from left
let y = 144; // 2 inches from top
Añadir imágenes a varias páginas
Para añadir la misma imagen (por ejemplo, un logo o una marca de agua) a todas las páginas de un documento, recorre la colección Pages:
const addImageToAllPages = async () => {
const pdfModule = window.wasmModule?.spirepdf;
if (!pdfModule) return;
await window.spire.FetchFileToVFS('Business_Data_Overview.pdf', "", `${process.env.PUBLIC_URL}/data/`);
await window.spire.FetchFileToVFS('Logo.png', "", `${process.env.PUBLIC_URL}/data/`);
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile('Business_Data_Overview.pdf');
let image = pdfModule.PdfImage.FromFile('Logo.png');
let imgWidth = 60;
let imgHeight = 30;
// Loop through all pages and draw the logo in the top-right corner
for (let i = 0; i < doc.Pages.Count; i++) {
let page = doc.Pages.get_Item(i);
let x = page.Canvas.ClientSize.Width - imgWidth - 20;
let y = 20;
page.Canvas.DrawImage({ image: image, x: x, y: y, width: imgWidth, height: imgHeight });
}
const outputFileName = 'AllPagesWithLogo.pdf';
doc.SaveToFile({ fileName: outputFileName });
doc.Close();
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
Este patrón es útil para añadir marcas de agua, logos corporativos o sellos de página de manera uniforme a un documento con varias páginas.
Descargar el resultado
Después de guardar el PDF en el VFS con doc.SaveToFile(), debes leerlo de nuevo y activar la descarga en el navegador. Este patrón de dos pasos —guardar en el VFS y luego leer desde el VFS— se usa en todos los ejemplos de Spire.PDF for JavaScript:
// 1. Save the PDF to the VFS
doc.SaveToFile({ fileName: 'Output.pdf' });
doc.Close();
// 2. Read the file from VFS as a byte array
const fileArray = window.dotnetRuntime.Module.FS.readFile('Output.pdf');
// 3. Create a Blob and trigger download
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'Output.pdf';
a.click();
URL.revokeObjectURL(url);
El mismo patrón se aplica al guardar imágenes (usa type: 'image/png' o type: 'image/jpeg' en el constructor del Blob).
Preguntas frecuentes
¿Cómo controlo con precisión la posición y el tamaño de una imagen?
Los parámetros x e y de DrawImage establecen las coordenadas de la esquina superior izquierda de la imagen (en puntos, donde 1 punto = 1/72 pulgada). Los parámetros width y height definen el tamaño de visualización. Para escalar proporcionalmente, lee image.Width y image.Height y multiplica ambos por el mismo factor. Para centrar horizontalmente, calcula x = (page.Canvas.ClientSize.Width - width) / 2.
¿Puedo añadir varias imágenes a la misma página?
Sí. Llama a page.Canvas.DrawImage(...) una vez por cada imagen, con coordenadas x/y diferentes. Las imágenes se dibujan en el orden en que llamas al método, por lo que las imágenes posteriores aparecen encima de las anteriores si se superponen.
¿Qué formatos de imagen son compatibles?
Spire.PDF for JavaScript admite formatos de mapa de bits comunes, incluyendo PNG, JPEG, BMP y GIF. Usa PdfImage.FromFile(filename) para cargar cualquiera de ellos desde el VFS.
¿Afecta añadir una imagen al contenido existente de la página?
No. DrawImage añade un nuevo objeto de imagen a la página sin modificar el texto, los gráficos ni otras imágenes existentes. La imagen se dibuja encima del contenido existente en las coordenadas especificadas. Para extraer una imagen de un PDF existente y poder reutilizarla en otro lugar, consulta Extracción de imágenes de un PDF en JavaScript (React).