Salta ai contenuti
getnextpdf.com

stabilità: Sperimentale

Supporto dello shaping di script complessi

Anteprima opt-in. Lo shaping di script complessi è disattivato per impostazione predefinita. Quando è spento, il motore rende attraverso il percorso esistente da codepoint a cmap — byte-identico a una build senza la funzionalità. Attivalo solo quando hai libharfbuzz e un font capace di shaping, e convalida il risultato.

Il renderer HTML aggiunge uno shaper opt-in di script complessi per tibetano e mongolo. Quando lo shaper è attivo, un tratto tibetano o mongolo in ambito rilevato è sottoposto a shaping tramite libharfbuzz ed emesso come codici di glifo Identity-H. Lo shaper copre il tibetano orizzontale nei caratteri TrueType e CFF/OTTO, incluso l’a capo, e il mongolo verticale impostato dall’alto verso il basso (TTB).

Terminal window
composer require nextpdf/core:^3

Lo shaper è incluso nel pacchetto core. L’opt-in CssFeatureFlags::$complexTextShaping è @since 6.1.0. libharfbuzz è un requisito di runtime quando il flag è attivo — lo shaper chiama in libharfbuzz attraverso l’estensione FFI di PHP. Quando il flag è spento, la libreria non ha alcuna dipendenza da libharfbuzz.

Gli script complessi riordinano, sostituiscono e riposizionano i glifi in base al contesto. Una mappatura ingenua da codepoint a glifo li rende visibilmente errati. Lo shaper consegna un tratto in ambito a libharfbuzz, che applica le tabelle di shaping OpenType del font, e il motore emette la sequenza di glifi risultante come un font composito Type 0 con codifica Identity-H (ISO 32000-2 §9.7.4 — la stringa mostrata è composta da CID a due byte).

L’ambito è deliberato. Lo shaper riconosce i tratti tibetani e mongoli e li sottopone a shaping; non rivendica una copertura generale di script complessi. Il tibetano orizzontale è sottoposto a shaping nei caratteri TrueType e CFF/OTTO, con a capo di riga. Il mongolo è sottoposto a shaping verticalmente, dall’alto verso il basso.

Lo shaper non emette mai come fallback glifi non sottoposti a shaping e visivamente rotti. Un tratto che non può essere sottoposto a shaping fedelmente solleva invece un’eccezione tipizzata:

  • ComplexScriptShapingException — il tratto non può essere sottoposto a shaping fedelmente: al font mancano i glifi necessari (ne risulterebbe un .notdef), a un carattere CFF viene chiesto di eseguire lo shaping nel percorso verticale, il tratto contiene un link, oppure una colonna mongola necessita di a capo (un caso fuori ambito).
  • HarfBuzzUnavailableException — il flag è attivo ma libharfbuzz non è raggiungibile tramite FFI a runtime.

Con il flag spento, un tratto in ambito viene reso attraverso il percorso esistente da codepoint a cmap. Questa è una limitazione documentata, non una rivendicazione di shaping: il percorso spento non applica lo shaping OpenType, perciò le forme contestuali non sono garantite. Non descrivere l’output del percorso spento come “sottoposto a shaping”.

Confine di onestà — parità oggettiva, non approvazione estetica

Sezione intitolata “Confine di onestà — parità oggettiva, non approvazione estetica”

La fedeltà di shaping è convalidata oggettivamente rispetto a HarfBuzz: gli identificatori di glifo emessi, la mappatura dei cluster e le posizioni dei glifi corrispondono all’output di riferimento di HarfBuzz (parità di glifo, cluster e posizione). Una revisione estetica da parte di un madrelingua — che giudica se il risultato si legge in modo naturale per un lettore fluente — è un seguito tracciato post-rilascio. NextPDF non avanza alcuna rivendicazione di qualità linguistica in questa API o in questa documentazione. La parità oggettiva è asserita; la qualità estetica no.

SimboloPosizioneRuolo
CssFeatureFlags::$complexTextShapingsrc/Html/CssFeatureFlags.phpFlag opt-in per lo shaper tibetano/mongolo (predefinito false).
Config::withCssFeatureFlags(CssFeatureFlags $flags): selfsrc/Core/Config.phpCollega l’insieme di flag alla configurazione di un documento.
ComplexScriptShapingExceptionsrc/Font/Shaper/ComplexScriptShapingException.phpSollevata quando un tratto in ambito non può essere sottoposto a shaping fedelmente.
HarfBuzzUnavailableExceptionsrc/Font/Shaper/HarfBuzzUnavailableException.phpSollevata quando il flag è attivo ma libharfbuzz non è disponibile.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Config;
use NextPDF\Core\Document;
use NextPDF\Html\Css\CssFeatureFlags;
$config = (new Config())->withCssFeatureFlags(
new CssFeatureFlags(complexTextShaping: true),
);
$doc = Document::createStandalone($config);
$doc->addPage();
$doc->writeHtml(
'<div style="font-family: NotoSerifTibetan;">བོད་སྐད་</div>',
);
$doc->save(__DIR__ . '/tibetan.pdf');

Registra un font capace di shaping, fai opt-in nello shaper e gestisci esplicitamente le due modalità di fallimento tipizzate. Un render fedele o un’eccezione chiara — mai un tratto di glifi rotto silenziosamente.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Config;
use NextPDF\Core\DocumentFactory;
use NextPDF\Exception\ComplexScriptShapingException;
use NextPDF\Exception\HarfBuzzUnavailableException;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Html\Css\CssFeatureFlags;
use NextPDF\Typography\FontRegistry;
$fontRegistry = new FontRegistry();
$fontRegistry->register('/path/to/NotoSerifTibetan-Regular.ttf', alias: 'NotoSerifTibetan');
$config = (new Config())->withCssFeatureFlags(
new CssFeatureFlags(complexTextShaping: true),
);
$factory = new DocumentFactory($fontRegistry, new ImageRegistry(maxCacheBytes: 0));
$doc = $factory->create($config);
$doc->setLanguage('bo');
$doc->addPage();
try {
$doc->writeHtml('<div style="font-family: NotoSerifTibetan;">བོད་སྐད་</div>');
} catch (HarfBuzzUnavailableException $e) {
// The flag is on but libharfbuzz is not reachable. Install it, or turn the
// flag off to fall back to the unshaped cmap path.
throw $e;
} catch (ComplexScriptShapingException $e) {
// The run cannot be shaped faithfully (missing glyphs, link in run,
// out-of-scope case). Fix the font or the content; do not ship broken glyphs.
throw $e;
}
$doc->save($out);
  • libharfbuzz è richiesto quando è attivo. Con il flag attivo e libharfbuzz assente, il motore solleva HarfBuzzUnavailableException. Non degrada silenziosamente.
  • Spento non significa “sottoposto a shaping”. Con il flag spento, un tratto in ambito viene reso attraverso il percorso cmap senza shaping OpenType. Questa è una limitazione documentata; non chiamarla output sottoposto a shaping.
  • L’ambito è tibetano e mongolo. Altri script complessi sono fuori ambito per questa fetta.
  • Un link nel tratto fallisce in modo fail-closed. Un tratto che contiene un’annotazione di link solleva ComplexScriptShapingException, perché il rettangolo del link non può seguire il riordino di shaping.
  • Nessuna rivendicazione di qualità linguistica. La parità con HarfBuzz è asserita; la qualità estetica da parte di un madrelingua è un seguito tracciato e non è rivendicata.

Lo shaping aggiunge una chiamata a libharfbuzz per ogni tratto in ambito, più il passaggio di emissione dei glifi, lineare nel conteggio dei glifi. Il budget (wall_ms: 2000, peak_mb: 128) segue il profilo CJK/script complessi, perché i font di shaping sono grandi e la gestione del font domina il costo.

Abilitare lo shaper introduce una chiamata FFI in libharfbuzz, una libreria nativa. I file di font restano input binario non attendibile gestito dalla convalida esistente del livello tipografico prima di raggiungere lo shaper. Lo shaper consuma caratteri già registrati e già convalidati. Tratta la provenienza dei font forniti dall’utente finale come non attendibile e fornisci libharfbuzz da una fonte attendibile.

AffermazioneStandardClausola
I tratti sottoposti a shaping sono emessi come CID a due byte Identity-H in un font composito Type 0.ISO 32000-2§9.7.4
Lo shaper applica la sostituzione e il posizionamento dei glifi OpenType del font.OpenType SpecificationGSUB / GPOS
La formazione dei cluster segue le proprietà di script per tibetano e mongolo.Unicode Standard AnnexTibetan and Mongolian

Questa è un’implementazione di anteprima limitata a tibetano e mongolo, convalidata per la parità oggettiva con HarfBuzz. Non avanza alcuna rivendicazione di qualità linguistica e non asserisce alcuna conformità PDF end-to-end per il file prodotto. Nessun testo normativo è riprodotto.