← dompdf.js Studio

PDF Image Embedding Guide: dompdf.js Image & Text Layout Tutorial

A professional PDF is almost never pure text. Invoices carry tax QR codes, contracts carry electronic seals, catalogs carry product photos, resumes carry headshots, and proposals carry company logos. How well those images are embedded determines both the document's perceived quality and its file size. Many HTML-to-PDF tools sidestep the problem by rasterizing the entire page: images stay sharp, but the text around them becomes a blurry, unselectable bitmap, and the whole document turns into one giant picture. dompdf.js takes the opposite approach. It renders the document as vector graphics, embeds images at their original resolution, and keeps text as true vector type. The result is a hybrid document that is crisp everywhere and surprisingly small. This guide explains every supported way to embed images in dompdf.js — network URLs, relative paths, base64 data URIs, and Blob URLs — along with quality optimization tips and a troubleshooting section for the classic 'image does not show up' problem, so you can ship image-rich PDFs without the usual debugging marathon. Throughout the guide, the examples use realistic business assets — logos, QR codes, and product photos — so you can see how each technique behaves in the situations where image quality actually matters. The optimization and troubleshooting sections are written as practical checklists, so you can work through them during implementation rather than after an incident.

Typical Image Use Cases in PDFs

Images in business documents fall into two broad categories. Decorative images — logos, banners, background textures — establish branding and visual identity and make a document look complete rather than thin. Informational images — QR codes, electronic seals, product photos, screenshots — carry data that readers must be able to scan, read, or verify. The second category is where rendering quality really matters.

A QR code that blurs at the edges fails to scan; a seal that loses its color balance undermines a contract; a product photo that smears makes a catalog look unprofessional. Informational images demand faithful, high-resolution embedding, which is exactly what a vector-first renderer provides, because a blurred QR code is useless and a blurred seal can have legal consequences.

dompdf.js handles both categories well. Images are embedded at their native resolution without aggressive recompression, while surrounding text remains vector. When the whole page is zoomed or printed, images and text stay in sync — no smearing, no pixelation, no mismatch between what you designed and what you shipped, and the mixed layout stays stable page after page.

Think about what happens after the PDF is delivered. A catalog goes to a printer, a contract goes to legal, an invoice goes to an accountant. Each of those readers may zoom, print, or archive the file, and each action exposes quality problems that look fine on a phone screen. Embedding images at native resolution and keeping text vector means the file survives all of those journeys without degrading, which is why the rendering pipeline matters more than the source assets alone.

Decorative and informational images also differ in how they should be treated technically. A logo can be recompressed or downscaled aggressively without anyone noticing, but a QR code must keep its quiet zone and contrast, and a screenshot must preserve every pixel of its detail. Deciding which category an asset belongs to before embedding it prevents the two most common mistakes: files that are needlessly heavy, and images that are unusable because they were optimized too aggressively.

There is also a workflow angle worth planning early: decide where the source assets live. If images are stored on a CDN, plan for CORS and cache headers; if they are uploaded by users, validate format, dimensions, and size at upload time rather than at export time. A few validation rules at the entry point prevent a steady stream of broken exports later, and the rules are cheap to implement once and reuse across every export feature.

Which Image Sources Does dompdf.js Support?

The most direct way is a standard <img> tag. The src attribute can point to an absolute network URL, a relative path, a base64 data URI, or a Blob URL created with URL.createObjectURL. Network images work well as long as the server allows cross-origin access and the image loads before rendering starts, while base64 is naturally inline and works offline with zero network dependency.

Images generated at runtime — Canvas screenshots, QR codes, chart library outputs — are easy to include too. Convert the canvas to a data URL with toDataURL() or to a Blob, then either assign it to an <img> element's src in the DOM or interpolate the string into your HTML template before calling addPage. The renderer reads the embedded resource automatically, so the loop is closed without extra plumbing.

CSS background images are supported as well and work nicely for decorative purposes. For informational images, however, prefer <img> tags: they carry explicit dimensions and alt semantics, align predictably in tables and flex layouts, and give you straightforward control over spacing and alignment, whereas background images can drift when page dimensions change.

A practical tip for dynamic pages: build a small image loader helper that collects every img element in the target DOM, awaits their decode() promises, and only then calls addPage. It costs a few lines of code and removes a whole category of flaky, timing-dependent bugs where the PDF is missing images only on slow networks or on the first visit.

The four source types are not mutually exclusive, and a robust export pipeline often uses them in combination. Base64 is the safest choice for images that already exist as data at render time, such as QR codes or user uploads; Blob URLs are convenient for runtime-generated content; network URLs keep the HTML template readable when the assets are stable and cacheable. Matching the source type to the asset's lifecycle avoids most timing and availability problems before they can occur.

One detail that surprises many developers: the same img element can be passed to the renderer directly when you render a live DOM node, which means images that are already loaded in the page do not need to be fetched again. This reuse is one of the reasons rendering a live DOM is often faster than re-parsing a freshly built HTML string, especially on image-heavy pages with many assets.

Code Example: Logo + QR Code + Product Photo

import { DomPDF } from 'dompdf.js';

// Generate the QR code with any library, then convert it to base64
const qrDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...';

const catalogHTML = `
  <div style="text-align:center">
    <img src="/logo.png" width="120" alt="Company Logo">
    <h2>2026 Autumn Product Catalog</h2>
  </div>
  <table style="width:100%;border-collapse:collapse">
    <tr>
      <td style="border:1px solid #ccc;padding:12px;text-align:center">
        <img src="https://example.com/product-a.jpg" width="160">
        <p>Wireless Noise-Cancelling Headphones</p>
      </td>
      <td style="border:1px solid #ccc;padding:12px;text-align:center">
        <img src="${qrDataUrl}" width="120">
        <p>Scan for details</p>
      </td>
    </tr>
  </table>`;

const pdf = new DomPDF();
pdf.addPage(catalogHTML, { format: 'A4' });
pdf.save('catalog.pdf');

Image Quality and File Size Optimization

Because dompdf.js embeds images at their native pixel resolution, an oversized source image directly inflates the PDF. As a rule of thumb, keep source images under 2000px on their longest side and a few hundred kilobytes in size. That is plenty for print-quality output on A4 and keeps the resulting file lean, which is basic hygiene for image-rich documents.

Choose the format by content type. Photographs compress best as JPG or WebP; logos, icons, and QR codes — graphics with hard edges — belong in PNG. Transparent PNGs are essential for seals and logos that must sit on colored or textured backgrounds without a white box showing through, and they blend naturally into the layout.

File size is not the only cost of oversized images. Encoding and decoding large bitmaps also consumes memory and CPU at render time, which matters on lower-end laptops and mobile devices. Keeping sources reasonably sized therefore improves the export experience for everyone, not just users with fast hardware, and it makes the whole feature feel snappier.

When the same image appears on many pages, such as a logo in a repeated header, reference the same URL everywhere instead of embedding a fresh copy per page. dompdf.js reuses resources, which prevents the file size from multiplying with every page you add — one of the easiest wins for multi-page documents, and one that is all too easy to miss.

Build a small resource checklist into your export flow: count the images referenced on the page, verify each one's load state, and estimate the total embedded size before rendering. Running that check automatically catches missing or oversized assets before users do, which turns a support complaint into a silent fix.

Resolution and file size are related but not identical, and it helps to think about them separately. A 4000x3000 JPG at 80 percent quality may weigh 1.5MB even though its useful print size on A4 is only a fraction of the page; downscaling it to 1600px on the longest side can cut that to 200KB with no visible difference in the PDF. The extra pixels were never going to be displayed, so carrying them into the file only adds cost.

Color profile is a smaller but real consideration. PNGs with embedded ICC profiles and CMYK JPEGs can render with unexpected color shifts in some viewers. For most business documents, converting everything to sRGB at the source keeps colors predictable across screens and printers, and it costs one export step in your image pipeline rather than a debugging session later.

Troubleshooting: Images Not Showing Up

Q: Network images fail to load? A: Check CORS configuration on the image server and confirm the URL is reachable. The bulletproof workaround is to convert the image to a base64 data URI and inline it, so rendering never depends on the network and failures become impossible by construction.

Q: Large base64 strings make the page sluggish? A: Downscale the image on a Canvas first — draw it at the target dimensions and export with toDataURL — then embed the smaller string. This cuts both memory and render time dramatically while keeping enough detail for print.

Q: Images look fine in the browser but are misplaced in the PDF? A: Check the width constraints of the parent container. Give the <img> an explicit width or max-width so the layout engine does not fall back to browser-default auto sizing, which is the most common cause of layout drift.

Q: Animated GIFs only show their first frame? A: That is a limitation of the PDF format itself, which does not support animation. Replace animated GIFs with a static frame before embedding, or the delivered document will be missing content that the source page clearly had.

Q: The PDF looks different from the browser preview? A: Compare the browser print preview with the PDF output. Many differences come from print-specific CSS such as page margins and background handling, not from image embedding itself. Align your print stylesheet with the on-screen design and most discrepancies disappear.

Two additional failure modes are worth listing because they appear constantly in support queues. First, SVG files: while many browsers render them perfectly, some SVG features are not representable in the PDF image model — if an SVG does not appear, convert it to PNG at the required size before embedding. Second, very large images on low-memory devices: if exports crash only on specific machines, check whether an oversized source image is blowing through the memory budget, and downscale it preemptively in the export pipeline.

Comparing with Bitmap-Based Approaches

html2pdf.js rasterizes the entire page into one bitmap before embedding it. Images inside the page are rasterized along with everything else, so both images and text blur at high zoom, and the file grows with page dimensions rather than content — the sharpness advantage of the original images is lost entirely.

jsPDF's manual API can embed images cleanly with addImage, but you must compute every coordinate, wrap, and alignment by hand. Mixed image-and-text layouts become a geometry exercise that is expensive to build and fragile to maintain, and any later layout change means redoing the math.

dompdf.js parses the DOM directly and treats images and text through different pipelines: images keep their native resolution while text stays vector. You get the layout convenience of HTML with the file quality of a professional print pipeline — and all you had to write was the HTML. For teams that maintain image-rich catalogs, contracts, or reports, that combination is the highest return on investment.

If your product already has a bitmap-based export path and a full switch is not feasible this quarter, a pragmatic middle ground is to export critical informational images — QR codes, seals — at high resolution separately, so at least the elements that must be scannable stay sharp. That limits the damage while the migration is planned.

Finally, measure before you optimize. Export a representative document, check its size in kilobytes, and open it at 200% zoom before spending time on compression strategies. In most cases a few well-chosen source images and format decisions solve 80% of the size and quality issues without any exotic tooling.

One final measurement worth doing: export the same document through each pipeline and inspect the artifacts side by side. Zoom to 200 percent, try to select text, check the file size, and count the pages. In most evaluations the vector result is clearly sharper and smaller, but having your own numbers makes the decision easy to defend to stakeholders who are attached to the existing implementation.

⚡ 现场演示(点击生成 PDF)

下面的按钮用 dompdf.js 在浏览器端实时生成 PDF,无需后端:

Hello from dompdf.js!

这是由 dompdf.js 渲染的示例 PDF 内容。