---
title: "How to build area annotations with canvas capture in PDF.js"
canonical_url: "https://www.nutrient.io/blog/pdfjs-area-annotations-canvas-capture/"
md_url: "https://www.nutrient.io/blog/pdfjs-area-annotations-canvas-capture.md"
last_updated: "2026-08-11T08:57:05.236Z"
description: "Build area annotations in PDF.js: pointer tracking, canvas-region capture, PDF coordinate conversion, and draggable overlays with React."
---

**TL;DR**

- Capture pointer drag/release on a fullscreen overlay and translate the screen rectangle into PDF coordinates via the page’s `PageViewport`.

- Crop the rendered canvas region with `drawImage` and `toDataURL` to store the area as a JPEG or PNG.

- Render annotations back over the page with `react-rnd`, recropping on drag/resize, and recalculating positions on zoom/rotation.

## Prerequisites

This guide assumes a working PDF.js viewer (`PDFViewer` + `EventBus` + a loaded `pdfDocument`). If you don’t have that yet, start with our guide on [how to set up a custom PDF.js viewer in React](https://www.nutrient.io/blog/pdfjs-react-viewer-setup.md).

You’ll also need:

- `pdfjs-dist` 4.x or later

- The `react-rnd` package (`npm install react-rnd`) for draggable/resizable overlays

- The `screenToPdf`/`pdfToScreen`/`nodeLocationToScaled` helpers from [PDF.js coordinate systems: PDF to screen](https://www.nutrient.io/blog/pdfjs-coordinate-systems-pdf-to-screen.md) — this post uses them but doesn’t redefine them.

## Architecture

```

User selects area tool
  -> Pointer tracking overlay captures drag start/end
  -> Selection box renders during drag
  -> On release: convert screen rectangle to PDF coordinates
  -> Capture canvas region as an image (JPEG/PNG)
  -> Save annotation with coordinates + image data
  -> Render as draggable/resizable overlay

```

## Step 1: Pointer tracking overlay

Create a transparent overlay that captures pointer events when the area tool is active:

```tsx

function PointerArea({ disabled, selectionBox, style, shouldStart, onStart, onEnd }) {
  const [isDrawing, setIsDrawing] = React.useState(false);
  const [origin, setOrigin] = React.useState(null);
  const [current, setCurrent] = React.useState(null);
  const startElementRef = React.useRef(null);

  const handlePointerDown = (e) => {
    if (disabled) return;
    if (!shouldStart(e)) return;

    startElementRef.current = e.target;
    setOrigin({ x: e.clientX, y: e.clientY });
    setCurrent({ x: e.clientX, y: e.clientY });
    setIsDrawing(true);
    onStart?.();
  };

  const handlePointerMove = (e) => {
    if (!isDrawing) return;
    setCurrent({ x: e.clientX, y: e.clientY });
  };

  const handlePointerUp = (e) => {
    if (!isDrawing) return;
    setIsDrawing(false);

    onEnd(startElementRef.current, {
      clientOrigin: [origin.x, origin.y],
      clientTarget: [e.clientX, e.clientY],
    });
  };

  return (
    <div
      style={{ position: "fixed", inset: 0, zIndex: 100 }}
      onPointerDown={handlePointerDown}
      onPointerMove={handlePointerMove}
      onPointerUp={handlePointerUp}
    >
      {isDrawing && selectionBox && (
        <div
          style={{...style,
            position: "absolute",
            left: Math.min(origin.x, current.x),
            top: Math.min(origin.y, current.y),
            width: Math.abs(current.x - origin.x),
            height: Math.abs(current.y - origin.y),
          }}
        />
      )}
    </div>
  );
}

```

## Step 2: Handle selection completion

When the pointer is released, determine which page was selected and convert coordinates:

```tsx

const handlePointerEnd = (startElement, origins) => {
  const page = getPageFromElement(startElement);
  if (!page) return;

  const pageBounds = page.canvasWrapper.getBoundingClientRect();

  const clientLeft = Math.min(origins.clientOrigin[0], origins.clientTarget[0]);
  const clientTop = Math.min(origins.clientOrigin[1], origins.clientTarget[1]);

  const canvasLeft = clientLeft - pageBounds.left;
  const canvasTop = clientTop - pageBounds.top;
  const width = Math.abs(origins.clientOrigin[0] - origins.clientTarget[0]);
  const height = Math.abs(origins.clientOrigin[1] - origins.clientTarget[1]);

  // Skip tiny selections (accidental clicks).
  if (width * height <= 100) return;

  const viewport = viewer.getPageView(page.number - 1).viewport;

  // Convert to PDF coordinates for storage.
  const pdfCoords = screenToPdf(
    { left: canvasLeft, top: canvasTop, width, height, pageNumber: page.number },
    viewport,
  );

  // Capture the canvas region as an image.
  const canvas = viewer.getPageView(page.number - 1).canvas;
  const imageContent = getAreaAsImage(canvas, {
    left: canvasLeft, top: canvasTop, width, height,
  });

  // Save annotation.
  onCreateAreaAnnotation(
    color,
    page.number,
    [pdfCoords.x1, pdfCoords.y1, pdfCoords.x2, pdfCoords.y2],
    imageContent,
  );
};

```

## Step 3: Capturing canvas regions

PDF.js renders pages on `<canvas>` elements. You can extract any rectangular region:

```tsx

function getAreaAsImage(canvas, position) {
  const { left, top, width, height } = position;

  const newCanvas = document.createElement("canvas");
  newCanvas.width = width;
  newCanvas.height = height;

  const ctx = newCanvas.getContext("2d");
  if (!ctx ||!canvas) return "";

  // PDF.js renders at its own output scale, which is usually but not always
  // `window.devicePixelRatio`. Read the real scale from the rendered canvas.
  const dpr = canvas.width / canvas.clientWidth;

  ctx.drawImage(
    canvas,
    left * dpr,      // source x (scaled for DPI).
    top * dpr,       // source y.
    width * dpr,     // source width.
    height * dpr,    // source height.
    0, 0,            // destination origin.
    width, height,   // destination size (CSS pixels).
  );

  return newCanvas.toDataURL("image/jpeg");
}

```

**DPI matters!** PDF.js renders canvases at its own output scale, which is usually but not always equal to `window.devicePixelRatio` (PDF.js caps the scale and lets configurations override it). Derive the real scale from `canvas.width / canvas.clientWidth` rather than reading `devicePixelRatio` directly.

## Step 4: Render as draggable/resizable box

Use `react-rnd` to render area annotations that users can drag and resize:

```tsx

import { Rnd } from "react-rnd";

function AreaAnnotation({ annotation, viewport, page }) {
  const ref = React.useRef(null);
  const positionRef = React.useRef(null);

  // Update position when viewport changes (zoom/rotation).
  React.useEffect(() => {
    const pdfCoords = nodeLocationToScaled({
      page: annotation.page,
      rect: annotation.rect,
    });
    const position = pdfToScreen(pdfCoords, viewport);
    positionRef.current = position;

    ref.current?.updatePosition({ x: position.left, y: position.top });
    ref.current?.updateSize({ width: position.width, height: position.height });
  }, [annotation.rect, viewport]);

  const handleChangePosition = (newPosition) => {
    // Convert back to PDF coordinates.
    const pdfCoords = screenToPdf(
      {...positionRef.current,...newPosition },
      viewport,
    );
    const location = {
      page: pdfCoords.pageNumber,
      rect: [pdfCoords.x1, pdfCoords.y1, pdfCoords.x2, pdfCoords.y2],
    };

    // Recapture the canvas region with new bounds.
    const canvas = viewer.getPageView(page - 1).canvas;
    const newImage = getAreaAsImage(canvas, {...positionRef.current,...newPosition });

    // Save updated annotation.
    saveAnnotation(annotation.id, { rect: location.rect, image_content: newImage });
  };

  return (
    <Rnd
      ref={ref}
      style={{
        position: "absolute",
        background: "rgba(255, 94, 94, 0.4)",
        borderRadius: "8px",
        cursor: "pointer",
      }}
      onDragStop={(_, data) => {
        handleChangePosition({ top: data.y, left: data.x });
      }}
      onResizeStop={(_, __, ref, ___, position) => {
        handleChangePosition({
          top: position.y,
          left: position.x,
          width: ref.offsetWidth,
          height: ref.offsetHeight,
        });
      }}
    />
  );
}

```

## Step 5: Disable text selection during drawing

When the area tool is active, prevent text selection from interfering:

```tsx

function toggleDisableSelection(viewer, flag) {
  viewer.viewer?.classList.toggle("disableSelection", flag);
}

```

```css.disableSelection {
  user-select: none;
  -webkit-user-select: none;
}.disableTouchAction {
  touch-action: none;
}

```

Enable `disableSelection` on pointer down, and disable on pointer up.

## Minimum size threshold

Ignore accidental clicks by checking the area:

```tsx

if (width * height <= 100) return; // Less than ~10x10 pixels.

```

## Key points

- Use a fullscreen overlay to capture pointer events outside the PDF container.

- Subtract `canvasWrapper.getBoundingClientRect()` to get page-relative coordinates.

- Derive the output scale from `canvas.width / canvas.clientWidth` rather than `window.devicePixelRatio` — PDF.js caps the render scale and configurations can override it.

- `canvas.toDataURL("image/jpeg")` gives you a base64 string for storage (use `"image/png"` for lossless capture).

- Recapture the canvas region when the user drags/resizes the annotation.

- `react-rnd` provides drag and resize with a clean React API.

- Update the `Rnd` position imperatively via `ref.updatePosition()` when the viewport changes.

## How Nutrient Web SDK handles this

Nutrient Web SDK ships `RectangleAnnotation` with drag, resize, and draw-on-page interactions wired into the default UI. The rectangle tool appears in the toolbar without any extra code. Use the programmatic API when creating annotations from code — import flows, automation, server-driven annotations:

```js

const annotation = new NutrientViewer.Annotations.RectangleAnnotation({
  pageIndex: 0,
  boundingBox: new NutrientViewer.Geometry.Rect({
    left: 50,
    top: 100,
    width: 300,
    height: 200,
  }),
  strokeColor: NutrientViewer.Color.RED,
  strokeWidth: 2,
});
await instance.create(annotation);

```

To export the pixels under a rectangle as an image — useful for callouts, off-page references, or sharing a region without the source PDF — use `renderPageAsArrayBuffer` to grab the rendered bytes for the given area. Refer to our guide on how to [render visible area in current page](https://www.nutrient.io/guides/web/knowledge-base/render-visible-area-in-current-page.md) for the full pattern.

For other vector overlays, the SDK also supports `EllipseAnnotation`, `PolygonAnnotation`, and `PolylineAnnotation` — all draggable and resizable by default.

## FAQ

#### JPEG or PNG for the captured region?

JPEG keeps file size small for photographs and screenshots of dense pages, but it compresses text and line art poorly. PNG is lossless and noticeably better for scans, diagrams, or text-heavy regions — at the cost of bigger payloads. If you store many annotations per document, default to JPEG and switch to PNG selectively.

#### Why use <code>canvas.width / canvas.clientWidth</code> instead of <code>window.devicePixelRatio</code>?

PDF.js doesn’t always render at `devicePixelRatio` — it caps the output scale on huge pages and respects configurations that override it. The actual rendered resolution is whatever’s in the canvas’s intrinsic `width`/`height`, so deriving the scale from those gives you the correct pixel ratio every time.

#### How do I support touch input?

Pointer events already cover touch, mouse, and pen — `pointerdown`/`pointermove`/`pointerup` fire for all three. Add `touch-action: none` (the `.disableTouchAction` class in the CSS section above) to the drawing surface to stop the browser from interpreting the drag as a scroll.

#### What happens when the page is rotated?

`PageViewport.convertToPdfPoint()` returns coordinates in the PDF’s own coordinate space, so a rotated page captures correctly. The catch is that `convertToPdfPoint` can return `x1 > x2` or `y1 > y2` for rotated viewports — normalize with `Math.min`/`Math.max` before storing.

#### Should I store the captured image or rerender it on demand?

Rerendering is cheaper at write time and easier to keep current when the underlying PDF changes, but requires the original PDF to be available every time you display the annotation. Storing the cropped image (typical pattern in collaborative apps where the captured area is the artifact) costs storage but makes the annotation portable.

Area annotations take five coordinated pieces: a pointer-tracking overlay, coordinate conversion, canvas DPI scaling, image capture, and a drag-resize library. The individual steps are manageable — the overhead is keeping them in sync as zoom, rotation, and viewport changes update the layout.

---

_See [Nutrient Web SDK](https://www.nutrient.io/sdk/web-overview/) for built-in image and vector annotations without the canvas wiring, or follow the [migration guide](https://www.nutrient.io/guides/web/about/migration-guides/migrating-from-mozilla-pdfjs.md) to switch from PDF.js. [Talk to Sales](https://www.nutrient.io/contact-sales/?=sdk) about your requirements._
---

## Related pages

- [The business case for accessibility: Five ways it drives enterprise value](/blog/5-ways-accessibility-drives-enterprise-value.md)
- [Accessibility Untangled Why It Matters Guide](/blog/accessibility-untangled-why-it-matters-guide.md)
- [Advanced Techniques For React Native Ui Components](/blog/advanced-techniques-for-react-native-ui-components.md)
- [`vector_store` holds your indexed documents (see the multimodal RAG post](/blog/agentic-rag.md)
- [Ai Document Automation Extraction To Action](/blog/ai-document-automation-extraction-to-action.md)
- [Ai Legal Assistant Document Authoring](/blog/ai-legal-assistant-document-authoring.md)
- [Angular File Viewer Pdf Image Office Files](/blog/angular-file-viewer-pdf-image-office-files.md)
- [Auto Tagging And Document Accessibility In Dotnet Sdk](/blog/auto-tagging-and-document-accessibility-in-dotnet-sdk.md)
- [Best Document Ai Platforms](/blog/best-document-ai-platforms.md)
- [Best Document Viewers](/blog/best-document-viewers.md)
- [The CEO’s AI playbook: Why decision architecture beats model selection](/blog/ceo-ai-playbook-decision-architecture.md)
- [1. Extract and chunk the PDF.](/blog/chat-with-pdf.md)
- [Complete Guide To Pdfjs](/blog/complete-guide-to-pdfjs.md)
- [Construction Document Data Extraction](/blog/construction-document-data-extraction.md)
- [Convert One Drive Files To Pdf In Sharepoint](/blog/convert-one-drive-files-to-pdf-in-sharepoint.md)
- [Create And Edit Pdfs In Flutter](/blog/create-and-edit-pdfs-in-flutter.md)
- [Create Pdfs With React](/blog/create-pdfs-with-react.md)
- [Creating A Document Scanner With Ocr In Python](/blog/creating-a-document-scanner-with-ocr-in-python.md)
- [Creating And Filling Pdf Forms Programmatically In Javascript](/blog/creating-and-filling-pdf-forms-programmatically-in-javascript.md)
- [The CTO’s AI playbook: Why accountability architecture beats orchestration](/blog/cto-ai-playbook-accountability-architecture.md)
- [Digital Signatures](/blog/digital-signatures.md)
- [Digital Workflow Automation](/blog/digital-workflow-automation.md)
- [Document Ai Vs Ocr](/blog/document-ai-vs-ocr.md)
- [Document Extraction Confidence Scores](/blog/document-extraction-confidence-scores.md)
- [Document Viewer](/blog/document-viewer.md)
- [Document Watermarking](/blog/document-watermarking.md)
- [Emerging threats: Your logging system may be an agentic threat vector](/blog/emerging-threats-your-logging-system.md)
- [Extract Patient Data On Premises](/blog/extract-patient-data-on-premises.md)
- [app.py](/blog/extract-text-from-pdf-using-python.md)
- [Fillable Pdf](/blog/fillable-pdf.md)
- [How To Add Digital Signature To Pdf Using React](/blog/how-to-add-digital-signature-to-pdf-using-react.md)
- [How To Build A Dotnet Maui Pdf Viewer](/blog/how-to-build-a-dotnet-maui-pdf-viewer.md)
- [How To Build A Flutter Pdf Viewer](/blog/how-to-build-a-flutter-pdf-viewer.md)
- [or](/blog/how-to-build-a-javascript-pdf-viewer-with-pdfjs.md)
- [How To Build A Javascript Pdf Viewer](/blog/how-to-build-a-javascript-pdf-viewer.md)
- [or](/blog/how-to-build-a-nextjs-pdf-viewer.md)
- [How To Build A Powerpoint Viewer Using Javascript](/blog/how-to-build-a-powerpoint-viewer-using-javascript.md)
- [Using Yarn](/blog/how-to-build-a-react-excel-viewer.md)
- [How To Build A React Native Pdf Viewer](/blog/how-to-build-a-react-native-pdf-viewer.md)
- [How To Build A React Powerpoint Viewer](/blog/how-to-build-a-react-powerpoint-viewer.md)
- [How To Build A Reactjs File Viewer](/blog/how-to-build-a-reactjs-file-viewer.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer-with-react-pdf.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer.md)
- [How To Build A Reactjs Viewer With Pdfjs](/blog/how-to-build-a-reactjs-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer With Pdfjs](/blog/how-to-build-a-vuejs-pdf-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer](/blog/how-to-build-a-vuejs-pdf-viewer.md)
- [How To Build An Android Pdf Viewer](/blog/how-to-build-an-android-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Ng2 Pdf Viewer](/blog/how-to-build-an-angular-pdf-viewer-with-ng2-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Pdfjs](/blog/how-to-build-an-angular-pdf-viewer-with-pdfjs.md)
- [How To Convert Docx To Pdf Using Javascript](/blog/how-to-convert-docx-to-pdf-using-javascript.md)
- [How To Convert Docx To Pdf Using Python](/blog/how-to-convert-docx-to-pdf-using-python.md)
- [How To Convert Html To Pdf Using Html2pdf](/blog/how-to-convert-html-to-pdf-using-html2pdf.md)
- [or](/blog/how-to-convert-html-to-pdf-using-react.md)
- [How To Convert Html To Pdf Using Wkhtmltopdf And Csharp](/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-csharp.md)
- [or](/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-python.md)
- [How To Convert Word To Pdf In Nodejs](/blog/how-to-convert-word-to-pdf-in-nodejs.md)
- [or](/blog/how-to-create-a-react-js-signature-pad.md)
- [How To Create Pdfs With React To Pdf](/blog/how-to-create-pdfs-with-react-to-pdf.md)
- [How To Edit Pdfs Using Ios Pdf Library](/blog/how-to-edit-pdfs-using-ios-pdf-library.md)
- [How To Embed A Pdf Viewer In Your Website](/blog/how-to-embed-a-pdf-viewer-in-your-website.md)
- [How To Extract Tables From Pdf And Images](/blog/how-to-extract-tables-from-pdf-and-images.md)
- [How To Generate Pdf From Html With Nodejs](/blog/how-to-generate-pdf-from-html-with-nodejs.md)
- [base_url tells WeasyPrint where to resolve relative asset paths](/blog/how-to-generate-pdf-reports-from-html-in-python.md)
- [How To Merge Pdfs Using Javascript](/blog/how-to-merge-pdfs-using-javascript.md)
- [How To Ocr Pdfs In Linux](/blog/how-to-ocr-pdfs-in-linux.md)
- [How To Print Pdf In Csharp](/blog/how-to-print-pdf-in-csharp.md)
- [Open an image.](/blog/how-to-use-tesseract-ocr-in-python.md)
- [From an HTML string.](/blog/html-in-pdf-format.md)
- [Javascript Pdf Editors](/blog/javascript-pdf-editors.md)
- [Javascript Pdf Libraries](/blog/javascript-pdf-libraries.md)
- [Linearized Pdf](/blog/linearized-pdf.md)
- [or](/blog/merge-pdfs.md)
- [Swift Package Manager](/blog/mobile-pdf-sdk.md)
- [`elements` come from your document parser — each has a type and content.](/blog/multimodal-rag.md)
- [Nutrient Vs Conga Composer](/blog/nutrient-vs-conga-composer.md)
- [Online Document Viewer](/blog/online-document-viewer.md)
- [Open Pdf In Your Web App](/blog/open-pdf-in-your-web-app.md)
- [Building WCAG 2.2, Section 508, and PDF/UA-compliant PDFs with an SDK](/blog/pdf-accessibility.md)
- [Pdf Data Extraction Developer Guide](/blog/pdf-data-extraction-developer-guide.md)
- [Pdf Extraction Benchmark Opendataloader Bench](/blog/pdf-extraction-benchmark-opendataloader-bench.md)
- [Pdf Extraction Document Case Studies](/blog/pdf-extraction-document-case-studies.md)
- [Pdf Page Labels](/blog/pdf-page-labels.md)
- [Pdf Sdk Compliance Security Checklist](/blog/pdf-sdk-compliance-security-checklist.md)
- [Pdf Sdk Performance Benchmark](/blog/pdf-sdk-performance-benchmark.md)
- [Pdf Ua Compliance Guide](/blog/pdf-ua-compliance-guide.md)
- [Pdfjs Accessibility Structtree Printing](/blog/pdfjs-accessibility-structtree-printing.md)
- [Pdfjs Advanced Loading Streaming Workers](/blog/pdfjs-advanced-loading-streaming-workers.md)
- [Pdfjs Annotation Editor Layer](/blog/pdfjs-annotation-editor-layer.md)
- [Pdfjs Coordinate Systems Pdf To Screen](/blog/pdfjs-coordinate-systems-pdf-to-screen.md)
- [Pdfjs Document Outline Bookmarks Metadata](/blog/pdfjs-document-outline-bookmarks-metadata.md)
- [Pdfjs Eventbus Guide](/blog/pdfjs-eventbus-guide.md)
- [macOS](/blog/pdfjs-file-format-conversion-to-pdf.md)
- [macOS](/blog/pdfjs-generating-pdf-thumbnails-pdf2pic.md)
- [Pdfjs Limitations Commercial Upgrade](/blog/pdfjs-limitations-commercial-upgrade.md)
- [Pdfjs Native Annotation Layer Forms](/blog/pdfjs-native-annotation-layer-forms.md)
- [Pdfjs Navigation Zoom Rotation](/blog/pdfjs-navigation-zoom-rotation.md)
- [Pdfjs Pdf Page Manipulation Pdf Lib](/blog/pdfjs-pdf-page-manipulation-pdf-lib.md)
- [Pdfjs React Viewer Setup](/blog/pdfjs-react-viewer-setup.md)
- [Pdfjs Rendering Overlays React Portals](/blog/pdfjs-rendering-overlays-react-portals.md)
- [Pdfjs Server Side Text Extraction](/blog/pdfjs-server-side-text-extraction.md)
- [Pdfjs Sticky Note Annotations](/blog/pdfjs-sticky-note-annotations.md)
- [Pdfjs Text Highlight Annotations](/blog/pdfjs-text-highlight-annotations.md)
- [Pdfjs Text Search Pdffindcontroller](/blog/pdfjs-text-search-pdffindcontroller.md)
- [Pdfjs Thumbnail Sidebar](/blog/pdfjs-thumbnail-sidebar.md)
- [Process Flows](/blog/process-flows.md)
- [React Native Pdf Annotation](/blog/react-native-pdf-annotation.md)
- [Using Yarn](/blog/react-pdf-editor.md)
- [or](/blog/sample-blog-updated.md)
- [Sdk Product Updates Q2 2026](/blog/sdk-product-updates-q2-2026.md)
- [Add DWS MCP Server to your Claude Code project.](/blog/teaching-llms-to-read-pdfs.md)
- [Open an image file.](/blog/tesseract-python-guide.md)
- [Define the HTML part of the document.](/blog/top-10-ways-to-generate-pdfs-in-python.md)
- [Top 5 Javascript Pdf Viewers](/blog/top-5-javascript-pdf-viewers.md)
- [or](/blog/top-js-pdf-libraries.md)
- [Convert an HTML file to PDF.](/blog/top-ten-ways-to-convert-html-to-pdf.md)
- [Vector Pdf](/blog/vector-pdf.md)
- [Wcag2 Accessibility Requirements Documents](/blog/wcag2-accessibility-requirements-documents.md)
- [Web Sdk Is Now Headless](/blog/web-sdk-is-now-headless.md)
- [What Are Annotations](/blog/what-are-annotations.md)
- [What Is A Vpat](/blog/what-is-a-vpat.md)
- [What Is Document Processing](/blog/what-is-document-processing.md)
- [What Is Intelligent Document Processing](/blog/what-is-intelligent-document-processing.md)
- [What Is Pdf Ua](/blog/what-is-pdf-ua.md)
- [Why Pdfium Is A Trusted Platform For Pdf Rendering](/blog/why-pdfium-is-a-trusted-platform-for-pdf-rendering.md)
- [Why Your Ai Agent Hallucinates Pdf Table Data](/blog/why-your-ai-agent-hallucinates-pdf-table-data.md)

