Lewati ke konten
getnextpdf.com

stabilitas: Eksperimental

Dukungan shaping skrip-kompleks

Preview opt-in. Shaping skrip-kompleks default-mati. Saat mati, mesin merender melalui jalur codepoint-ke-cmap yang sudah ada — byte-identik dengan build tanpa fitur tersebut. Aktifkan hanya saat Anda memiliki libharfbuzz dan font yang mampu melakukan shaping, dan validasi hasilnya.

Perender HTML menambahkan shaper skrip-kompleks yang opt-in untuk Tibet dan Mongolia. Saat shaper aktif, sebuah run Tibet atau Mongolia dalam-cakupan yang terdeteksi di-shape melalui libharfbuzz dan dipancarkan sebagai kode glyph Identity-H. Shaper mencakup Tibet horizontal pada face TrueType dan CFF/OTTO, termasuk pembungkusan, serta Mongolia vertikal yang disusun dari atas ke bawah (TTB).

Terminal window
composer require nextpdf/core:^3

Shaper disertakan dalam paket core. Opt-in CssFeatureFlags::$complexTextShaping adalah @since 6.1.0. libharfbuzz adalah persyaratan runtime saat flag aktif — shaper memanggil libharfbuzz melalui ekstensi FFI PHP. Saat flag mati, pustaka tidak memiliki dependensi libharfbuzz.

Skrip kompleks menyusun ulang, mensubstitusi, dan memreposisi glyph menurut konteks. Pemetaan codepoint-ke-glyph yang naif merendernya dengan jelas keliru. Shaper menyerahkan sebuah run dalam-cakupan ke libharfbuzz, yang menerapkan tabel shaping OpenType font, dan mesin memancarkan urutan glyph yang dihasilkan sebagai font Type 0 komposit dengan encoding Identity-H (ISO 32000-2 §9.7.4 — string yang ditampilkan adalah CID dua-byte).

Cakupannya disengaja. Shaper mengenali run Tibet dan Mongolia dan men-shape-nya; ia tidak mengklaim cakupan skrip-kompleks umum. Tibet horizontal di-shape pada face TrueType dan CFF/OTTO, dengan pembungkusan baris. Mongolia di-shape secara vertikal, dari atas ke bawah.

Shaper tidak pernah memancarkan glyph yang tak-di-shape dan rusak secara visual sebagai fallback. Sebuah run yang tidak dapat di-shape secara setia akan memunculkan eksepsi bertipe sebagai gantinya:

  • ComplexScriptShapingException — run tidak dapat di-shape secara setia: font tidak memiliki glyph yang dibutuhkan (sebuah .notdef akan dihasilkan), sebuah face CFF diminta men-shape pada jalur vertikal, run berisi sebuah tautan, atau sebuah kolom Mongolia membutuhkan pembungkusan (kasus di luar cakupan).
  • HarfBuzzUnavailableException — flag aktif tetapi libharfbuzz tidak dapat dijangkau melalui FFI pada runtime.

Dengan flag mati, sebuah run dalam-cakupan dirender melalui jalur codepoint-ke-cmap yang sudah ada. Itu adalah keterbatasan terdokumentasi, bukan klaim shaping: jalur mati tidak menerapkan shaping OpenType, sehingga bentuk kontekstual tidak dijamin. Jangan jelaskan keluaran jalur-mati sebagai “di-shape”.

Batas kejujuran — paritas objektif, bukan persetujuan estetis

Bagian berjudul “Batas kejujuran — paritas objektif, bukan persetujuan estetis”

Fidelitas shaping divalidasi secara objektif terhadap HarfBuzz: pengenal glyph yang dipancarkan, pemetaan cluster, dan posisi glyph cocok dengan keluaran referensi HarfBuzz (paritas glyph, cluster, dan posisi). Tinjauan estetis oleh penutur asli — menilai apakah hasilnya terbaca alami bagi pembaca fasih — merupakan tindak lanjut pasca-rilis yang dilacak. NextPDF tidak membuat klaim kualitas-bahasa apa pun dalam API ini atau dalam dokumen ini. Paritas objektif ditegaskan; kualitas estetis tidak.

SimbolLokasiPeran
CssFeatureFlags::$complexTextShapingsrc/Html/CssFeatureFlags.phpFlag opt-in untuk shaper Tibet/Mongolia (default false).
Config::withCssFeatureFlags(CssFeatureFlags $flags): selfsrc/Core/Config.phpMelampirkan kumpulan flag ke konfigurasi dokumen.
ComplexScriptShapingExceptionsrc/Font/Shaper/ComplexScriptShapingException.phpDilempar saat run dalam-cakupan tidak dapat di-shape secara setia.
HarfBuzzUnavailableExceptionsrc/Font/Shaper/HarfBuzzUnavailableException.phpDilempar saat flag aktif tetapi libharfbuzz tidak tersedia.
<?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');

Daftarkan sebuah font yang mampu melakukan shaping, opt-in ke shaper, dan tangani kedua mode kegagalan bertipe secara eksplisit. Render yang setia atau eksepsi yang jelas — tidak pernah run glyph yang diam-diam rusak.

<?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 diperlukan saat aktif. Dengan flag aktif dan libharfbuzz tidak ada, mesin melempar HarfBuzzUnavailableException. Ia tidak diam-diam terdegradasi.
  • Mati bukan “di-shape”. Dengan flag mati, sebuah run dalam-cakupan dirender melalui jalur cmap tanpa shaping OpenType. Ini adalah keterbatasan terdokumentasi; jangan menyebutnya keluaran yang di-shape.
  • Cakupannya Tibet dan Mongolia. Skrip kompleks lain berada di luar cakupan untuk irisan ini.
  • Tautan di dalam run gagal secara fail-closed. Sebuah run yang berisi anotasi tautan memunculkan ComplexScriptShapingException, karena persegi panjang tautan tidak dapat mengikuti penataan-ulang yang di-shape.
  • Tidak ada klaim kualitas-bahasa. Paritas dengan HarfBuzz ditegaskan; kualitas estetis oleh penutur asli adalah tindak lanjut yang dilacak dan tidak diklaim.

Shaping menambah satu panggilan libharfbuzz per run dalam-cakupan, plus lintasan pancaran-glyph, linear terhadap jumlah glyph. Anggaran (wall_ms: 2000, peak_mb: 128) mengikuti profil CJK/skrip-kompleks, karena font shaping berukuran besar dan penanganan font mendominasi biaya.

Mengaktifkan shaper memperkenalkan panggilan FFI ke libharfbuzz, sebuah pustaka native. Berkas font tetap merupakan masukan biner tak-tepercaya yang ditangani validasi yang sudah ada pada lapisan tipografi sebelum mencapai shaper. Shaper mengonsumsi face yang sudah terdaftar dan sudah divalidasi. Perlakukan asal-usul font yang dipasok pengguna-akhir sebagai tak-tepercaya, dan sediakan libharfbuzz dari sumber yang tepercaya.

PernyataanStandarKlausul
Run yang di-shape dipancarkan sebagai CID dua-byte Identity-H dalam font Type 0 komposit.ISO 32000-2§9.7.4
Shaper menerapkan substitusi dan pemosisian glyph OpenType font.OpenType SpecificationGSUB / GPOS
Pembentukan cluster mengikuti properti skrip untuk Tibet dan Mongolia.Unicode Standard AnnexTibetan and Mongolian

Ini adalah implementasi preview yang dicakupkan ke Tibet dan Mongolia, divalidasi untuk paritas objektif HarfBuzz. Ia tidak membuat klaim kualitas-bahasa dan tidak menegaskan konformitas PDF ujung-ke-ujung untuk berkas yang dihasilkan. Tidak ada teks standar yang direproduksi.