Eseguire il rendering di HTML arabo da destra a sinistra
In sintesi
Sezione intitolata “In sintesi”Eseguire il rendering in PDF di HTML da destra a sinistra (RTL) con writeHtml(). Impostare la proprietà CSS direction: rtl e registrare un font con copertura per l’arabo. Il motore riordina il testo nell’ordine visivo tramite l’algoritmo bidirezionale Unicode (UAX #9) e sagoma le lettere arabe nelle loro forme contestuali. Questa ricetta mostra il rendering di una piccola fattura araba. L’RTL si applica ad arabo, ebraico, persiano e urdu. L’ebraico viene riordinato ma non sagomato; per questa scrittura è il comportamento corretto.
Installazione
Sezione intitolata “Installazione”composer require nextpdf/coreServe inoltre un font TrueType o OpenType con copertura per l’arabo. La sua mappa dei caratteri deve coprire il blocco Arabic Presentation Forms-B. Noto Naskh Arabic e Amiri sono font adatti, distribuiti con licenza aperta.
Panoramica concettuale
Sezione intitolata “Panoramica concettuale”Per il rendering RTL sono necessari due input: la proprietà CSS direction: rtl e un font registrato per l’arabo.
direction: rtl indica all’impaginazione di disporre il testo da destra a sinistra. Il motore usa quindi l’algoritmo bidirezionale Unicode (UAX #9) per risolvere l’ordine visivo. Il contenuto misto viene ordinato correttamente: parole latine, parole arabe e cifre mantengono ciascuna la propria direzione. Un numero dopo testo arabo mantiene le cifre da sinistra a destra.
L’arabo è una scrittura corsiva, quindi ogni lettera usa un glifo diverso a seconda dei caratteri vicini. Il motore seleziona la forma iniziale, mediana, finale o isolata per ciascuna lettera e applica la legatura Lam-Alef. Questa sagomatura contestuale richiede un font la cui mappa dei caratteri copra il blocco Arabic Presentation Forms-B. Un font soltanto latino, inclusi i tipi di carattere standard-14, non può disegnare l’arabo.
In una tabella, il contenuto di ogni cella viene riordinato e sagomato separatamente, e le celle si allineano al bordo iniziale: il bordo destro con direction: rtl. I valori logici di text-align start e end si risolvono rispetto alla direzione, quindi start corrisponde al bordo destro per il contenuto RTL.
Impostare la direzione con la proprietà CSS direction. L’attributo HTML dir non è equivalente. Vedere RTL — limiti attuali per i limiti attuali dell’implementazione.
Superficie dell’API
Sezione intitolata “Superficie dell’API”| Simbolo | Posizione | Ruolo |
|---|---|---|
Document::writeHtml(string $html): static | NextPDF\Core\Concerns\HasTextOutput | Esegue il rendering del frammento HTML alla posizione corrente del cursore. |
FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfo | NextPDF\Typography\FontRegistry | Registra il font arabo sotto un alias. |
DocumentFactory::create(): Document | NextPDF\Core\DocumentFactory | Crea un documento che legge il registro già popolato. |
L’esempio usa queste proprietà CSS: direction, font-family, text-align. Nel CSS font-family, fare riferimento al font registrato tramite il suo alias di registro.
Esempio di codice — Avvio rapido
Sezione intitolata “Esempio di codice — Avvio rapido”<?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');Il titolo viene reso da destra a sinistra e le cifre 380.00 restano da sinistra a destra all’interno della frase araba.
Esempio di codice — Produzione
Sezione intitolata “Esempio di codice — Produzione”Questo esempio autonomo esegue il rendering di una tabella di fattura araba. Ogni cella include direction: rtl e il font arabo registrato, così il motore riordina e sagoma ogni riga, quindi allinea le celle al bordo destro.
<?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";Casi limite e insidie
Sezione intitolata “Casi limite e insidie”- Registrare il font prima di costruire il documento.
Document::createStandalone()costruisce un proprio registro e non può vedere un font registrato altrove. Costruire tramiteDocumentFactory, così il writer legge il registro, come fanno entrambi gli esempi. - Far corrispondere il CSS
font-familyall’alias di registro. Il nome passato aregister(..., alias: 'ArabicFont')è il nome a cui si fa riferimento nel CSS. - Usare il CSS
direction, non l’attributo HTMLdir. Solo la proprietà CSS modifica la direzione dell’impaginazione. - Un numero che segue l’arabo resta da sinistra a destra. Ciò segue UAX #9: un numero europeo che segue una lettera araba si risolve in un numero arabo e mantiene l’ordine delle cifre, quindi
380.00non viene invertito.
RTL — limiti attuali
Sezione intitolata “RTL — limiti attuali”L’implementazione attuale riordina e sagoma il testo RTL e allinea le celle di tabella. Restano questi limiti. Ciascuno richiede un futuro line box di formattazione inline per riga:
- Allineamento di blocco e inline al di fuori delle tabelle. Il testo a livello di blocco e inline al di fuori delle celle di tabella viene riordinato e sagomato, ma viene reso a partire dal bordo iniziale (sinistro). L’allineamento a destra o al centro del testo fuori tabella, e la distribuzione
text-align: justify, non sono ancora applicati. Le celle di tabella, invece, si allineano. - L’attributo HTML
dirnon corrisponde adirection. Impostare la direzione con la proprietà CSSdirection. - La risoluzione bidirezionale avviene per ciascun text run. I caratteri neutri non vengono risolti tra due elementi inline, come uno
<span>accanto a un<b>, sulla stessa riga. - Le colonne arabe strette vengono misurate sul testo logico. Le interruzioni di riga vengono misurate sul testo logico prima della sagomatura, quindi una colonna araba molto stretta può interrompere una riga leggermente in anticipo o in ritardo.
- L’arabo sagomato richiede la copertura di Presentation Forms-B. Il tipo di carattere deve coprire il blocco Arabic Presentation Forms-B. I font che si affidano solo alla sostituzione OpenType GSUB, e il percorso di sagomatura HarfBuzz, restano lavori futuri. Un font non arabo non può disegnare l’arabo.
Prestazioni
Sezione intitolata “Prestazioni”Il rendering scala in modo lineare con il numero di glifi. Il riordino bidirezionale e la sagomatura contestuale vengono eseguiti per riga e aggiungono solo un piccolo fattore costante rispetto al testo da sinistra a destra. Il budget di questa ricetta è wall_ms: 1500, peak_mb: 64.
Note sulla sicurezza
Sezione intitolata “Note sulla sicurezza”Convalidare la lunghezza delle stringhe fornite dall’utente per contenere la dimensione dell’output. Il motore esegue il rendering del testo, non lo interpreta e non esegue alcuno script. Se si carica un font da una sorgente remota @font-face, il recupero è regolato dai criteri relativi alle risorse esterne sicure; preferire un file di font locale per ottenere un output prevedibile.
Conformità
Sezione intitolata “Conformità”| Dichiarazione | Specifica | Clausola | reference_id |
|---|---|---|---|
| L’ordine visivo è prodotto invertendo i run di caratteri dal livello più alto fino al livello dispari più basso. | Unicode UAX #9 | §3.3.6 Rule L2 (uax9#3.3.6.p13) | 814977a77019d728dc562a612098a82dc260f6844f5998eca5fe7a3baf3394af |
| Un numero europeo che segue una lettera araba si risolve in un numero arabo, quindi le sue cifre mantengono l’ordine da sinistra a destra. | Unicode UAX #9 | §3.3.4 Rule W2 (uax9#3.3.4.p9) | 5747405357772797d62b3f4ba79328557fa0c4273a1dd5ffa8d996f24c78e120 |
La sagomatura contestuale dell’arabo (forme iniziale, mediana, finale e isolata più la legatura Lam-Alef) è una capacità verificata del motore e coperta dalla suite di test, non una dichiarazione di conformità a sé stante. Richiede un font la cui mappa dei caratteri copra il blocco Arabic Presentation Forms-B.
Contesto commerciale
Sezione intitolata “Contesto commerciale”Non applicabile.
Vedere anche
Sezione intitolata “Vedere anche”- HTML: sottosistema di rendering da HTML+CSS a PDF — il motore
writeHtml()e il suo supporto RTL. - Tipografia: registro dei font, subsetting, CMap, codifica, BiDi — il motore bidirezionale che risolve UAX #9.
- Matrice di supporto di font e scritture — quali scritture può disegnare ciascuna classe di font.
- Eseguire il rendering dell’HTML in una pagina PDF — il punto di partenza da sinistra a destra.