Skip to content

xingmolu/ofd-preview

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OFD Viewer (NestJS + TypeScript)

An OFD file previewer that serves both backend and frontend in one NestJS application. Provides API endpoints to fetch metadata, render pages as SVG/PNG/PDF, optional upload, and a lightweight viewer page with toolbar.

This implementation focuses on safety and simplicity while providing a working path to view typical text-only OFD pages. It includes a minimal sample OFD file generated on startup at /data/sample.ofd.

Features

  • Preview OFD via browser: http://127.0.0.1:3000/url?file=/data/sample.ofd or http://127.0.0.1:3000/url?file=https://example.com/sample.ofd
  • Viewer UI rebuilt with React 18 + Ant Design 5 (served statically via CDN) with responsive layout and Ant Design components
  • APIs
    • GET /api/ofd/metadata?file=... — pages, size (mm), title, author, creation date, extractable text flag, negotiated capabilities, active renderer
    • GET /api/ofd/page?file=...&page=<n>&format=svg|png|pdf — render a page as SVG/PNG/PDF
    • GET /api/ofd/text?file=...&page=<n> — extract text positions for a page (if possible)
    • POST /api/upload — upload OFD and get a temporary id to reference as file=id:<id>
    • GET /api/ofd/raw?file=... — download the original OFD
  • Frontend /url page
    • Ant Design toolbar with zoom, pagination, goto page, download current page (PNG/PDF), download original OFD, toggle text selection
    • Keyboard shortcuts: + zoom in, - zoom out, 0 reset, arrow keys turn pages
    • Remote/local file input with history update, loading indicators, inline error feedback via Ant Design message / Alert
  • Caching: in-memory LRU for parsed docs and rendered SVG pages (TTL 10 min)
  • Security: path is restricted to OFD_ROOT or upload ids; prevents path traversal; file size limits
  • Limits: file size, parse timeout, helpful error codes

Compatibility and Rendering Strategies

src/ofd/parser.ts now orchestrates a chain of rendering strategies so that the backend can adapt to different levels of OFD complexity without code changes:

  1. OFDRW CLI strategy (optional). When the environment variable OFDRW_CLI points to a binary or script that understands the expected CLI contract, the service delegates metadata extraction and page rendering to it. This is ideal for wrappers around ofdrw or any other robust renderer and unlocks support for complex graphics, embedded fonts, annotations, and electronic signatures.
  2. Basic XML fallback. If no CLI is configured (or the CLI becomes unavailable), the built-in TypeScript strategy parses the OFD package directly and renders TextObject/TextCode instructions into SVG. This preserves the previous behaviour and keeps the application self-contained.

The parser automatically uses the first available strategy and falls back when a strategy errors out. Metadata responses now return a capabilities object describing the negotiated features (text, vector drawing, images, annotations, signatures) so the frontend can react accordingly.

When only the basic strategy is active, the following limitations remain:

  • Complex graphics (paths, images, clipping, CTM transforms) are not drawn
  • Fonts defined in resource packages are not embedded; system fallbacks are used
  • Advanced layout features such as vertical text, kerning, or glyph substitutions are ignored
  • Annotations, stamps, and e-seals are not rendered
  • Multi-document OFD packages remain unsupported

Configure an OFDRW-compatible CLI to unlock the advanced features required for production workloads.

Remote OFD Support

The backend transparently downloads HTTP/HTTPS OFD files, validates their size, and caches them under OFD_ROOT/remote-cache. Cache lifetime and download timeout can be tuned with OFD_REMOTE_CACHE_TTL and OFD_REMOTE_TIMEOUT. Metadata, page rendering, and raw download endpoints accept remote URLs directly, enabling /url?file=https://example.com/sample.ofd style previews without preprocessing.

Getting Started

Requirements: Node.js 18+.

  1. Install dependencies
npm install
  1. Run in development
npm run start:dev

This will start the server at http://127.0.0.1:3000 and auto-generate a sample OFD at /data/sample.ofd.

Open the viewer:

  1. Build & run production
npm run build
npm run start:prod

Environment Variables

  • PORT — server port (default 3000)
  • OFD_ROOT — the root directory for OFD files (default /data). Absolute paths are only allowed if inside this directory. The sample file is created here.
  • MAX_OFD_SIZE — maximum OFD size in bytes (default 104857600, i.e., 100 MiB)
  • OFDRW_CLI — optional path to an executable or script that implements the OFDRW-compatible CLI used by OfdService
  • OFDRW_TIMEOUT — override the CLI invocation timeout in milliseconds (default 20000)
  • OFDRW_DISABLE — set to true/1/yes to skip the OFDRW strategy even when OFDRW_CLI is configured
  • OFDRW_KEEP_ARTIFACTS — set to 1 to retain temporary working directories produced by the CLI for debugging
  • OFD_REMOTE_CACHE_TTL — cache duration for downloaded remote OFD files in milliseconds (default 300000)
  • OFD_REMOTE_TIMEOUT — timeout for downloading remote OFD files in milliseconds (default 20000)

OFDRW CLI Contract

When OFDRW_CLI is configured the command is invoked with the following expectations:

  • OFDRW_CLI metadata <input.ofd> must write a JSON object to stdout containing:
    {
      "meta": { "pages": 1, "widthMM": 210, "heightMM": 297, "title": "...", "author": "...", "creationDate": "...", "textExtractable": true },
      "capabilities": { "text": true, "vector": true, "images": true, "annotations": true, "signatures": true },
      "pageRefs": ["page-1", "page-2"]
    }
    capabilities and pageRefs are optional; sensible defaults are applied when they are omitted.
  • OFDRW_CLI render --page <n> --format svg --output <outputBase> <input.ofd> must create <outputBase>.svg. Optionally write <outputBase>.json with an array of text items that match PageTextItem.

Any script or binary that fulfils this contract can drive the advanced renderer.

Uploading Files

  • POST /api/upload with a multipart form field file
  • Response returns { id, file: 'id:<id>' }
  • Use that value as the file query parameter, e.g. /url?file=id:<id>

API Examples

  • Metadata: GET /api/ofd/metadata?file=/data/sample.ofd
  • First page SVG: GET /api/ofd/page?file=/data/sample.ofd&page=1&format=svg
  • First page PNG: GET /api/ofd/page?file=/data/sample.ofd&page=1&format=png
  • First page PDF: GET /api/ofd/page?file=/data/sample.ofd&page=1&format=pdf
  • Text layer: GET /api/ofd/text?file=/data/sample.ofd&page=1
  • Raw download: GET /api/ofd/raw?file=/data/sample.ofd

All endpoints enforce path restrictions to stay within OFD_ROOT.

Tests

Run tests:

npm test

Included tests (at least 3):

  • Metadata success for sample
  • Page render success (SVG and PNG)
  • Metadata error for non-existing file

Docker (optional)

A simple Dockerfile is provided. Build and run:

docker build -t ofd-viewer .
docker run --rm -p 3000:3000 -e OFD_ROOT=/data -v $(pwd)/data:/data ofd-viewer

The container will create /data/sample.ofd on first start if not present.

Extending the Renderer

The strategy pipeline in src/ofd/parser.ts is intentionally open-ended:

  • Point OFDRW_CLI at any command that produces metadata JSON and per-page SVG (with optional text JSON) following the documented contract to gain full OFD compatibility via external renderers such as ofdrw.
  • Implement your own OfdRenderingStrategy (for example, an HTTP bridge or a WASM renderer) and pass it to new OfdParser({ strategies: [...] }) inside OfdService if you need tighter control.

Unsupported features still surface readable errors and the viewer informs the user with options to retry or upload another file.

About

ofd preview

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages