Ga naar inhoud
getnextpdf.com

stabiliteit: Experimenteel

Ondersteuning voor complex-script-shaping

Opt-in preview. Complex-script-shaping staat standaard uit. Wanneer het uit is, rendert de engine via het bestaande codepoint-naar-cmap-pad — byte-identiek aan een build zonder de functie. Zet het alleen aan wanneer je libharfbuzz en een shapingvaardig font hebt, en valideer het resultaat.

De HTML-renderer voegt een opt-in complex-script-shaper toe voor Tibetaans en Mongools. Wanneer de shaper aan staat, wordt een gedetecteerde in-scope Tibetaanse of Mongoolse run geshapet via libharfbuzz en uitgezonden als Identity-H-glyphcodes. De shaper dekt horizontaal Tibetaans in TrueType- en CFF/OTTO-letterbeelden, inclusief wrapping, en verticaal Mongools gezet van boven naar beneden (TTB).

Terminal window
composer require nextpdf/core:^3

De shaper wordt meegeleverd in het core-pakket. De CssFeatureFlags::$complexTextShaping-opt-in is @since 6.1.0. libharfbuzz is een runtimevereiste wanneer de vlag aan staat — de shaper roept libharfbuzz aan via de FFI-extensie van PHP. Wanneer de vlag uit staat, heeft de library geen libharfbuzz-afhankelijkheid.

Complexe schriften herordenen, substitueren en herpositioneren glyphs op basis van context. Een naïeve codepoint-naar-glyph-mapping rendert ze zichtbaar verkeerd. De shaper geeft een in-scope-run aan libharfbuzz, dat de OpenType-shapingtabellen van het font toepast, en de engine zendt de resulterende glyphsequentie uit als een composite Type 0-font met Identity-H-encoding (ISO 32000-2 §9.7.4 — de getoonde string bestaat uit two-byte CIDs).

Het bereik is bewust. De shaper herkent Tibetaanse en Mongoolse runs en shapet ze; hij claimt geen algemene complex-script-dekking. Horizontaal Tibetaans wordt geshapet in TrueType- en CFF/OTTO-letterbeelden, met regelwrapping. Mongools wordt verticaal geshapet, van boven naar beneden.

De shaper zendt nooit ongeshapete, visueel kapotte glyphs uit als terugval. Een run die niet getrouw kan worden geshapet, werpt in plaats daarvan een getypeerde exception:

  • ComplexScriptShapingException — de run kan niet getrouw worden geshapet: het font mist de benodigde glyphs (een .notdef zou het gevolg zijn), een CFF-letterbeeld wordt gevraagd te shapen in het verticale pad, de run bevat een link, of een Mongoolse kolom heeft wrapping nodig (een out-of-scope-geval).
  • HarfBuzzUnavailableException — de vlag staat aan maar libharfbuzz is niet bereikbaar via FFI tijdens runtime.

Met de vlag uit rendert een in-scope-run via het bestaande codepoint-naar-cmap-pad. Dat is een gedocumenteerde beperking, geen shapingclaim: het uit-pad past geen OpenType-shaping toe, dus contextuele vormen zijn niet gegarandeerd. Beschrijf uit-pad-uitvoer niet als “geshapet”.

Eerlijkheidsgrens — objectieve pariteit, geen esthetische goedkeuring

Sectie met titel “Eerlijkheidsgrens — objectieve pariteit, geen esthetische goedkeuring”

Shaping-getrouwheid wordt objectief gevalideerd tegen HarfBuzz: de uitgezonden glyph-identificatoren, clustermapping en glyphposities komen overeen met de HarfBuzz-referentie-uitvoer (glyph-, cluster- en positiepariteit). Een esthetische beoordeling door een moedertaalspreker — die beoordeelt of het resultaat natuurlijk leest voor een vloeiende lezer — is een bijgehouden post-shipvervolg. NextPDF maakt geen taalkwaliteitsclaim in deze API of in deze documentatie. Objectieve pariteit wordt beweerd; esthetische kwaliteit niet.

SymboolLocatieRol
CssFeatureFlags::$complexTextShapingsrc/Html/CssFeatureFlags.phpOpt-in-vlag voor de Tibetaanse/Mongoolse shaper (standaard false).
Config::withCssFeatureFlags(CssFeatureFlags $flags): selfsrc/Core/Config.phpKoppelt de vlaggenset aan een documentconfiguratie.
ComplexScriptShapingExceptionsrc/Font/Shaper/ComplexScriptShapingException.phpGegooid wanneer een in-scope-run niet getrouw kan worden geshapet.
HarfBuzzUnavailableExceptionsrc/Font/Shaper/HarfBuzzUnavailableException.phpGegooid wanneer de vlag aan staat maar libharfbuzz niet beschikbaar is.
<?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');

Registreer een shapingvaardig font, schakel de shaper in, en handel de twee getypeerde foutmodi expliciet af. Een getrouwe render of een duidelijke exception — nooit een stilletjes kapotte glyphrun.

<?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 is vereist wanneer aan. Met de vlag aan en libharfbuzz afwezig gooit de engine HarfBuzzUnavailableException. Hij degradeert niet stilletjes.
  • Uit is niet “geshapet”. Met de vlag uit rendert een in-scope-run via het cmap-pad zonder OpenType-shaping. Dit is een gedocumenteerde beperking; noem het geen geshapete uitvoer.
  • Het bereik is Tibetaans en Mongools. Andere complexe schriften vallen buiten het bereik van dit deel.
  • Een link in de run faalt gesloten. Een run die een linkannotatie bevat, werpt ComplexScriptShapingException, omdat de linkrechthoek geshapete herordening niet kan volgen.
  • Geen taalkwaliteitsclaim. Pariteit met HarfBuzz wordt beweerd; moedertaalspreker-esthetische kwaliteit is een bijgehouden vervolg en wordt niet geclaimd.

Shaping voegt één libharfbuzz-aanroep per in-scope-run toe, plus de glyph-uitzendpass, lineair in het aantal glyphs. Het budget (wall_ms: 2000, peak_mb: 128) volgt het CJK/complex-script-profiel, omdat shapingfonts groot zijn en fontverwerking de kosten domineert.

Het inschakelen van de shaper introduceert een FFI-aanroep naar libharfbuzz, een native library. Fontbestanden blijven niet-vertrouwde binaire invoer die door de bestaande validatie van de typografielaag wordt afgehandeld voordat ze de shaper bereiken. De shaper verbruikt reeds geregistreerde, reeds gevalideerde letterbeelden. Behandel de herkomst van door eindgebruikers geleverde fonts als niet-vertrouwd, en lever libharfbuzz uit een vertrouwde bron.

StatementSpecClause
Geshapete runs worden uitgezonden als Identity-H two-byte CIDs in een composite Type 0-font.ISO 32000-2§9.7.4
De shaper past de OpenType-glyphsubstitutie en -positionering van het font toe.OpenType SpecificationGSUB / GPOS
Clustervorming volgt de schrifteigenschappen voor Tibetaans en Mongools.Unicode Standard AnnexTibetan and Mongolian

Dit is een previewimplementatie gericht op Tibetaans en Mongools, gevalideerd op objectieve HarfBuzz-pariteit. Het maakt geen taalkwaliteitsclaim en beweert geen end-to-end PDF-conformiteit voor het geproduceerde bestand. Er wordt geen standaardtekst gereproduceerd.