phenx/php-font-lib
Read and parse TrueType, OpenType (TT glyphs) and WOFF fonts in PHP. Extract basic/advanced metadata, metrics, glyph names and shapes, generate Adobe Font Metrics (AFM), and build font subsets. Used by dompdf for font handling.
Installation:
composer require dompdf/php-font-lib
Ensure ext-mbstring is enabled in your PHP environment.
Basic Usage: Load a font file and extract metadata:
use FontLib\Font;
$font = Font::load(storage_path('fonts/your-font.ttf'));
$font->parse();
// Extract metadata
$fontName = $font->getFontName();
$weight = $font->getFontWeight();
$postscriptName = $font->getFontPostscriptName();
$font->close();
First Use Case: Generate a PDF with DOMPDF using a subsetted font:
use Dompdf\Dompdf;
use FontLib\Font;
$font = Font::load(storage_path('fonts/your-font.ttf'));
$font->parse();
$font->setSubset("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ");
$font->reduce();
$font->save(storage_path('fonts/subset-font.ttf'));
$font->close();
// Use the subsetted font in DOMPDF
$dompdf = new Dompdf();
$dompdf->loadHtml('<h1>Hello World</h1>');
$dompdf->setPaper('A4', 'portrait');
$dompdf->setOption('isRemoteEnabled', true);
$dompdf->setOption('isFontSubsettingEnabled', true);
$dompdf->render();
$dompdf->stream("document.pdf", ["Attachment" => true]);
Font Metadata Extraction: Use the library to extract font properties for dynamic typography or validation:
$font = Font::load($fontPath);
$font->parse();
$metadata = [
'name' => $font->getFontName(),
'family' => $font->getFontSubfamily(),
'weight' => $font->getFontWeight(),
'postscript' => $font->getFontPostscriptName(),
];
$font->close();
Font Subsetting for PDFs: Subset fonts to reduce file size and improve rendering performance:
$font = Font::load($fontPath);
$font->parse();
$font->setSubset($requiredCharacters); // e.g., "abc123"
$font->reduce();
$subsetPath = $outputPath . '.subset.ttf';
$font->save($subsetPath);
$font->close();
AFM/UFM Generation: Generate Adobe Font Metrics for legacy systems or compatibility:
$font = Font::load($fontPath);
$font->parse();
$font->saveAdobeFontMetrics($outputPath . '.afm');
$font->close();
Font Re-encoding: Re-encode fonts for specific platforms or encodings:
$font = Font::load($fontPath);
$font->parse();
$font->open($outputPath, FontLib\BinaryStream::modeReadWrite);
$font->encode(['OS/2']); // Specify encoding tables
$font->close();
PDF Generation Pipeline:
// app/Services/FontService.php
class FontService {
public function getSubsetFont($fontPath, $characters) {
$cachePath = storage_path("fonts/{md5($fontPath)}{md5($characters)}.ttf");
if (!file_exists($cachePath)) {
$font = Font::load($fontPath);
$font->parse();
$font->setSubset($characters);
$font->reduce();
$font->save($cachePath);
$font->close();
}
return $cachePath;
}
}
Dynamic Typography:
$font = Font::load($fontPath);
$font->parse();
$fontSize = $font->getFontWeight() > 500 ? 12 : 10; // Adjust size based on weight
$font->close();
Font Validation:
try {
$font = Font::load($fontPath);
$font->parse();
if ($font->getFontWeight() === null) {
throw new \Exception("Invalid font weight");
}
$font->close();
} catch (\Exception $e) {
Log::error("Font validation failed: " . $e->getMessage());
}
Laravel Service Container:
Bind the FontLib\Font class to the container for dependency injection:
// config/app.php
'bindings' => [
FontLib\Font::class => function ($app) {
return new FontLib\Font();
},
];
Artisan Commands: Create custom commands for font processing:
// app/Console/Commands/SubsetFont.php
class SubsetFont extends Command {
protected $signature = 'font:subset {font} {characters} {--output=}';
protected $description = 'Subset a font file';
public function handle() {
$fontPath = storage_path('fonts/' . $this->argument('font'));
$outputPath = $this->option('output') ?: storage_path('fonts/subset-' . $this->argument('font'));
$characters = $this->argument('characters');
$font = Font::load($fontPath);
$font->parse();
$font->setSubset($characters);
$font->reduce();
$font->save($outputPath);
$font->close();
$this->info("Font subsetted successfully: {$outputPath}");
}
}
Queue Jobs: Offload font processing to queues for performance:
// app/Jobs/SubsetFontJob.php
class SubsetFontJob implements ShouldQueue {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $fontPath;
public $characters;
public $outputPath;
public function handle() {
$font = Font::load($this->fontPath);
$font->parse();
$font->setSubset($this->characters);
$font->reduce();
$font->save($this->outputPath);
$font->close();
}
}
Storage Integration: Use Laravel’s filesystem to handle font files:
use Illuminate\Support\Facades\Storage;
$fontPath = Storage::disk('fonts')->path('your-font.ttf');
$font = Font::load($fontPath);
$font->parse();
// Process font
$font->close();
Font Parsing Errors:
glyf, cmap). Handle exceptions gracefully:try {
$font = Font::load($fontPath);
$font->parse();
// Process font
} catch (\Exception $e) {
Log::error("Failed to parse font: " . $e->getMessage());
throw new \RuntimeException("Invalid font file");
}
Memory Usage:
$font = Font::load($fontPath, FontLib\BinaryStream::modeRead);
$font->parse();
// Process font
$font->close();
PHP Version Compatibility:
TypedArray issues.Subsetting Limitations:
File Permissions:
$font = Font::load($fontPath);
$font->parse();
Log::debug('Font Metadata:', [
How can I help you explore Laravel packages today?