Get and Replace PDF Fonts in React with JavaScript

2026-10-22 09:35:06 Written by  Nina Tang
Rate this item
(0 votes)

The same PDF can look different when opened on different machines: if the font a document references is not installed locally, the viewer substitutes another one. Conversely, when brand standards or legal requirements say an outgoing file may only use specified fonts, you first need to know which fonts the original uses. Common browser-side PDF libraries mostly draw pages; they do not expose font resources.

This article uses Spire.PDF for JavaScript to read and replace the fonts in a PDF: first list the document's fonts with PdfDocument.UsedFonts, then replace the standard and non-embedded TrueType fonts with a new TrueType font via PdfUsedFont.Replace(). Everything runs in the browser; files are read and written through a virtual file system (VFS) and never uploaded to a server.

This article covers two core features:

For installation and project configuration, see Integrate Spire.PDF for JavaScript in a React Project. The examples below assume Spire.PDF is installed and the WebAssembly module is initialized.


Get the Fonts Used in a PDF

Spire.PDF for JavaScript provides the PdfDocument.UsedFonts property for reading every font used in a document. Each item in the collection is a PdfUsedFont, whose Name, Size, Style, and Type give the font name, size, style, and font type.

The steps are:

  1. Get the Spire.PDF WASM module and confirm it is ready.
  2. Load the sample PDF into the VFS, create a PdfDocument object, and load the file.
  3. Read PdfDocument.UsedFonts and take each PdfUsedFont from the collection.
  4. Put together each font's name, size, style, and type, and write them to a text file.
  5. Read the result file from the VFS and trigger a browser download.

The code for getting the fonts in a PDF is as follows:

function App() {
  const getFonts = async () => {
    // Get the Spire.PDF WASM module
    const pdfModule = window.wasmModule?.spirepdf;

    // Check whether the module is ready
    if (!pdfModule) {
      alert('Spire.PDF is not ready yet');
      return;
    }

    // Load the sample PDF into the VFS
    const inputFileName = 'Font_Sample.pdf';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);

    // Create a PdfDocument object and load the document
    const doc = new pdfModule.PdfDocument();
    doc.LoadFromFile(inputFileName);

    // UsedFonts lists the fonts the document currently uses
    const fonts = doc.UsedFonts;

    const styleNames = new Map([
      [pdfModule.PdfFontStyle.Regular.value, 'Regular'],
      [pdfModule.PdfFontStyle.Bold.value, 'Bold'],
      [pdfModule.PdfFontStyle.Italic.value, 'Italic'],
      [pdfModule.PdfFontStyle.Underline.value, 'Underline'],
      [pdfModule.PdfFontStyle.Strikeout.value, 'Strikeout'],
    ]);
    const typeNames = new Map([
      [pdfModule.PdfFontType.Standard.value, 'Standard'],
      [pdfModule.PdfFontType.TrueType.value, 'TrueType'],
      [pdfModule.PdfFontType.TrueTypeEmbedded.value, 'Embedded TrueType'],
    ]);

    // Collect each font's name, size, style, and type
    let report = `Document: ${inputFileName}\r\nFont count: ${fonts.length}\r\n\r\n`;
    for (let i = 0; i < fonts.length; i++) {
      const font = fonts.get(i);
      report += `${i + 1}. ${font.Name}\r\n`;
      report += `   Size: ${font.Size}\r\n`;
      report += `   Style: ${styleNames.get(font.Style.value)}\r\n`;
      report += `   Type: ${typeNames.get(font.Type.value)}\r\n\r\n`;
    }

    // Write the font list into the VFS
    const outputFileName = 'FontList.txt';
    window.dotnetRuntime.Module.FS.writeFile(outputFileName, report);
    doc.Close();

    // Read the result file from the VFS and trigger the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'text/plain;charset=utf-8' });
    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>Get the Fonts Used in a PDF</h1>
      <button onClick={getFonts}>
        Get fonts
      </button>
    </div>
  );
}

export default App;

The font list is written to a text file, listing each font's name, size, style, and type:

The font list is written to a text file, listing each font's name, size, style, and type


Replace the Fonts Used in a PDF

Spire.PDF for JavaScript also provides the PdfUsedFont.Replace() method, which swaps one font in a document for another font object. It works only with standard Type1 fonts and non-embedded TrueType fonts; embedded fonts (such as subset-embedded CJK fonts) cannot be replaced and must be skipped.

The steps are:

  1. Get the Spire.PDF WASM module and confirm it is ready.
  2. Load the sample PDF and the replacement font file into the VFS, with the font file placed under /Library/Fonts/.
  3. Create a PdfDocument object, load the PDF, and read PdfDocument.UsedFonts.
  4. Create a PdfTrueTypeFont object, iterate over UsedFonts, skip embedded fonts, and call PdfUsedFont.Replace() on standard and non-embedded TrueType fonts.
  5. Save the result with PdfDocument.SaveToFile() and trigger a browser download.

The code for replacing the fonts in a PDF is as follows:

function App() {
  const replaceFonts = async () => {
    // Get the Spire.PDF WASM module
    const pdfModule = window.wasmModule?.spirepdf;

    // Check whether the module is ready
    if (!pdfModule) {
      alert('Spire.PDF is not ready yet');
      return;
    }

    // Load the replacement font and the sample PDF
    await window.spire.FetchFileToVFS('ARIALUNI.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'Font_Sample.pdf';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/data/`);

    // Create a PdfDocument object and load the document
    const doc = new pdfModule.PdfDocument();
    doc.LoadFromFile(inputFileName);

    // UsedFonts returns the fonts used in the document
    const fonts = doc.UsedFonts;
    const newFont = new pdfModule.PdfTrueTypeFont({
      fontFamily: 'Arial Unicode MS',
      size: 12,
      style: pdfModule.PdfFontStyle.Regular,
      unicode: true
    });

    // Replace one by one: Replace() supports only standard Type1 and non-embedded TrueType fonts
    for (let i = 0; i < fonts.length; i++) {
      const font = fonts.get(i);
      // Embedded fonts cannot be replaced; skip them
      if (font.Type.value === pdfModule.PdfFontType.TrueTypeEmbedded.value) {
        continue;
      }
      font.Replace(newFont);
    }

    // Save the result file
    const outputFileName = 'ReplacedFonts.pdf';
    doc.SaveToFile(outputFileName);
    doc.Close();

    // Read the generated file from the VFS and trigger the 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>Replace the Fonts Used in a PDF</h1>
      <button onClick={replaceFonts}>
        Replace fonts
      </button>
    </div>
  );
}

export default App;

After replacement, the text in the standard font uses the new TrueType font while embedded fonts stay unchanged:

After replacement, the text in the standard font uses the new TrueType font while embedded fonts stay unchanged


FAQ

Why do the text size and style change after replacement

Reason: Replace() takes a complete font object, and replacement applies the new object's own size and style; the original sizes of individual text runs are not preserved.

Solution: Set the target font's size and style to the values you want in the result. For example, to make everything 12 pt regular, pass size: 12 and style: PdfFontStyle.Regular to PdfTrueTypeFont.

Why do Chinese or Japanese characters turn into boxes or question marks after replacement

Reason: The target font has no glyphs for those characters, or PdfTrueTypeFont was created without Unicode enabled.

Solution: Use a font that covers the target language (such as Arial Unicode MS) and pass unicode: true when creating it. The font file must first be loaded into /Library/Fonts/ in the VFS so Spire.PDF can embed it.

Can I replace only one of the fonts

Reason: UsedFonts lists each font in the document, and Replace() acts on a single PdfUsedFont.

Solution: Check Name while iterating and replace only the matching font:

for (let i = 0; i < fonts.length; i++) {
  const font = fonts.get(i);
  if (font.Name === 'ArialMT') {
    font.Replace(newFont);
  }
}

Font names of subset-embedded fonts may carry prefixes such as BCDEEE+, so write the comparison against the Name you actually read from the list.

Why does Replace() report that the font is not a standard Type 1 or non-embedded TrueType font

Reason: PdfUsedFont.Replace() only works on standard Type1 fonts and non-embedded TrueType fonts. CJK fonts in PDFs are often subset-embedded TrueType fonts (UsedFonts reports them as Embedded TrueType), and Spire.PDF cannot replace them directly.

Solution: Check Type while iterating UsedFonts and call Replace() only on standard and non-embedded TrueType fonts; skip the rest, or prepare a document that uses standard or non-embedded fonts first.


Get a Free License

To remove the evaluation message from result documents or lift the feature limits, contact sales for a 30-day temporary license.