I’m using PDFLib (this library https://www.pdflib.com/). I’m on PHP but this library exists also for other languages, so the question is not specific for PHP.
I would like to print on the PDF name value pairs. Something like this:
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?
2
Answers
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 https://www.pdflib.com/pdflib-cookbook/pdfua/table_pdfua1/php/ and fill one table cell after the other with a textflow.
Then PDFlib 10 will generate the table tagging for you, and you will have a nice accessible PDF. (See also PDFlib 10 Tutorial, Chapter 11.2.1 "Automatic Table Tagging"). The tutorial is included in the PDFlib 10 package, as well available on the download page.
For PDF/UA please also refer to Chapter 11.4.1 "The PDF/UA-1 Standard" in the PDFlib 10 Tutorial. Your code fragment already shows that you must at least change the font, because the font must be embedded. In your case you are using the PDF Latin Core font Helvetica which is not embedded. Therefore I recommend to use a font that you have and like. As an example you could of course use the NotoSerif-Regular used in the PDFlib examples.
if you want to stick with your solution, you could first determine the length for each key entry. You can do this via
info_textline()
with the same font options as when placing the text withfit_textline()
. You could use this to determine the maximum length and then adjust the llx position for the textflows accordingly.I would not use leftindent, but pass different X values for fit_textline() and fit_texfflow().
Also, I would get the end position with
info_textflow()
, not withget_option("texty")
.I think you are always better off with a PDFlib table. And if you really want to create Tagged PDF, that is also possible with PDFlib 10.
One comment about your used options:
encoding=utf8
is not valid. The correct option value is "encoding=unicode". You can set$pdf->set_optin("stringformat=utf8");
when your input content is UTF-8. In PDFlib 10stringformat=utf8
andencoding=unicode
is default and can be omitted.I would like to answer your questions about the above answer in a new one. There you can format better.
Instead of
leftindent
you can also simply move your x position of thefit_textflow()
. Hopefully that makes your code easier to understand.About using encoding=utf8: I always get an error message then. Which PDFlib version are you using? (you can see in the phpinfo() output for example) Generally utf8 is not a valid keyword unless you have crafted and provided an encoding yourself. But that would not be recommended.
From the PDFlib 10 API Reference, chapter 4.1, table 4.1:
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.
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.