PDFLib, как печатать пары «имя-значение»?

Я использую PDFLib (эта библиотека https://www.pdflib.com/). Я на PHP, но эта библиотека существует и для других языков, поэтому вопрос не специфичен для PHP.

Я хотел бы напечатать пары значений имени PDF. Что-то вроде этого:

Я знаю, что самым простым решением было бы использовать таблицу, но я не могу, потому что PDF-файл должен быть доступен, и мне сказали, что в PDF-файле таблица, показывающая значение имени, будет недоступна, поэтому я должен найти другое решение вместо таблицы.

В настоящее время я пробовал с 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();

Работает, но как видите, в оптлисте я поставил leftindent=0% и leftindent=22%

Проблема в том, что если ключ будет длиннее, мне придется вручную увеличить «левый отступ», иначе он не будет выравниваться с другими парами. Кроме того, что, если бы ключи были динамическими, поэтому я не знаю их длины? Я бы не знал, сколько "leftindent".

Есть ли более чистый и лучший способ распечатать значение имени с помощью PDFLib?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
0
88
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я знаю, что самым простым решением было бы использовать таблицу, но я не могу, потому что PDF должен быть доступен, и они сказали мне, что

кто это сказал? Это утверждение пока слишком общее. Кроме того, ваш контент никак не доступен, потому что вы достигаете этого в PDF только через Tagged PDF.

PDFlib можно использовать для создания PDF/UA (т. е. PDF с тегами), которые можно использовать для создания PDF-файлов с доступом.

Самый простой способ — следовать примеру PDFlib 10 Coobkook https://www.pdflib.com/pdflib-cookbook/pdfua/table_pdfua1/php/ и заполнять одну ячейку таблицы за другой текстовым потоком.

Затем PDFlib 10 сгенерирует для вас теги таблиц, и вы получите удобный доступный PDF-файл. (См. также учебник по PDFlib 10, глава 11.2.1 «Автоматическая разметка таблиц»). Учебник включен в пакет PDFlib 10, а также доступен на странице загрузки.

Для PDF/UA см. также главу 11.4.1 «Стандарт PDF/UA-1» в руководстве по PDFlib 10. Ваш фрагмент кода уже показывает, что вы должны как минимум изменить шрифт, потому что шрифт должен быть встроенным. В вашем случае вы используете не встроенный шрифт PDF Latin Core Helvetica. Поэтому я рекомендую использовать тот шрифт, который у вас есть и который вам нравится. В качестве примера вы, конечно, можете использовать NotoSerif-Regular, используемый в примерах PDFlib.

если вы хотите придерживаться своего решения, вы можете сначала определить длину для каждой ключевой записи. Вы можете сделать это с помощью info_textline() с теми же параметрами шрифта, что и при размещении текста с помощью fit_textline(). Вы можете использовать это, чтобы определить максимальную длину, а затем соответствующим образом настроить положение llx для текстовых потоков. Я бы не использовал leftindent, а передал бы разные значения X для fit_textline() и fit_texfflow().

Кроме того, я бы получил конечную позицию с info_textflow(), а не с get_option("texty").

Я думаю, вам всегда лучше с таблицей PDFlib. И если вы действительно хотите создать PDF с тегами, это также возможно с PDFlib 10.

Один комментарий о ваших используемых опциях:

$label_optlist = "fontname = {Helvetica} fontsize=7 encoding=utf8 fakebold=true leftindent=0%";

encoding=utf8 недействителен. Правильное значение параметра — «encoding=unicode». Вы можете установить $pdf->set_optin("stringformat=utf8");, когда ваш входной контент имеет кодировку UTF-8. В PDFlib 10 stringformat=utf8 и encoding=unicode используются по умолчанию и могут быть опущены.

во-первых, спасибо за ответ. Доступна ли таблица без заголовка и с именами в столбцах 1 и значениями в столбцах 2? Причина, по которой я использую leftindent, заключается в том, чтобы встроить все значения. Я имею в виду, посмотрите скриншот в посте, без левого отступа они не были бы встроенными, как с левым отступом.

stefano_it 08.11.2022 17:41

насчет кодировки, какая разница, если я использую $pdf->set_option("stringformat=utf8"); и ставлю encoding=unicode или если я не использую set_option и ставлю encoding=utf8? В настоящее время только с encoding=utf8 кажется, что работает

stefano_it 08.11.2022 17:50

Насчет "встраивания", что оно делает? Я пытался поставить embedding, но я получил эту ошибку Font 'Helvetica' with encoding 'utf8': Font cannot be embedded. Я попытался изменить кодировку на unicode, как вы сказали, и это работает. Но в чем разница между fontname = {Helvetica} fontsize=8 embedding encoding=unicode и fontname = {Helvetica} fontsize=8 encoding=utf8? Извините за нубские вопросы и извините, если я разделил их на 3 комментария, но ТАК говорит слишком много символов xD

stefano_it 08.11.2022 17:51
Ответ принят как подходящий

Я хотел бы ответить на ваши вопросы о приведенном выше ответе в новом. Там можно отформатировать получше.

Вместо leftindent вы также можете просто переместить позицию x fit_textflow(). Надеюсь, это облегчит понимание вашего кода.

Об использовании encoding=utf8: тогда я всегда получаю сообщение об ошибке. Какую версию PDFlib вы используете? (вы можете видеть, например, в выводе phpinfo()) Как правило, utf8 не является допустимым ключевым словом, если вы не создали и не предоставили кодировку самостоятельно. Но это не рекомендуется.

Из справочника API PDFlib 10, глава 4.1, таблица 4.1:

О встраивании: вы должны предоставить файлы шрифтов в SearchPath, потому что PDFlib нужны данные шрифта во время выполнения. Пожалуйста, обратитесь к учебнику PDFlib 10, глава 3.1.4 и глава 6.3.4 «Поиск шрифтов». В предоставленных примерах PDFlib для SearchPath установлено значение «../data», где вы можете найти ресурсы, необходимые в примерах. Вы могли бы хотеть кроватку там.

Вернуться к таблице и доступности:

В общем, уже можно создать таблицу без заголовка, но это будет помечено при проверке доступности. В зависимости от того, насколько важна тема, вы должны соответствующим образом реализовать таблицу. С другой стороны, ваш вывод в настоящее время также недоступен, поэтому вам будет намного легче, если вы поместите все в таблицу. Я прикрепил очень простую таблицу PDF/UA, созданную с помощью следующего кода. Может быть, вы сможете точнее определить свою проблему.

<?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;
?>
        

этот пример адаптирован из кулинарной книги PDFlib «pdfua/table_pdfua1».

Однако я подозреваю, что проблема доступности не является для вас реальной проблемой, поэтому вы можете просто реализовать все это с помощью таблицы PDFlib. Просто спросите человека, что касается стола и доступности. Потому что, если настоящий Tagged PDF (PDF/UA) не является проблемой, многое становится проще.

Спасибо за ответ. Попробовал сделать с таблицей как вы сказали, на Edge скринридер читает правильно. Проблема заключается в программном обеспечении, которое они используют для чтения с экрана, которое плохо читает его в Adoble Acrobat (он говорит, что это таблица, и если я помещаю слишком много места между столбцами, он сначала читает весь столбец 1, а затем весь столбец 2 вместо чтения в правильном порядке). К сожалению, я не могу использовать таблицу в качестве решения, но я найду способ заставить PDF работать только с их экраном с текстовым потоком. (продолжите в следующем комментарии, потому что это слишком долго)

stefano_it 11.11.2022 16:34

Я по-прежнему считаю это правильным ответом, потому что, как вы сказали, таблица доступна. Они используют программу чтения с экрана, которая плохо ее читает и говорит, что это таблица. Что касается utf8, я буду использовать unicode, как вы сказали, потому что, если я поставлю опцию «встраивание», это приведет к ошибке с utf8. И последний вопрос: почему в официальной документации не используют load_font, а каждый раз повторяют шрифт? Я имею в виду, что таким образом $font = $pdf->load_font('NotoSerif', 'unicode', ''); тогда $optlist = "font = " . $font . " fontsize=10"; они избегали бы повторения имени шрифта. Load_font плохой?

stefano_it 11.11.2022 16:39

PDFlib может загружать неявный и явный шрифт, и результат будет идентичным. В главе 6.3.1 учебника PDFlib 10 я нашел следующее: «Шрифты можно загружать явно с помощью метода PDF_load_font() или неявно, указав имя шрифта и параметры кодирования для таких методов, как PDF_add/create_textflow() или PDF_fill_textblock()». Лично я считаю, что использование имени шрифта в приведенных примерах намного понятнее, чем использование дескриптора шрифта. Но это, безусловно, дело вкуса. Шрифт не загружается снова, если он уже был загружен.

Rainer 14.11.2022 14:47

Другие вопросы по теме