コンテンツにスキップ

右から左に書くアラビア語 HTML をレンダリングする

writeHtml() を使って、右から左に書く(RTL)HTML を PDF にレンダリングします。CSS の direction: rtl プロパティを設定し、アラビア語対応フォントを登録します。エンジンは Unicode 双方向アルゴリズム(UAX #9)に基づいてテキストを視覚的順序に並べ替え、アラビア語の文字を文脈依存の字形にシェーピングします。このレシピでは、小さなアラビア語の請求書をレンダリングします。RTL はアラビア語、ヘブライ語、ペルシア語、ウルドゥー語に適用されます。ヘブライ語は並べ替えの対象ですが、シェーピングは行われません。これは、この文字体系では正しい動作です。

Terminal window
composer require nextpdf/core

加えて、アラビア語対応の TrueType または OpenType フォントが必要です。その文字マップは、アラビア語 Presentation Forms-B ブロックをカバーしていなければなりません。Noto Naskh Arabic と Amiri は、適切なオープンライセンスの書体です。

RTL レンダリングには 2 つの入力が必要です。CSS の direction: rtl プロパティと、登録済みのアラビア語フォントです。

direction: rtl は、テキストを右から左へ配置するようレイアウトに指示します。続いて、エンジンは Unicode 双方向アルゴリズム(UAX #9)を使って視覚的順序を解決します。混在したコンテンツも正しく順序付けられます。ラテン文字の語、アラビア語の語、数字は、それぞれ固有の方向を保ちます。アラビア語のテキストに続く数字は、左から右のまま維持されます。

アラビア語は筆記体(カーシブ)の文字体系であり、各文字は隣接する文字に応じて異なる字形(グリフ)を使用します。エンジンは各文字について語頭形、語中形、語末形、または独立形を選択し、Lam-Alef リガチャを適用します。この文脈依存シェーピングには、文字マップがアラビア語 Presentation Forms-B ブロックをカバーするフォントが必要です。標準 14 書体を含むラテン文字専用フォントでは、アラビア語を描画できません。

表内では、各セルが個別に並べ替えられ、シェーピングされます。セルは開始エッジ、つまり direction: rtl では右端に揃えられます。論理的な text-align の値である startend は方向に応じて解決されるため、RTL コンテンツでは start が右端にマッピングされます。

方向は CSS の direction プロパティで設定します。HTML の dir 属性はこのプロパティにマッピングされません。現在の実装上の境界については、RTL — 現在の制限を参照してください。

シンボル場所役割
Document::writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutput現在のカーソル位置への HTML フラグメントのレンダリング
FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfoNextPDF\Typography\FontRegistryエイリアスに紐づくアラビア語書体の登録
DocumentFactory::create(): DocumentNextPDF\Core\DocumentFactory設定済みレジストリを読み取るドキュメントの作成

このサンプルでは、次の CSS プロパティを使用します。directionfont-familytext-align。登録済みフォントは、CSS の font-family からレジストリエイリアスで参照します。

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
$fontRegistry = new FontRegistry();
$fontRegistry->register(__DIR__ . '/NotoNaskhArabic-Regular.ttf', alias: 'ArabicFont');
$documentFactory = new DocumentFactory($fontRegistry, new ImageRegistry(maxCacheBytes: 0));
$doc = $documentFactory->create();
$doc->addPage();
$doc->writeHtml(
'<div style="direction: rtl; font-family: \'ArabicFont\';">'
. '<h1>فاتورة</h1>'
. '<p>المبلغ الإجمالي 380.00</p>'
. '</div>'
);
$doc->save(__DIR__ . '/rtl-arabic.pdf');

見出しは右から左にレンダリングされ、数字 380.00 はアラビア語の文中でも左から右のまま保持されます。

この自己完結したサンプルでは、アラビア語の請求書の表をレンダリングします。各セルに direction: rtl と登録済みのアラビア語フォントが指定されているため、エンジンはすべての行を並べ替えてシェーピングし、その後セルを右端に揃えます。

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
// Supply an Arabic-capable face whose cmap covers Arabic Presentation Forms-B.
// Embed only fonts you are licensed to embed.
$fontPath = __DIR__ . '/NotoNaskhArabic-Regular.ttf';
if (!is_file($fontPath)) {
fwrite(STDERR, "Arabic font not found at {$fontPath}\n");
exit(1);
}
$fontRegistry = new FontRegistry();
$fontRegistry->register($fontPath, alias: 'ArabicFont');
$documentFactory = new DocumentFactory($fontRegistry, new ImageRegistry(maxCacheBytes: 0));
$doc = $documentFactory->create();
$doc->setTitle('Arabic invoice');
$doc->addPage();
$html = <<<'HTML'
<div style="direction: rtl; font-family: 'ArabicFont'; font-size: 12pt;">
<h1>فاتورة</h1>
<table style="width: 100%; border-collapse: collapse;">
<tr>
<th style="border: 1px solid #333; padding: 6px;">الوصف</th>
<th style="border: 1px solid #333; padding: 6px;">المبلغ</th>
</tr>
<tr>
<td style="border: 1px solid #333; padding: 6px;">خدمات استشارية</td>
<td style="border: 1px solid #333; padding: 6px;">380.00</td>
</tr>
<tr>
<td style="border: 1px solid #333; padding: 6px;">الإجمالي</td>
<td style="border: 1px solid #333; padding: 6px;">380.00</td>
</tr>
</table>
</div>
HTML;
$doc->writeHtml($html);
$out = getenv('NEXTPDF_OUT');
$doc->save($out !== false ? $out : __DIR__ . '/render-rtl-arabic-html.pdf');
echo "Wrote the Arabic invoice PDF\n";
HTML;$doc->writeHtml($html);$out = getenv('NEXTPDF_OUT');$doc->save($out !== false ? $out : __DIR__ . '/render-rtl-arabic-html.pdf');echo "Wrote the Arabic invoice PDF\n";">
  • ドキュメントを構築する前にフォントを登録してください。 Document::createStandalone() は独自のレジストリを構築するため、別の場所で登録した書体を参照できません。どちらのサンプルでも行っているように、DocumentFactory を通じて構築し、ライターが利用側のレジストリを読み取るようにしてください。
  • CSS の font-family をレジストリエイリアスに一致させてください。 register(..., alias: 'ArabicFont') に渡す名前が、CSS で参照する名前です。
  • HTML の dir 属性ではなく、CSS の direction を使用してください。 レイアウトを切り替えるのは CSS プロパティのみです。
  • アラビア語の後の数字は左から右のまま保持されます。 これは UAX #9 に従います。アラビア語の文字に続くヨーロッパ数字はアラビア数字に解決され、その数字の順序を保つため、380.00 は反転しません。

現在の実装は RTL テキストの並べ替えとシェーピングを行い、表のセルを揃えます。次の境界は残っています。いずれも、将来的な行ごとのインライン書式整形ライン box が必要です。

  • 表の外でのブロックおよびインラインの配置。 表セルの外にあるブロックレベルおよびインラインのテキストは並べ替えられ、シェーピングされますが、開始(左)エッジからレンダリングされます。表以外のテキストの右揃えまたは中央揃え、および text-align: justify による分配は、まだ適用されません。表セルは揃えられます。
  • HTML の dir 属性は direction にマッピングされません。 方向は CSS の direction プロパティで設定してください。
  • 双方向の解決はテキストランごとです。 中立文字は、同じ行上の 2 つのインライン要素(たとえば <span> の隣の <b>)にまたがって解決されません。
  • 狭いアラビア語のカラムは論理テキストで計測されます。 改行位置はシェーピング前の論理テキストで計測されるため、非常に狭いアラビア語のカラムでは、行が少し早く、または少し遅く改行されることがあります。
  • シェーピングされたアラビア語には Presentation Forms-B のカバレッジが必要です。 書体はアラビア語 Presentation Forms-B ブロックをカバーしていなければなりません。OpenType GSUB 置換のみに依存するフォント、および HarfBuzz シェーピングパスは、将来の課題です。アラビア語対応でないフォントではアラビア語を描画できません。

レンダリングはグリフ数に対して線形にスケールします。双方向の並べ替えと文脈依存シェーピングは行ごとに実行され、左から右のテキストに対して小さな定数倍の負荷を加えます。このレシピの予算は wall_ms: 1500, peak_mb: 64 です。

ユーザー指定の文字列は長さを検証し、出力サイズを抑えてください。エンジンはテキストをレンダリングするだけで、解釈もスクリプトの実行も行いません。リモートの @font-face ソースからフォントを読み込む場合、その取得はセキュアな外部リソースポリシーによって管理されます。予測可能な出力にするには、ローカルのフォントファイルを使用することをおすすめします。

記述仕様条項reference_id
最も高いレベルから最も低い奇数レベルまで文字ランを反転して生成される視覚的順序Unicode UAX #9§3.3.6 Rule L2 (uax9#3.3.6.p13)814977a77019d728dc562a612098a82dc260f6844f5998eca5fe7a3baf3394af
アラビア語の文字に続くヨーロッパ数字がアラビア数字に解決され、その数字が左から右の順序を保つことUnicode UAX #9§3.3.4 Rule W2 (uax9#3.3.4.p9)5747405357772797d62b3f4ba79328557fa0c4273a1dd5ffa8d996f24c78e120

アラビア語の文脈依存シェーピング(語頭形、語中形、語末形、独立形に加えて Lam-Alef リガチャ)は、テストスイートでカバーされている検証済みのエンジン機能であり、別個の適合性主張ではありません。これには、文字マップがアラビア語 Presentation Forms-B ブロックをカバーするフォントが必要です。

該当なし。