Категория

Как добавить изображения в PDF на JavaScript (React)

2026-09-08 05:56:14 Allen Yang
AI Summarize:
ChatGPT
ChatGPT ✓
Claude ✓
Grok ✓
Perplexity ✓
Quick
Quick
Concise overview
Highlights
Key takeaways
Detailed
Structured explanation
Brief
One sentence summary
Summarize |

A PDF document with an image added using Spire.PDF for JavaScript in a React application

Когда ваше React-приложение создаёт PDF-файлы на лету — счёт-фактуру, на которую нужно поместить логотип компании, отчёт со встроенной диаграммой или сертификат с подписью, — вам приходится программно размещать растровые изображения на странице. Обычный JavaScript не умеет записывать данные во внутреннюю структуру PDF, а поднимать бэкенд только ради добавления логотипа — избыточно для задачи, которая на самом деле решается на клиентской стороне.

Spire.PDF для JavaScript компилирует полноценный PDF-движок в WebAssembly, поэтому ваше React-приложение может создавать, редактировать и сохранять PDF-файлы полностью в браузере. Файлы передаются через встроенную в браузер виртуальную файловую систему (VFS), благодаря чему не требуется сетевой обмен данными. Используя PdfImage и метод DrawImage на холсте страницы, вы управляете точным расположением и размером каждого изображения.

В этой статье вы узнаете, как:

  • Загрузить изображение в VFS и преобразовать его в объект PdfImage
  • Нарисовать его на странице PDF в выбранной позиции и с заданным размером
  • Добавлять изображения как в новые, так и в существующие PDF-документы
  • Масштабировать, центрировать и повторять изображения на нескольких страницах
  • Запустить скачивание готового PDF-файла в браузере

Зачем создавать PDF-файлы в браузере

Обычная альтернатива — серверная библиотека (iText, PDFBox и т. п.): браузер загружает ресурсы на сервер, сервер выполняет рендеринг, а результат возвращается обратно. Такой подход работает, но при встраивании изображений создаёт дополнительные трудности:

  • Задержка — каждый рендер требует обмена данными по сети, что особенно ощутимо для больших файлов или медленных соединений.
  • Конфиденциальность — исходные документы и изображения покидают устройство пользователя, что критично для любых чувствительных данных.
  • Стоимость — рендеринг PDF требует значительных вычислительных ресурсов и не масштабируется бесплатно.

С помощью Spire.PDF для JavaScript вся задача выполняется в браузере через WebAssembly. После загрузки WASM-модуля рендеринг происходит локально и мгновенно, файл не покидает устройство, а серверное время не расходуется.


Предварительные требования

В этом руководстве предполагается, что у вас уже создан React-проект с установленным Spire.PDF для JavaScript и инициализированным WASM-модулем. Если нет, сначала выполните инструкции из статьи Интеграция Spire.PDF для JavaScript в проект React.

Вам понадобятся:

  • Файлы spire.pdf.base.js и spire.pdf.base.wasm в папке public вашего проекта
  • Модуль WASM, доступный через window.wasmModule.spirepdf
  • Изображение, которое нужно встроить (PNG, JPEG и т. д.), расположенное там, откуда VFS сможет его загрузить

Добавление изображения в новый PDF

Самый простой сценарий: создать абсолютно новый PDF-документ и нарисовать изображение на его первой странице. Основные шаги выглядят так:

  1. Загрузите изображение в VFS, используя window.spire.FetchFileToVFS
  2. Создайте объект PdfDocument и добавьте пустую страницу
  3. Создайте объект PdfImage из загруженного файла с помощью PdfImage.FromFile
  4. Нарисуйте изображение на холсте страницы с помощью page.Canvas.DrawImage
  5. Сохраните и скачайте результат
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;

PDF-документ, созданный после добавления изображения

PDF document generated after adding an image

Что делает этот код:

  • PdfImage.FromFile(inputImageName) читает изображение из VFS и создаёт объект PdfImage. Исходные размеры в пикселях доступны через image.Width и image.Height.
  • page.Canvas.DrawImage(...) выводит изображение на страницу. Параметры x и y задают позицию верхнего левого угла, а width и height — размер отображения.
  • Изображение масштабируется до 60% исходного размера (* 0.6) и центрируется по горизонтали с помощью выражения (page.Canvas.ClientSize.Width - width) / 2.

Добавление изображения в существующий PDF

Добавление изображения в существующий документ выполняется по той же схеме — единственное отличие состоит в том, что вместо создания нового PdfDocument вы загружаете документ из VFS и выбираете нужную страницу.

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);
};

Ключевое отличие от примера с новым документом: doc.LoadFromFile('Report.pdf') загружает существующий PDF вместо создания пустого документа, а doc.Pages.get_Item(0) получает страницу из загруженного документа. Вся остальная логика отрисовки идентична.

Если на странице уже есть изображение, которое нужно изменить, а не наложить поверх новое, обратитесь к статье Замена и удаление изображений из PDF на JavaScript (React).


Масштабирование и позиционирование

Метод DrawImage даёт полный контроль над тем, где и в каком размере будет отображаться изображение. Ниже приведены самые частые сценарии:

Пропорциональное масштабирование — умножьте обе стороны на один и тот же коэффициент, чтобы сохранить пропорции:

let scale = 0.5; // 50% of original size
let width = image.Width * scale;
let height = image.Height * scale;

Фиксированная ширина и автоматическая высота — задайте ширину и вычислите высоту, сохранив соотношение сторон:

let targetWidth = 200;
let width = targetWidth;
let height = image.Height * (targetWidth / image.Width);

Центрирование по горизонтали — поместите изображение на одинаковом расстоянии от левого и правого краёв страницы:

let x = (page.Canvas.ClientSize.Width - width) / 2;

Центрирование по вертикали — поместите изображение на одинаковом расстоянии от верхнего и нижнего краёв страницы:

let y = (page.Canvas.ClientSize.Height - height) / 2;

Произвольное положение — используйте абсолютные координаты (начало координат — в верхнем левом углу, единицы измерения — пункты; 1 пункт = 1/72 дюйма):

let x = 72;  // 1 inch from left
let y = 144; // 2 inches from top

Добавление изображений на несколько страниц

Чтобы добавить одинаковое изображение (например, логотип или водяной знак) на каждую страницу документа, выполните перебор коллекции 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);
};

Этот приём удобно использовать для добавления водяных знаков, логотипов компании или штампов на все страницы многостраничного PDF-документа.


Скачивание результата

После сохранения PDF в VFS с помощью doc.SaveToFile() необходимо прочитать его обратно и инициировать скачивание в браузере. Эта двухэтапная схема — сохранение в VFS, затем чтение из VFS — используется во всех примерах Spire.PDF для 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);

Та же схема применяется при сохранении изображений (в конструкторе Blob укажите type: 'image/png' или type: 'image/jpeg').


Часто задаваемые вопросы

Как точно контролировать положение и размер изображения?

Параметры x и y метода DrawImage задают координаты верхнего левого угла изображения (в пунктах, где 1 пункт = 1/72 дюйма). Параметры width и height задают размер отображения. Чтобы масштабировать пропорционально, прочитайте image.Width и image.Height и умножьте оба значения на один и тот же коэффициент. Для центрирования по горизонтали вычислите x = (page.Canvas.ClientSize.Width - width) / 2.

Можно ли добавить на одну страницу несколько изображений?

Да. Вызывайте page.Canvas.DrawImage(...) для каждого изображения по отдельности, задавая разные координаты x/y. Изображения рисуются в том порядке, в котором вы вызываете метод, поэтому при перекрытии последующие изображения будут поверх предыдущих.

Какие форматы изображений поддерживаются?

Spire.PDF для JavaScript поддерживает распространённые растровые форматы: PNG, JPEG, BMP и GIF. Для загрузки любого из них из VFS используйте PdfImage.FromFile(filename).

Влияет ли добавление изображения на существующее содержимое страницы?

Нет. Метод DrawImage добавляет на страницу новый объект изображения, не изменяя существующий текст, графику и другие изображения. Изображение наносится поверх текущего содержимого в указанных координатах. Чтобы извлечь изображение из существующего PDF и использовать его в другом месте, обратитесь к статье Извлечение изображений из PDF на JavaScript (React).


См. также