# Fonts

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

## Font Setup

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 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"
    ]
  }
}
```

Fonts are then generated by:

```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
```

Generated fonts are kept in `vendor/tecnickcom/tc-lib-pdf-font/target/fonts/` and are not regenerated unless explicitly rebuilt.

Custom fonts can be converted to PHP font data with `tc-lib-pdf-font`. For shared or immutable environments, generate them once into a persistent directory outside `vendor/` and point `K_PATH_FONTS` to that location.

Runnable custom font workflow: [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');
```

## 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. 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 uses. Text search, copy and paste, and assistive technologies read that CMap.

Consequences for a document:

- Characters above U+FFFF are rendered, given the font conversion described below.
- No `CIDToGIDMap` stream is embedded.
- 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.

### 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) |
