# BDF Parser (TypeScript / JavaScript library)

Parse BDF bitmap fonts in JavaScript or TypeScript, inspect glyphs, render text, and manipulate bitmaps with bdfparser.

## Introduction

This is a BDF (Glyph Bitmap Distribution; [Wikipedia](https://en.wikipedia.org/wiki/Glyph_Bitmap_Distribution_Format); [Spec](../bdf_spec/)) format bitmap font file parser library in TypeScript (JavaScript). It has [`Font`](font/), [`Glyph`](glyph/) and [`Bitmap`](bitmap/) classes providing more than 30 chainable API methods of parsing BDF fonts, getting their meta information, rendering text in any writing direction, adding special effects and manipulating bitmap images. 0 dependencies and tested in Node.js, browsers (so you can use HTML Canvas) and Deno, it has detailed documentation / tutorials / API reference.

You can even try the [**Live Demo & Code Editor**](editor/)!

**BDF Parser TypeScript (JavaScript) library** ([documentation](../bdfparser_js/); [GitHub page](https://github.com/fontpixel/bdfparser-js); [npm page](https://www.npmjs.com/package/bdfparser); `npm i bdfparser`) is a port of **BDF Parser Python library** ([documentation](../bdfparser_py/); [GitHub page](https://github.com/fontpixel/bdfparser); [PyPI page](https://pypi.org/project/bdfparser/); `pip install bdfparser`). Both are written by [Tom Chen](https://github.com/tomchen/) and under the MIT License.

## Installation

```bash npm2yarn
npm install bdfparser readlineiter
```

`readlineiter` is used for Node.js to read local file. You can instead use `fetchline` for browsers/Deno to fetch remote file. See [Fetch Line JavaScript packages](https://github.com/tomchen/fetchline).

## Quick examples

<Tabs
  groupId="bdfparser-js-ts-py"
  defaultValue="js"
  values={[
    { label: 'JavaScript (CJS)', value: 'js', },
    { label: 'TypeScript (strict)', value: 'ts', },
    { label: 'Python', value: 'py', },
  ]
}>
<TabItem value="js">

```js
const { $Font } = require('bdfparser')

const getline = require('readlineiter') // or `require('fetchline')` for browsers


;(async () => {

    const font = await $Font(getline('./test/fonts/unifont-13.0.04.bdf'))

    console.log(`This font's global size is \
${font.headers.fbbx} x ${font.headers.fbby} (pixel), \
it contains ${font.length} glyphs.`)

})()


// This font's global size is 16 x 16 (pixel), it contains 57086 glyphs.
```

</TabItem>
<TabItem value="ts">

```ts
import { $Font } from 'bdfparser'
import getline from 'readlineiter'

;(async () => {
  try {
    const font = await $Font(getline('./test/fonts/unifont-13.0.04.bdf'))
    if (!font || !font.headers) {
      throw new Error('Unable to load font')
    }
    console.log(`This font's global size is \
${font.headers.fbbx} x ${font.headers.fbby} (pixel), \
it contains ${font.length} glyphs.`)
  } catch (error) {
    throw error
  }
})()
// This font's global size is 16 x 16 (pixel), it contains 57086 glyphs.
```

</TabItem>
<TabItem value="py">

*Python code is included here only for comparison. See [Python library's documentation](../bdfparser_py/#quick-examples) for details*

```py
from bdfparser import Font

font = Font('tests/fonts/unifont-13.0.04.bdf')
print(f"This font's global size is "
      f"{font.headers['fbbx']} x {font.headers['fbby']} (pixel), "
      f"it contains {len(font)} glyphs.")
# This font's global size is 16 x 16 (pixel), it contains 57086 glyphs.
```

</TabItem>
</Tabs>

Print cropped and combined "a" and "c" with shadow effect:

<Tabs
  groupId="bdfparser-js-ts-py"
  defaultValue="js"
  values={[
    { label: 'JavaScript (CJS)', value: 'js', },
    { label: 'TypeScript (strict)', value: 'ts', },
    { label: 'Python', value: 'py', },
  ]
}>
<TabItem value="js">

```js
const a = font.glyph('a')
const c = font.glyph('c')

const ac = a
  .draw()
  .crop(6, 8, 1, 2)
  .concat(c.draw().crop(6, 8, 1, 2))
  .shadow()

console.log(ac.toString())
// .####..####..
// #.&&&##.&&&#.
// .&...##&....&
// .######&.....
// #.&&&##&.....
// #&...##&.....
// #&..###&...#.
// .###.#&####.&
// ..&&&.&.&&&&.
```

</TabItem>
<TabItem value="ts">

```ts
const a = font.glyph('a')
const c = font.glyph('c')
if (a && c) {
  const ac = a
    .draw()
    .crop(6, 8, 1, 2)
    .concat(c.draw().crop(6, 8, 1, 2))
    .shadow()
  console.log(ac.toString())
}
// .####..####..
// #.&&&##.&&&#.
// .&...##&....&
// .######&.....
// #.&&&##&.....
// #&...##&.....
// #&..###&...#.
// .###.#&####.&
// ..&&&.&.&&&&.
```

</TabItem>
<TabItem value="py">

```py
ac = font.glyph("a").draw().crop(6, 8, 1, 2).concat(
    font.glyph("c").draw().crop(6, 8, 1, 2)
    ).shadow()
print(ac)
# .####..####..
# #.&&&##.&&&#.
# .&...##&....&
# .######&.....
# #.&&&##&.....
# #&...##&.....
# #&..###&...#.
# .###.#&####.&
# ..&&&.&.&&&&.
```

</TabItem>
</Tabs>

Get an enlarged version (8 times both width and height) of this "ac", and render it in HTML `<canvas>` in browser with JavaScript / TypeScript <small>(or with PIL (Pillow) library in Python)</small>:

<Tabs
  groupId="bdfparser-js-ts-py"
  defaultValue="js"
  values={[
    { label: 'JavaScript (CJS)', value: 'js', },
    { label: 'TypeScript (strict)', value: 'ts', },
    { label: 'Python', value: 'py', },
  ]
}>
<TabItem value="js">

```js
const ac_8x8 = ac.enlarge(8, 8)
const ctx = canvas.getContext('2d')
ac_8x8.draw2canvas(ctx)
```

</TabItem>
<TabItem value="ts">

```ts
const ac_8x8 = ac.enlarge(8, 8)
const ctx = canvas.getContext('2d')
ac_8x8.draw2canvas(ctx)
```

</TabItem>
<TabItem value="py">

```py
ac_8x8 = ac * 8
from PIL import Image
im_ac = Image.frombytes('RGBA',
                        (ac_8x8.width(), ac_8x8.height()),
                        ac_8x8.tobytes('RGBA'))
im_ac.save("ac.png", "PNG")
```

</TabItem>
</Tabs>

<BDF demo="js-index-0" client:visible />

Get text "Hello!", from right to left, with glowing effect:

<Tabs
  groupId="bdfparser-js-ts-py"
  defaultValue="js"
  values={[
    { label: 'JavaScript (CJS)', value: 'js', },
    { label: 'TypeScript (strict)', value: 'ts', },
    { label: 'Python', value: 'py', },
  ]
}>
<TabItem value="js">

```js
const hello = font.draw('Hello!', {direction: 'rl'}).glow()
hello.draw2canvas(canvas.getContext('2d'))
```

</TabItem>
<TabItem value="ts">

```ts
const hello = font.draw('Hello!', {direction: 'rl'}).glow()
hello.draw2canvas(canvas.getContext('2d'))
```

</TabItem>
<TabItem value="py">

```py
hello = font.draw('Hello!', direction='rl').glow()
```

</TabItem>
</Tabs>

<BDF demo="js-index-1" client:visible />

Save all glyphs in [Unifont](https://en.wikipedia.org/wiki/GNU_Unifont) as a black-and-white-two-color-only "font_preview.png" (with default width 512px):

<Tabs
  groupId="bdfparser-js-ts-py"
  defaultValue="js"
  values={[
    { label: 'JavaScript (CJS)', value: 'js', },
    { label: 'TypeScript (strict)', value: 'ts', },
    { label: 'Python', value: 'py', },
  ]
}>
<TabItem value="js">

```js
const font_preview = font.drawall()
font_preview.draw2canvas(canvas.getContext('2d'))
```

</TabItem>
<TabItem value="ts">

```ts
const font_preview = font.drawall()
font_preview.draw2canvas(canvas.getContext('2d'))
```

</TabItem>
<TabItem value="py">

```py
font_preview = font.drawall()
im_ac = Image.frombytes(
  '1',
  (font_preview.width(), font_preview.height()),
  font_preview.tobytes('1'),
)
im_ac.save('font_preview.png', 'PNG')
```

</TabItem>
</Tabs>

<Figure
  src="bdfparser_py/font_preview_part.png"
  caption="Parts of the Unifont preview image (click the image to view the long original)"
  position="center"
  imgUrl={true}
  link={import.meta.env.BASE_URL + 'img/bdfparser_py/font_preview.png'}
/>

Now try it your self. Copy and paste this into the [Live Demo & Code Editor](editor/):

```jsx
<BDF func={
  (font) => {
    return font.draw('Hello World!', {linelimit: 100, direction: 'tblr'})
      .enlarge(3, 3).shadow(2, -2)
  }
}/>
```

Or even this:

```jsx
<BDF size={1} func={(font) => font.drawall()}/>
```

## Deno usage

If you are using Deno instead of Node.js, you don't need to install the package with npm/yarn, and you should replace `const { $Font } = require('bdfparser'); const getline = require('readlineiter')` by:

```ts
import { $Font } from "https://raw.githubusercontent.com/fontpixel/bdfparser-js/main/deno/mod.ts"
import readlineiter from 'https://raw.githubusercontent.com/tomchen/fetchline/main/packages/readlineiter-deno/mod.ts'
```

## Copyright & links

Written by [Tom Chen](https://tomchen.org/), under [the MIT License](https://github.com/fontpixel/bdfparser-js/blob/master/LICENSE), a permissive open-source license.

This TypeScript / JavaScript library supports Node.js, Deno and modern browsers. It has TypeScript source code, as well as compiled versions in CommonJS, ES module, minified UMD and seperate type definition files.

[GitHub repo](https://github.com/fontpixel/bdfparser-js) | [npm page](https://www.npmjs.com/package/bdfparser)

The documentation belongs to [font.tomchen.org](https://font.tomchen.org/), a website where I put font & typography related stuff. [The documentation website's GitHub repo](https://github.com/fontpixel/fontpixel)
