Skip to content

crosspoint-reader-ko/epdfont-converter

Repository files navigation

EPDFont Converter

Browser-based TTF/OTF → EPDFont converter for CrossPoint Reader. Runs entirely client-side with no file-size or font-size limits.

The app is a Next.js 16 static export. FreeType is shipped as a patched WASM module and all rasterization work happens in a Web Worker, so the UI stays responsive even when converting large fonts (Pretendard, Noto Sans CJK, etc.).

Features

  • TTF / OTF / WOFF / WOFF2 input
  • 1-bit or 2-bit grayscale EPDFont output
  • Full Unicode range picker with 14 quick presets, "select all", and custom intervals (hex)
  • Rendering controls: char / line spacing, boldness, italic angle, horizontal scale, baseline shift, antialiasing
  • Live canvas preview with adjustable BG/FG and zoom
  • Korean / English UI (language toggle in the header)
  • Static export compatible with GitHub Pages and any plain-file host

Getting started

This project uses Bun as its package manager and runtime.

bun install
bun run dev

Open http://localhost:3000.

Scripts

Script Description
bun run dev Next dev server (Turbopack)
bun run build Production static export to out/
bun start Serve the built out/ directory locally
bun run lint ESLint

The predev / prebuild hooks run scripts/sync-freetype-wasm.mjs, which copies node_modules/freetype-wasm/dist/* into public/wasm/ and patches the binary / JS to enable heap growth (see "How it works").

Static deployment

bun run build
# out/ is ready to deploy as-is (GitHub Pages, S3, Netlify, etc.)

Set NEXT_PUBLIC_BASE_PATH at build time if the site lives under a sub-path:

NEXT_PUBLIC_BASE_PATH=/epdfont-converter bun run build

EPDFont format

Little-endian binary. See src/lib/epdfont-converter.ts for the encoder and src/types/epdfont.ts for the types.

Header (32 bytes):
  magic            uint32   0x46445045 ("EPDF")
  version          uint16   1
  is2Bit           uint8    0 = 1-bit B/W, 1 = 2-bit grayscale
  reserved         uint8
  advanceY         uint8    line height (px)
  ascender         int8     max above baseline
  descender        int8     max below baseline
  reserved         uint8
  intervalCount    uint32
  glyphCount       uint32
  intervalsOffset  uint32
  glyphsOffset     uint32
  bitmapOffset     uint32

Intervals (12 bytes each):
  start            uint32   first codepoint (inclusive)
  end              uint32   last codepoint (inclusive)
  glyphOffset      uint32   index into glyph array

Glyphs (16 bytes each):
  width, height    uint8
  advanceX         uint8
  reserved         uint8
  left, top        int16
  dataLength       uint32
  dataOffset       uint32

Bitmap data:
  1-bit → 8 px/byte, MSB first
  2-bit → 4 px/byte, 2 MSBs are the first pixel

How it works

freetype-wasm@0.0.4 on npm is compiled with ALLOW_MEMORY_GROWTH=0 and the WASM module itself hard-codes min = max = 16 MB. That ceiling blows up on anything larger than a trivial Latin font.

scripts/sync-freetype-wasm.mjs runs on every install / dev / build and does two targeted patches:

  1. WASM memory section — rewrites the memory limits so max = 32768 pages (2 GB). Initial stays at 256 pages (16 MB); Emscripten grows on demand.
  2. JS wrapper — replaces the stub emscripten_resize_heap (which just calls abort("OOM")) with a real wasmMemory.grow() + view-refresh loop, using the module's existing updateGlobalBufferAndViews helper.

The patched assets land in public/wasm/ and are loaded from ${basePath}/wasm/freetype.js. The main thread loads FreeType for font validation and canvas preview; conversion itself happens in src/lib/freetype-worker.ts, which owns its own FreeType instance and streams progress + glyph data back via postMessage with transferable buffers.

Project layout

src/
  app/                         Next.js app router, root layout, icons
  components/
    Header.tsx, Footer.tsx
    font-converter/            Main UI and converter controls
    unicode-range.ts           Range IDs, intervals, categories
  i18n/
    index.tsx                  React context + useT hook
    locales/{ko,en}.ts         All translated strings, incl. range names
  lib/
    epdfont-converter.ts       Binary encoder, worker client wrapper
    freetype-loader.ts         Main-thread FreeType loader
    freetype-worker.ts         Off-thread rasterizer
    freetype-worker-client.ts  Worker message protocol
  types/                       FreeType + EPDFont type definitions
public/wasm/                   Patched freetype.js + freetype.wasm
scripts/sync-freetype-wasm.mjs Install-time WASM patcher

Credits

  • FreeType — glyph rasterization
  • freetype-wasm — Emscripten wrapper, patched at install time for memory growth

License

MIT. See LICENSE.

About

EPDFont Web Converter

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors