# Use font writers

Writers keep the selected face and change its output container. They do not
reduce the character or glyph set. Use [Create a font subset](https://altophp.com/font/subset.md)
first when the output should contain fewer glyphs.

The examples assume Composer's autoloader is loaded, a source font exists at
`fonts/Inter-Regular.ttf`, and `output` exists. Run the first example with the
PHP Brotli extension installed; it creates three new font files and prints
nothing. Use [Convert a font](https://altophp.com/font/convert.md) for a complete first script.

## Write SFNT, WOFF, and WOFF2

```php
use Alto\Font\Compression\BrotliExtensionCompressor;
use Alto\Font\Font;
use Alto\Font\Writer\SfntWriter;
use Alto\Font\Writer\Woff2Writer;
use Alto\Font\Writer\WoffWriter;

$font = Font::fromFile(__DIR__.'/fonts/Inter-Regular.ttf');

new SfntWriter()->write($font, __DIR__.'/output/inter.ttf');
new WoffWriter()->write($font, __DIR__.'/output/inter.woff');
new Woff2Writer(new BrotliExtensionCompressor())->write(
    $font,
    __DIR__.'/output/inter.woff2',
);
```

The output directory must exist. Writers create a new file exclusively and
never replace an existing path. A partial file is removed if writing fails.

## Return bytes instead of writing a file

Every writer provides `dump()`:

```php
use Alto\Font\Compression\BrotliExtensionCompressor;
use Alto\Font\Writer\SfntWriter;
use Alto\Font\Writer\Woff2Writer;
use Alto\Font\Writer\WoffWriter;

$sfntBytes = new SfntWriter()->dump($font);
$woffBytes = new WoffWriter()->dump($font);
$woff2Bytes = new Woff2Writer(
    new BrotliExtensionCompressor(),
)->dump($font);
```

`dump()` materializes the complete output as one string. Use it for storage
APIs that accept bytes. Use `write()` for an exclusive filesystem destination.

`Font::toSfnt()` is the direct convenience API for in-memory SFNT output.

## Extract a collection face

```php
$font = Font::fromFile(__DIR__.'/fonts/Collection.ttc', faceIndex: 1);

new SfntWriter()->write($font, __DIR__.'/output/selected-face.ttf');
```

A selected TTC or OTC face is always written as a standalone font.

## Writer contracts

`SfntWriter`, `WoffWriter`, and `Woff2Writer` belong to `Alto\Font\Writer`.
They expose the same two methods:

| Signature | Result and side effects |
| --- | --- |
| `dump(Font $font): string` | Return all output bytes in memory. No output file is created. Compression adapters may use temporary resources. |
| `write(Font $font, string\|Stringable $file): void` | Write a new local file. Its parent directory must exist; an existing destination is never replaced. |

`SfntWriter` and `WoffWriter` need no constructor arguments.
`Woff2Writer` requires a `BrotliCompressorInterface`; see
[WOFF2 compression](https://altophp.com/font/convert/woff2.md) for the available adapters.

## Understand reconstruction

| Source and target | Result |
| --- | --- |
| Unchanged standalone SFNT to SFNT | Preserved byte-for-byte |
| Collection face to SFNT | Standalone face with rebuilt directory and checksums |
| WOFF or WOFF2 to SFNT | Reconstructed standalone SFNT |
| Any supported face to WOFF | Each table uses Zlib level 6 only when compression makes it smaller |
| Any supported face to WOFF2 | Tables transformed when supported, then Brotli-compressed |

WOFF and WOFF2 container metadata and private-data blocks are not preserved
when a webfont is decoded and written again. WOFF and WOFF2 output remove
`DSIG`. WOFF2 output also updates required `head.flags` and may reconstruct
`glyf`, `loca`, and `hmtx` canonically. Rebuilt output is structurally
equivalent, not necessarily byte-for-byte identical.

## Handle failures

| Exception | Meaning |
| --- | --- |
| `FontWriteException` | The destination is empty, exists already, or cannot be written |
| `CompressionException` | Zlib or Brotli compression, support, or temporary streams failed |
| `UnsupportedFontException` | The requested view or font feature cannot be written |
| `InvalidFontException` | Required source tables are malformed or inconsistent |

These exceptions implement `FontExceptionInterface`. A selected variable view
created with `withVariations()` cannot be written as a static font.

See [WOFF2 compression](https://altophp.com/font/convert/woff2.md) for Brotli configuration and
memory behavior.

Create the destination directory before writing and choose a new filename for
a rerun: writers do not create directories or overwrite files. For compression
or temporary-storage failures, check the [WOFF2 runtime](https://altophp.com/font/convert/woff2.md#check-the-runtime).

A selected variable view is read-only. Use `withoutVariations()` to write the
original variable font with all its axes, or supply a static source font when
you need a fixed-weight file. See [Variable fonts](https://altophp.com/font/inspect/variations.md).
