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 first when the output should contain fewer glyphs.

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.

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 for Brotli configuration and memory behavior.