# Fonts

Back to root overview: [README.md](../README.md#in-depth-documentation)

## Font Setup

When you install `tc-lib-pdf` as a dependency in your project (via `composer require` or `composer install`), the fonts from the companion package [`tc-lib-pdf-font`](https://github.com/tecnickcom/tc-lib-pdf-font) must be generated before they can be used.

Composer does not execute scripts declared by dependencies, so you need to add the font generation step to your **consuming project's** `composer.json` file:

```json
{
  "scripts": {
    "tc-lib-pdf-fonts": [
      "[ -d vendor/tecnickcom/tc-lib-pdf-font ] && make -C vendor/tecnickcom/tc-lib-pdf-font deps fonts || true"
    ],
    "post-install-cmd": [
      "@tc-lib-pdf-fonts"
    ],
    "post-update-cmd": [
      "@tc-lib-pdf-fonts"
    ]
  }
}
```

This ensures fonts are generated automatically when you run:

```bash
composer install
composer update
composer require ...
```

To also cover `composer dump-autoload` (used in many CI pipelines), add the hook to `post-autoload-dump` as well:

```json
"post-autoload-dump": [
    "@tc-lib-pdf-fonts"
]
```

If you prefer to generate fonts manually, run the build in the `tc-lib-pdf-font` package:

```bash
cd vendor/tecnickcom/tc-lib-pdf-font
make fonts
```

Equivalent one-liner from your project root:

```bash
make -C vendor/tecnickcom/tc-lib-pdf-font deps fonts
```

Once fonts are generated, they are cached in `vendor/tecnickcom/tc-lib-pdf-font/target/fonts/` and will not be regenerated unless explicitly rebuilt.

You can also add your own fonts and generate their PHP font data with `tc-lib-pdf-font`. For shared or immutable environments, generate them once into a persistent directory you control (outside `vendor/`) and point `K_PATH_FONTS` to that location.

For a runnable end-to-end custom font workflow, see [examples/E072_import_new_font.php](../examples/E072_import_new_font.php).

Example import commands (from the project root):

```bash
mkdir -p target/fonts/source target/fonts/custom

curl -fL --retry 3 -o target/fonts/source/NotoSans-Regular.ttf \
    https://github.com/notofonts/noto-fonts/raw/main/hinted/ttf/NotoSans/NotoSans-Regular.ttf

php vendor/tecnickcom/tc-lib-pdf-font/util/convert.php \
    --outpath=target/fonts/custom \
    --type=TrueTypeUnicode \
    --flags=32 \
    --encoding_id=10 \
    --fonts=target/fonts/source/NotoSans-Regular.ttf
```

`--encoding_id=10` selects the full Unicode cmap subtable of the font, which is required to render characters above U+FFFF. See [Unicode Text Encoding](#unicode-text-encoding).

Then point `K_PATH_FONTS` to `target/fonts/custom` (or an absolute path to that directory) before creating the `Tcpdf` instance.

```php
\define('K_PATH_FONTS', '/opt/app/fonts/tc-lib-pdf');
```

This avoids regenerating fonts on every dependency reinstall and lets multiple deployments reuse the same prepared font set.

## Unicode Text Encoding

A `TrueTypeUnicode` font is written as a composite (Type0) font with the `Identity-H` encoding, so every character in a content stream is a 2-byte code. Since `tc-lib-pdf-font` 4.0 that code is the glyph index of the font (`/CIDToGIDMap /Identity`), and the mapping back to Unicode is carried by a `/ToUnicode` CMap generated for the glyphs the document actually uses. Text search, copy and paste, and assistive technologies read that CMap.

What this changes for a document:

- Characters above U+FFFF are rendered. See below for the font conversion they require.
- The 131072-byte `CIDToGIDMap` stream is no longer embedded, so PDFs using Unicode fonts are smaller.
- The `.ctg.z` file of a font is read when the text is encoded, not only when the font is embedded. It must stay next to the `.json` definition file.
- The generated bytes of a content stream differ from previous versions. Regenerate any baseline used to compare PDF output byte by byte.

### Supplementary-Plane Characters

Characters outside the Basic Multilingual Plane, such as the mathematical alphanumeric symbols (U+1D400 to U+1D7FF), emoji, and the CJK extensions, are mapped by the format 12 cmap subtable of a font. That subtable is only read when the font is converted with `--encoding_id=10`:

```bash
php vendor/tecnickcom/tc-lib-pdf-font/util/convert.php \
    --outpath=target/fonts/custom \
    --type=TrueTypeUnicode \
    --flags=32 \
    --encoding_id=10 \
    --fonts=target/fonts/source/MyFont-Regular.ttf
```

`--encoding_id=10` is a safe default for any `TrueTypeUnicode` font: a font without a format 12 subtable falls back to the BMP one.

The fonts bundled with `tc-lib-pdf-font` are converted with `--encoding_id=1` and therefore cover the BMP only. To use a supplementary-plane character, convert a font that contains it with `--encoding_id=10` and point `K_PATH_FONTS` to the output directory.

A character with no glyph in the font is drawn as `.notdef`, as with any other missing character.

### Font Selection and the Current Font

A string is always measured and encoded with the current font of the stack. Adding the font operator of another font to the page content does not change that, so the two must be kept in agreement:

```php
// Wrong: the text is measured and encoded with the font that is current on the stack,
// which is $fontB here, whatever operator was added to the page.
$fontA = $pdf->font->insert($pdf->pon, 'dejavusans', 'B', 18);
$fontB = $pdf->font->insert($pdf->pon, 'dejavusans', '', 10);
$pdf->page->addContent($fontA['out']);
$pdf->page->addContent($pdf->getTextCell(txt: 'Heading', posx: 15, posy: 20, width: 180));
```

Make the wanted font current instead, with `insert()` or by cloning an already inserted one:

```php
$fontA = $pdf->font->cloneFont($pdf->pon, $fontA['idx'], null, $fontA['size']);
$pdf->page->addContent($fontA['out']);
$pdf->page->addContent($pdf->getTextCell(txt: 'Heading', posx: 15, posy: 20, width: 180));
```

`cloneFont()` inherits the size of the current font when `$size` is null, so pass the size explicitly to keep the one of the cloned font. See [examples/E044_toc_index.php](../examples/E044_toc_index.php).

With a byte font (Core, TrueType, Type1) a mismatch only affects the metrics used for layout, since the character codes mean the same thing in every font. With a `TrueTypeUnicode` font the codes are the glyph indices of the font that encoded them, so a mismatch would draw unrelated glyphs: a text object using such a font therefore selects it explicitly, and the current font of the stack wins over any operator previously added to the page.

## Third-Party Fonts

PHP font metadata files under the fonts directory are covered by the project license (GNU LGPL v3). They can be regenerated with the built-in font utilities.

Original source files are renamed for compatibility and compressed with PHP `gzcompress` (`.z` extension) where applicable.

| Prefix | Source | License |
|--------|--------|---------|
| `freefont` | [GNU FreeFont](https://ftp.gnu.org/gnu/freefont/freefont-ttf-20120503.zip) | GNU GPL v3 |
| `pdfa` | [tc-font-pdfa](https://github.com/tecnickcom/tc-font-pdfa) (derived from GNU FreeFont) | GNU GPL v3 |
| `dejavu` | [DejaVu Fonts 2.35](https://sourceforge.net/projects/dejavu/files/dejavu/2.35/dejavu-fonts-ttf-2.35.zip) | Bitstream Vera (with DejaVu public-domain changes) |
| `unifont` | [GNU Unifont 15.1.03](https://www.unifoundry.com/pub/unifont/unifont-15.1.03/unifont-15.1.03.tar.gz) | GPL v2+ with font embedding exception (also distributed under SIL OFL 1.1) |
| `cid0` | [GNU Unifont](http://unifoundry.com/unifont.html) (CID mappings) | GPL v2+ with font embedding exception |
| `core` | [Adobe Core14 AFM](https://partners.adobe.com/public/developer/en/pdf/Core14_AFMs.zip) | Adobe copyright terms (see AFM notices) |
