Przejdź do głównej zawartości

Tekst: granica kształtowania, CJK i obsługa przebiegów

Moduł tekstu definiuje granicę kształtowania. Udostępnia niewielki interfejs, który zamienia przebieg w 8-bitowym formacie Unicode Transformation Format (UTF-8) na rozmieszczone glify, wybiera rzeczywiste zaplecze OpenType, gdy jest dostępne, deterministycznie przełącza się na rozwiązanie awaryjne, gdy takiego zaplecza nie ma, oraz udostępnia rejestr modułów kształtujących właściwych dla poszczególnych pism.

Okno terminala
composer require nextpdf/core:^3

ShaperInterface łączy potok układu tekstu z silnikiem kształtowania OpenType. Celowo pozostaje niewielki: jedna metoda shape() przyjmuje obiekt ShaperInput i zwraca obiekt ShapingResult. Ten typ zwracany jest jedynym wynikiem widocznym dla konsumentów. Implementacje nie mogą ujawniać szczegółów wewnętrznych silnika kształtowania, a typowana wartość zwracana wymusza tę granicę. ShapingResult zawiera listę rekordów GlyphRun, odwzorowany tekst źródłowy, pismo i kierunek oraz znacznik shaperImpl, który identyfikuje zaplecze odpowiedzialne za wytworzenie wyniku.

Wybór zaplecza jest jawny i raportuje możliwości bez zgadywania. ShaperFactory wykonuje jednorazowe sondowanie możliwości. Jeśli host ma działające powiązanie HarfBuzz, create() zwraca moduł kształtujący oparty na HarfBuzz. W przeciwnym razie zwraca NullShaper. NullShaper jest przepuszczającym rozwiązaniem awaryjnym. Emituje jeden syntetyczny glif na każdy punkt kodowy Unicode, z zerowymi krokami i zerowymi przesunięciami. Oznacza wynik, aby narzędzia obserwowalności mogły wykryć rozwiązanie awaryjne, a rozwiązywanie kroków pozostawia modułowi metryk czcionek. Ta ścieżka jest udokumentowaną degradacją, a nie pełnym kształtowaniem. Podstawianie, ligatury, pozycjonowanie znaków diakrytycznych oraz formy kontekstowe wymagają rzeczywistego zaplecza. wouldUseRealShaper() jest predykatem diagnostycznym. Kod produkcyjny powinien zamiast tego rozgałęziać się na podstawie znacznika shaperImpl w wyniku.

Kształtowanie właściwe dla danego pisma to interfejs dostawcy usługi (SPI), a nie dołączona implementacja. ScriptShaperRegistry jest rejestrem w stylu PHP Standards Recommendation 11 (PSR-11), który rozwiązuje interfejs MongolianShaperInterface lub TibetanShaperInterface według tagu pisma International Organization for Standardization (ISO) 15924. Rejestr przechowuje klucze bez rozróżniania wielkości liter i opiera się na jednym źródle prawdy dla ważności kodów pism. Rejestr i interfejsy modułów kształtujących dla pism stanowią zamrożony kontrakt, więc rozszerzenie może zarejestrować dostawcę z fazy 12 bez naruszania miejsc wywołań. Silnik dostarcza granicę. Konsumenci dostarczają dostawców dla pism złożonych.

Obsługa przebiegów dla pism chińskiego, japońskiego i koreańskiego (CJK) znajduje się na granicy kodowania typografii. Osadzony krój TrueType CJK jest emitowany jako czcionka typu Type 0 z mapą CMap Identity-H oraz potomkiem CIDFontType2, zgodnie z ISO 32000-2 §9.7.4 (skrót retrieval-augmented generation (RAG) został obcięty ze względu na limit licencji; zapisany w _downgraded-claims-o3.md). Gdy program TrueType jest osadzony, czcionka CIDFont typu Type 2 odwzorowuje identyfikatory znaków na indeksy glifów poprzez wpis CIDToGIDMap, zgodnie z ISO 32000-2 §9 (skrót przypięty na stronie kontraktu B1). Mechanizm tworzenia podzbioru zachowuje oryginalną numerację glifów, dzięki czemu /CIDToGIDMap /Identity pozostaje prawidłowy dla podzbioru. CjkFontValidator sprawdza, czy kandydująca czcionka obejmuje bloki Unicode wymagane przez dane pismo, zanim zostanie wybrana.

TypRodzajKluczowe składoweStabilnośćOd wersji
ShaperInterfaceinterfejsshape(ShaperInput): ShapingResultstabilny3.2.0
ShaperFactoryklasa finaldefault(), create(), wouldUseRealShaper()stabilny3.2.0
NullShaperklasa final readonlyprzepuszczający moduł kształtujący do obsługi awaryjnejstabilny3.2.0
ShapingResultklasa final readonly$glyphRuns, $originalText, $script, $direction, $shaperImplstabilny3.2.0
ScriptShaperRegistryklasa finalregisterMongolian(), getMongolian(), hasMongolian() oraz odpowiedniki dla pisma tybetańskiegostabilny3.1.0
CjkFontValidatorklasa finalvalidateCoverage(), detectScript(), isCjkCodepoint()stabilny1.0.0

Kształt metod register*, get* i has* w ScriptShaperRegistry oraz interfejsy modułów kształtujących dla pism stanowią zamrożony kontrakt. Z założenia ShapingResult pozostaje jedynym wynikiem modułu kształtującego widocznym dla konsumentów.

examples/text/shaper-factory.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Font\Shaper\ShaperFactory;
use NextPDF\Font\Shaper\ShaperImpl;
$factory = ShaperFactory::default();
$shaper = $factory->create();
// Branch on the result tag, not on the concrete class.
$wouldShape = $factory->wouldUseRealShaper()
? 'HarfBuzz backend available'
: 'NullShaper fallback (degraded — no substitution or positioning)';
echo $wouldShape, "\n";

ShaperFactory::default() konfiguruje produkcyjne sondowanie możliwości. create() zapamiętuje wybrane zaplecze przez cały czas życia fabryki. Użyj wouldUseRealShaper() oraz znacznika shaperImpl w każdym wyniku, aby sprawdzić możliwości.

examples/text/script-shaper-registry.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Text\Shaping\MongolianShaperInterface;
use NextPDF\Text\Shaping\ScriptShaperRegistry;
final readonly class ComplexScriptBootstrap
{
public function __construct(private ScriptShaperRegistry $registry) {}
/**
* Register a consumer-supplied Mongolian shaper provider at boot so
* the layout pipeline can resolve it by ISO 15924 script tag.
*/
public function register(MongolianShaperInterface $mongolian): void
{
$this->registry->registerMongolian($mongolian);
}
public function hasMongolian(): bool
{
return $this->registry->hasMongolian();
}
}

Rejestr jest punktem integracji dla dostawców pism złożonych. Silnik dostarcza granicę i zamrożoną postać akcesorów. Konsumenci dostarczają implementacje dla pisma mongolskiego i tybetańskiego.

  • Wynik NullShaper ma zerowe kroki i zerowe przesunięcia. Nie przekazuj tych pozycji bezpośrednio do układu tekstu. Rozwiązuj kroki za pomocą modułu metryk czcionek i wykrywaj rozwiązanie awaryjne przez znacznik shaperImpl.
  • Puste wejście daje pustą listę glyphRuns, a nie pusty przebieg. Kod iteracji po stronie konsumenta nie potrzebuje specjalnego przypadku dla przebiegu o zerowej długości.
  • ScriptShaperRegistry nie implementuje bezpośrednio Psr\Container\ContainerInterface, dzięki czemu typowane akcesory zachowują zawężony typ zwracany w analizie statycznej. Używaj getMongolian() i getTibetan(), a nie ogólnego get().
  • Dopasowanie tagów pism odbywa się według kanonicznej wartości alpha-4 ISO 15924 i są one przechowywane bez rozróżniania wielkości liter. Przekaż Mong lub Tibt. Wielkość liter nie wpływa na wyszukiwanie.
  • Znaki CJK Extension B znajdują się w płaszczyźnie 2 Unicode i wymuszają w podzbiorze podtablicę cmap w formacie Format 12. Ścieżka kodowania obsługuje ten przypadek. Nie zakładaj, że podstawowa płaszczyzna wielojęzyczna obejmuje cały tekst CJK.

Sondowanie możliwości wykonuje się raz dla każdej instancji ShaperFactory, a zaplecze jest zapamiętywane, więc powtarzane wywołania create() nie generują kosztu. NullShaper działa liniowo względem liczby punktów kodowych w przebiegu wejściowym i nie wykonuje operacji input/output (I/O). Rozwiązywanie w ScriptShaperRegistry jest wyszukiwaniem po kluczu w stałym czasie. CjkFontValidator próbkuje punkty kodowe z określonym krokiem, zamiast testować każdy z osobna, co utrzymuje niski koszt sprawdzania pokrycia nawet w przypadku czcionki CJK o 20,000 glifach. performance_budget wynoszący 1500 ms czasu rzeczywistego i 64 MB szczytowego zużycia pamięci obejmuje typowy przebieg. Przy rzeczywistym kształtowaniu dominującym kosztem jest zaplecze OpenType. Gdy rozwiązanie awaryjne jest aktywne, koszt ten pozostaje poza zakresem tego modułu.

Granica modułu kształtującego przyjmuje ciąg znaków UTF-8. NullShaper toleruje nieprawidłowy UTF-8, dzieląc tekst najlepiej, jak potrafi, zamiast zgłaszać błąd, ponieważ udokumentowany kontrakt rozwiązania awaryjnego oznacza już „brak rzeczywistego kształtowania”. Kod wywołujący jest przygotowany na wynik niskiej jakości. Kontrakt klastrów oparty na przesunięciach bajtowych używa długości wyrażonej w bajtach, co jest poprawne dla wejścia wielobajtowego i pozwala uniknąć defektu odwzorowania klastrów przesuniętego o jeden punkt kodowy. Jeśli jest dostępne, rzeczywiste zaplecze jest natywną biblioteką innej firmy. Traktuj jej wejście jako niezaufane i ograniczaj długość przebiegu wcześniej w przepływie. Rejestr modułów kształtujących dla pism przechowuje dostawców dostarczonych przez konsumenta. Te implementacje znajdują się w granicy zaufania konsumenta, a nie silnika.

TwierdzenieNormaKlauzulaDowód
Osadzony krój TrueType CJK jest emitowany jako czcionka typu Type 0 z mapą CMap Identity-H oraz potomkiem CIDFontType2.ISO 32000-2§9.7.4Skrót retrieval-augmented generation (RAG) obcięty ze względu na limit licencji; prefiks 7a5258772f508e3b, zob. _downgraded-claims-o3.md
Osadzona czcionka CIDFont typu Type 2 odwzorowuje identyfikatory znaków na indeksy glifów poprzez CIDToGIDMap.ISO 32000-2§9

Obie klauzule są parafrazowane. Druga ma przypięty skrót (ponownie wykorzystany ze strony kontraktu B1), a pierwsza jest potwierdzona przez ADR-013 oraz przegląd dla programistów kodera cmap. NextPDF nie reprodukuje tekstu normatywnego. Zaplecze modułu kształtującego jest niezależne od zgodności z formatem Portable Document Format (PDF). Twierdzenia o zgodności dotyczą tutaj emisji słownika czcionek CJK przez granicę kodowania. ADR-013 oraz przegląd dla programistów kodera cmap dokumentują tę ścieżkę bardziej szczegółowo.

Zaawansowany potok wstępnego przetwarzania tekstu oraz usługi ekstrakcji korzystają z granicy modułu kształtującego pakietu Core i z typów wartości obsługujących przebiegi. Moduł tekstu pakietu Core dostarcza granicę, rozwiązanie awaryjne oraz rejestr modułów kształtujących dla pism bez licencji. Brak łącza konwersji jest zamierzony.