PDFlib Cookbook

cookbook

complex_scripts/arabic_formatting

Arabic formatting issues.

Download PHP Code  Switch to Java Code  Show Output 

<?php
/*
 * Starter sample for Arabic text formatting
 * Demonstrate various formatting topics specific for the Arabic script;
 * Additional aspects are demonstrated in the bidi_formatting Cookbook topic.
 * 
 * Required software: PDFlib/PDFlib+PDI/PPS 9
 * Required data: Arabic fonts
 */

/* This is where the data files are. Adjust as necessary. */
$searchpath = dirname(__FILE__,3)."/input";
$outfile = "";

$llx = 50; $lly = 50; $urx = 800; $ury = 550;

$header = array( "Arabic formatting topic", "Raw input",
    "Reordered and shaped output" );

class shaping {
    function __construct($optlist, $language, $text) {
        $this->fontopt = "fontname=NotoNaskhArabic-Regular encoding=unicode fallbackfonts={ {fontname=NotoSerif-Regular encoding=unicode} }";
        $this->optlist = $optlist;
        $this->language = $language;
        $this->text = $text;
    }
}

$shapingsamples = array(
        new shaping(
        "shaping script=arab",
        "Add vowels to base consonants",
        "\u{0643}\u{0650}\u{062A}\u{064E}\u{0627}\u{0628}"),
        
    new shaping(
        "shaping script=arab charref",
        "Isolated form of HEH could be confused with digit FIVE (wrong)",
        "\u{0661}\u{0663}\u{0666}\u{0665} \u{0647}"),
                
    new shaping(
        "shaping script=arab charref",
        "Force initial form of HEH with ZERO WIDTH JOINER",
        "\u{0661}\u{0663}\u{0666}\u{0665} \u{0647}&ZWJ;"),

    new shaping(
        "shaping script=arab charref",
        "Persian plural with joined character (wrong; only for comparison)",
        "\u{0645}\u{0648}\u{0632}\u{0647}\u{0647}\u{0627}"),

    new shaping(
        "shaping script=arab charref",
        "Prevent character join with ZERO WIDTH NON-JOINER",
        "\u{0645}\u{0648}\u{0632}\u{0647}&ZWNJ;\u{0647}\u{0627}"),
        
    new shaping(
        "shaping script=arab charref",
        "Abbreviation with character join (wrong; only for comparison)",
        "\u{0623}\u{064A}\u{0628}\u{064A}\u{0625}\u{0645}"),

    new shaping(
        "shaping script=arab charref",
        "Prevent character join with ZERO WIDTH NON-JOINER",
        "\u{0623}\u{064A}&ZWNJ;\u{0628}\u{064A}&ZWNJ;\u{0625}\u{0645}"),
            
    new shaping(
        "shaping script=arab",
        "Single-glyph ligature",
        "\u{0627}\u{0644}\u{0644}\u{0651}\u{0670}\u{0647}"),

    new shaping(
        "shaping script=arab",
        "European digits",
        "0123456789"),

    new shaping(
        "shaping script=arab",
        "Arabic-Indic digits U+0660 etc.",
        "\u{0660}\u{0661}\u{0662}\u{0663}\u{0664}\u{0665}\u{0666}\u{0667}\u{0668}\u{0669}"),

    new shaping(
        "shaping script=arab",
        "Text without elongation",
        "\u{062D}\u{0642}\u{0648}\u{0642} " .
        "\u{0627}\u{0644}\u{0627}\u{0646}\u{0633}\u{0627}\u{0646}"),

    new shaping(
        "shaping script=arab",
        "Tatweel (kashida) elongation",
        "\u{062D}\u{0642}\u{0640}\u{0640}\u{0648}\u{0642} " .
        "\u{0627}\u{0644}\u{0627}\u{0646}\u{0633}\u{0640}\u{0640}\u{0627}\u{0646}"),

    new shaping(
        "shaping script=arab",
        "More tatweel elongation",
        "\u{062D}\u{0642}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0648}\u{0642} " .
        "\u{0627}\u{0644}\u{0627}\u{0646}\u{0633}" .
        "\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}" .
        "\u{0627}\u{0646}"),

    new shaping(
        "shaping script=arab",
        "Even more tatweel elongation",
        "\u{062D}\u{0642}" .
        "\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}" .
        "\u{0648}\u{0642} " .
        "\u{0627}\u{0644}\u{0627}\u{0646}\u{0633}" .
        "\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}\u{0640}" .
        "\u{0627}\u{0646}"),
);

try {
    $p = new PDFlib();

    $p->set_option("searchpath={" . $searchpath . "}");

    /*
     * This means that formatting and other errors will raise an
     * exception. This simplifies our sample code, but is not
     * recommended for production code.
     */
    $p->set_option("errorpolicy=exception");
    $p->set_option("stringformat=utf8");

    /* Set an output path according to the name of the topic */
    if ($p->begin_document($outfile, "") == 0) {
        throw new Exception("Error: " . $p->get_errmsg());
    }

    $p->set_info("Creator", "PDFlib Cookbook");
    $p->set_info("Title", "arabic_formatting");

    $table = 0;

    /* Create table header */
    for ($col = 0; $col < count($header); $col++) {
        $optlist =
                "margin=4 " .
            "fittextline={fontname=NotoSerif-Bold encoding=unicode "
            . "fontsize=14} colwidth=" . ($col == 0 ? "50%" : "25%");
        $table = $p->add_table_cell($table, $col + 1, 1, $header[$col],
                $optlist);
    }

    /* Create shaping samples */
    for ($i = 0; $i < count($shapingsamples); $i++) {
        $sample = $shapingsamples[$i];

        $col = 1;
        $row = $i + 2;

        /* Column 1: description */
        $optlist = "margin=4 fittextline={fontname=NotoSerif-Regular "
                . "encoding=unicode fontsize=12 position={left center}}";
        $table = $p->add_table_cell($table, $col++, $row, $sample->language,
                $optlist);

        /* Column 2: raw text */
        $optlist = "margin=4 fittextline={" . $sample->fontopt
                . " fontsize=12 position={left center}}";
        $table = $p->add_table_cell($table, $col++, $row, $sample->text,
                        $optlist);

        /* Column 3: shaped and reordered text */
        $optlist =
            "margin=4 fittextline={" . $sample->fontopt . " fontsize=12 "
            . $sample->optlist . " position={right center}}";
        $table = $p->add_table_cell($table, $col++, $row, $sample->text,
                $optlist);
    }

    /* ---------- Place the table on one or more pages ---------- */
    /*
     * Loop until all of the table is placed; create new pages as long
     * as more table instances need to be placed.
     */
    do {
        $p->begin_page_ext(0, 0, "width=a4.height height=a4.width");

        /* Shade every other row; draw lines for all table cells. */
        $optlist = "header=1 fill={{area=rowodd "
                . "fillcolor={gray 0.9}}} stroke={{line=other}} ";

        /* Place the table instance */
        $result = $p->fit_table($table, $llx, $lly, $urx, $ury, $optlist);

        if ($result == "_error") {
            throw new Exception("Couldn't place table: "
                    . $p->get_errmsg());
        }

        $p->end_page_ext("");

    }
    while ($result == "_boxfull");

    $p->end_document("");
    $buf = $p->get_buffer();
    $len = strlen($buf);

    header("Content-type: application/pdf");
    header("Content-Length: $len");
    header("Content-Disposition: inline; filename=arabic_formatting.pdf");
    print $buf;

}

catch (PDFlibException $e) {
    echo("PDFlib exception occurred in arabic_formatting sample:\n" .
        "[" . $e->get_errnum() . "] " . $e->get_apiname() . ": " .
        $e->get_errmsg() . "\n");
    exit(1);
}
catch (Throwable $e) {
    echo($e);
    exit(1);
}

$p = 0;

?>