Table of Contents

Generating PDF in TMS WEB Core

The PDF Library is shareable between VCL, FMX, and WEB Core, and the generation code is the same on all three. Two things differ in the browser, and both are about resources the runtime cannot simply read from disk: fonts must be fetched before they can be embedded, and compression needs a JavaScript library that is not bundled by default.

Get those two right and the rest of this guide applies unchanged.

Font caching

In VCL and FMX, TTMSFNCPDFLib reads font files from the system font directory when it embeds a subset. A browser has no such directory, so fonts have to be fetched over HTTP first and cached before generation starts.

Pre-load each font you intend to use:

AddFontToCache('http://www.myserver.com/fonts/arial.ttf');
AddFontToCache('http://www.myserver.com/fonts/tahoma.ttf');

AddFontToCache starts an asynchronous download. Generating a document before it completes produces a PDF with the font missing, so wait for the cache rather than generating immediately: handle Application.OnFontCacheReady and start the export from there.

Important

This is the most common WEB Core issue. A document that renders correctly in a desktop build and loses its fonts in the browser almost always means generation ran before OnFontCacheReady fired — not that the font is wrong.

Serve the font files from the same origin as the application where you can; a cross-origin font request needs the usual CORS headers on the font server, and a blocked request fails the same way a missing file does.

Compression

WEB Core requires the Pako ZLib library for PDF compression. Enable it via Manage JavaScript Libraries → Pako ZLib Compression (PDF) in the project context menu.

Enabling Pako ZLib compression in the Manage JavaScript Libraries dialog

Without it, generation still works but the output is uncompressed — noticeably larger files, which matters most when the PDF is downloaded over a slow connection or stored per user.

What stays the same

Everything else in this guide is portable as written:

Area WEB Core
Document skeleton Identical — BeginDocument / NewPage / EndDocument
Drawing and text Identical API
Form fields Not available (Windows and Linux only)
Output Use the stream overload and hand the bytes to a browser download

Because EndDocument returns a TMemoryStream when no file name is given, the browser case is the stream case — there is no local path to write to. See Creating a PDF document.

Putting it together

Both browser-specific concerns in one flow: cache the fonts, wait for the cache, generate to a stream, and hand the bytes to the browser. Only the first and last steps differ from the desktop code.

procedure TForm1.WebFormCreate(Sender: TObject);
begin
  { A browser has no system font directory, so every font the document embeds
    has to be fetched first. AddFontToCache starts an asynchronous download. }
  AddFontToCache('http://www.myserver.com/fonts/arial.ttf');
  AddFontToCache('http://www.myserver.com/fonts/tahoma.ttf');

  { Generating before the downloads finish produces a PDF with the font
    missing, so the export is started from the ready callback - never directly
    after the AddFontToCache calls above. }
  Application.OnFontCacheReady := HandleFontCacheReady;
end;

procedure TForm1.HandleFontCacheReady(Sender: TObject);
var
  p: TTMSFNCPDFLib;
  s: TMemoryStream;
begin
  p := TTMSFNCPDFLib.Create;
  try
    p.Header := '';
    p.Footer := '';

    { No file name: there is no local path to write to in the browser, so
      EndDocument hands the bytes back as a stream instead. }
    p.BeginDocument('');
    try
      p.NewPage;
      p.Graphics.Font.Name := 'Arial';
      p.Graphics.Font.Size := 16;
      p.Graphics.DrawText('Generated in the browser', PointF(40, 40));
    finally
      s := p.EndDocument;
    end;

    { Hand the stream to whatever delivers it to the user - a download link,
      an upload to your server, or an attachment. }
    DownloadStream(s, 'report.pdf');
  finally
    p.Free;
  end;
end;

Common mistakes

  • Generating before the font cache is ready. Wait for Application.OnFontCacheReady.
  • Assuming system fonts exist. They do not; every embedded font must be cached first.
  • Cross-origin font requests without CORS headers. The download fails and the font is missing from the output.
  • Expecting a file path. Use the stream overload and trigger a download.
  • Missing Pako ZLib. Output is valid but uncompressed.

See also