Home > Net >  PDFLib how to print name value pairs?
PDFLib how to print name value pairs?

Time:11-10

I'm using PDFLib (this library expected output

I know the easiest solution would be to use a table, but I can't because the PDF has to be accessible and they told me that, on PDF, a table to show name-value paris would not be accessible, so I have to find another solution instead of table.

Currently I tried with Textflow:

<?php
$upperX = 525;
$upperY = 780;
$lowerX = 70;
$lowerY = 50;

$y = $upperY;
$x = 70;

$pdf = new \PDFlib();
$pdf->begin_document('', '');
$pdf->begin_page_ext(0, 0, 'width=a4.width height=a4.height');

// Write "Name-Value paris:"
$optlist = "fontname={Helvetica} fontsize=8 encoding=utf8 alignment=center fakebold=true";
$tf = 0;
$tf = $pdf->add_textflow($tf, "Name-Value paris:", $optlist);
$pdf->fit_textflow($tf, $x, $lowerY, $upperX, $y, '');
$pdf->delete_textflow($tf);

$y -= 10;

// Write the pairs
$label_optlist = "fontname={Helvetica} fontsize=7 encoding=utf8 fakebold=true leftindent=0%";
$value_optlist = "fontname={Helvetica} fontsize=7 encoding=utf8 fakebold=false leftindent=22%";

$tf = 0;
$tf = $pdf->add_textflow($tf, "Name:", $label_optlist);
$tf = $pdf->add_textflow($tf, "John", $value_optlist);
$pdf->fit_textflow($tf, $x, $lowerY, $upperX, $y, '');
$pdf->delete_textflow($tf);
$y = $pdf->get_option('texty', ''); // Get Y where the above textflow ends

$tf = 0;
$tf = $pdf->add_textflow($tf, "Surname:", $label_optlist);
$tf = $pdf->add_textflow($tf, "Doe", $value_optlist);
$pdf->fit_textflow($tf, $x, $lowerY, $upperX, $y, '');
$pdf->delete_textflow($tf);
$y = $pdf->get_option('texty', '');

$tf = 0;
$tf = $pdf->add_textflow($tf, "Date of birth:", $label_optlist);
$tf = $pdf->add_textflow($tf, "2022/11/08", $value_optlist);
$pdf->fit_textflow($tf, $x, $lowerY, $upperX, $y, '');
$pdf->delete_textflow($tf);
$y = $pdf->get_option('texty', '');

$tf = 0;
$tf = $pdf->add_textflow($tf, "A key that has a long value:", $label_optlist);
$tf = $pdf->add_textflow($tf, "A very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long value", $value_optlist);
$pdf->fit_textflow($tf, $x, $lowerY, $upperX, $y, '');
$pdf->delete_textflow($tf);


$pdf->end_page_ext('');
$pdf->end_document('');
return $pdf->get_buffer();

It is working, but as you can see, in optlist, I put leftindent=0% and leftindent=22%

The problem is that if a key would be longer, I will have to increase the "leftindent" manually, otherwise it will not align with other pairs. Furthermore, what if the keys would be dynamic so I don't know their length? I wouldn't know how much "leftindent".

Is there a cleaner and better way to print name value paris using PDFLib?

CodePudding user response:

I know the easiest solution would be to use a table, but I can't because the PDF has to be accessible and they told me that

who said that? This statement is a bit too general for now. Also, your content is not accessible in any way, because you achieve this in the PDF only through Tagged PDF.

PDFlib can be used to create PDF/UA (i.e. Tagged PDF) which can be used to create accessible PDFs.

The easiest way would be to follow the PDFlib 10 Coobkook example enter image description here

About embedding: you must provide the font files in the SearchPath, because PDFlib needs the font data at runtime. Please refer to the PDFlib 10 Tutorial, Chapter 3.1.4, and Chapter 6.3.4 "Searching for Fonts". In the supplied PDFlib examples the SearchPath is set to "../data", where you can find the resources needed in the examples. You might want to crib there.

Back to the table and accessibiltiy:

In general it is already possible to create a table without a header, but this will be flagged in accessibility checks. Depending on how important the topic is, you should implement the table accordingly. On the other hand, your output is currently not accessible either, so you will have a much easier time if you put everything in a table. I have attached a very simple PDF/UA table which is created with the following code. Maybe you can identify your problem more precisely.

PDF/UA Table created with PDFlib 10

<?php
/*
 *
 * Demonstrate automatic table tagging
 *
 * required software: PDFlib/PDFlib PDI/PPS 10
 * required data: image file (dummy text created within the program)
 */

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

$p = null;

try {
    $p = new pdflib();

    $tf = 0;
    $tbl = 0;
    $rowmax = 5;
    $colmax = 5;

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

    /* Dummy text for filling a cell with multi-line Textflow */
    $tf_text =
        "Sample text created with the Textflow feature in order to " .
        "create multiline content within a table cell.";

    /*
     * Set the search path for fonts and images etc.
     */
    $p->set_option(
        "errorpolicy=exception SearchPath={" . $searchpath . "}");
    

    if ($p->begin_document("", 
            "pdfua=PDF/UA-1 lang=en tag={tagname=Document}") == 0)
        throw new Exception("Error: " . $p->get_errmsg());

    $p->set_info("Creator", "PDFlib Cookbook");
    $p->set_info("Title", $title);
    
    /* Automatically create spaces between chunks of text */
    $p->set_option("autospace=true charref");

    /* -------------------- Add table cells -------------------- */
    $row = 1;
    $col = 1;
   
    for ($row; $row <= $rowmax; $row  ) {
    /* ----- Simple text cell */
    $col = 1;

    $optlist = "colwidth = 100 fittextline={fontname=NotoSerif-Bold fontsize=10 position={left top}} margin=5";

    $tbl = $p->add_table_cell($tbl, $col, $row, "text " . $row, $optlist);

    /* ----- Multi-line text with Textflow */
    $col  ;

    $optlist = "fontname=NotoSerif-Regular fontsize=10";

    $tf = $p->add_textflow(0, $tf_text, $optlist);

    $optlist = "colwidth=300 rowheight=8 margin=5 textflow=" . $tf . " fittextflow={firstlinedist=capheight}";

    $tbl = $p->add_table_cell($tbl, $col, $row, "", $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.width height=a4.height");
        
        $p->create_bookmark("Tagged table demo", "");
        
        $p->fit_textline("Name-Value pairs", 50, 750,
            "fontname=NotoSerif-Regular " .
            "fontsize=16 tag={tagname=H1}");
        
        /*
         * Shade every other $row; draw lines for all table cells. Add
         * "showcells showborder" to visualize cell borders
         */
        $optlist = "tag={tagname=Table Summary={key value tablese}} ";
        /* Place the table instance */
        $result = $p->fit_table($tbl, $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");

    /* Check the $result; "_stop" means all is ok. */
    if (!$result == "_stop") {
        if ($result == "_error") {
            throw new Exception("Error when placing table: " 
                                        . $p->get_errmsg());
        }
        else {
            /*
             * Any other return value is a user exit caused by the
             * "return" option; this requires dedicated code to deal
             * with.
             */
            throw new Exception("User return found in Textflow");
        }
    }

    /* This will also delete Textflow handles used in the table */
    $p->delete_table($tbl, "");

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

    header("Content-type: application/pdf");
    header("Content-Length: $len");
    header("Content-Disposition: inline; filename=" . $title . ".pdf");
    print $buf;
}
catch (PDFlibException $e) {
    echo("PDFlib exception occurred in" . $title . "sample:\n" .
        "[" . $e->get_errnum() . "] " . $e->get_apiname() . ": " .
        $e->get_errmsg() . "\n");
    exit(1);
}
catch (Throwable $e) {
    echo($e);
    exit(1);
}

$p = 0;
?>
        

this sample is adapted from the PDFlib Cookbook "pdfua/table_pdfua1".

However, I suspect that the accessibility issue is not a real problem for you, so you could simply implement the whole thing with a PDFlib table. Just ask the person what the table and accessibility concerns are. Because if the real Tagged PDF (PDF/UA) is not an issue, many things become easier.

  • Related