5

我正在使用 php 的 dompdf 库从 HTML 模板生成 PDF 报告。在那个 html 模板中有一个部分目录。生成 PDF 时,我需要更新目录的页码。有谁知道我如何在 php 的 dompdf 库中实现这一点?

提前致谢。

4

5 回答 5

2

我已经在 Drupal 中实现了这一点,并且猜测它也适用于其他 php 开源和框架。我已将此代码保存在脚本标记中

$GLOBALS['entity_page'][] =  $pdf->get_page_number();        

在存储页码的模板中。模板扩展名为 tpl.php 现在在模块中,在我添加了其他导出代码之后......

$canvas = $dompdf->get_canvas();
    $font = Font_Metrics::get_font("helvetica", "normal");
    $canvas->page_text(520, 805, "Page {PAGE_NUM}", $font, 9, array(0.4, 0.4, 0.4));

    foreach ($GLOBALS['entity_page'] as $key => $val) {
        $GLOBALS["entity_val"] = 0;
        $GLOBALS["entity_y"] = 110;
        $canvas->page_script('if($PAGE_NUM == 3 && $PAGE_NUM < 4){
                 $font = Font_Metrics::get_font("helvetica", "normal");
                 $x = 380;
                 $y = $GLOBALS["entity_y"];

                 $pdf->text($x, $y, "-------------------------".$GLOBALS["entity_page"][$GLOBALS["entity_val"]]."", $font, 12, array(0, 0, 0, 0.8));
                 $GLOBALS["entity_y"] = $GLOBALS["entity_y"] + 33;
                 $GLOBALS["entity_val"] = $GLOBALS["entity_val"] + 1;

                }');
    }

$pdf->text 这部分在 y 轴位置以恒定增量添加页码。其他全局变量 entity_y 和 entity_val 用于存储值。

于 2016-06-30T12:18:32.390 回答
1

从 HTML 生成目录(使用 h1、h2、h3),我执行了以下操作:

  • 首先给每个标头一个唯一的 ID(因为我们使用的是 PrinceXML),这是一个很好的做法。
  • 然后创建它的 OL/LI 结构,尽管那段代码可能包含错误。
    $matches = null;
    $smatches = null;
    $had_headers = array();
    preg_match_all('/<h[0-9].*?>.*?<\/h[0-9]>/i', $content, $matches);
    if (!empty($matches[0]) && count($matches[0]) > 0)
    foreach ($matches[0] as $headertag) {
        preg_match('/>(.*?)<\/(h[0-9])>/i', $headertag, $smatches);
    
        if (!empty($smatches[1]) && count($smatches[1]) > 0) {
            $headerid = strip_tags($headertag);
            $headerid = trim(strtolower(preg_replace('/[^a-z0-9]/i', '', $headerid)));
            $smatches[2] = strtolower($smatches[2]);
            $header_depth = intval(trim(str_ireplace('h', '', $smatches[2])));
        
            while (in_array($headerid, $had_headers)) {
                $headerid .= '1';
            }
            $had_headers[] = $headerid;
        
            $content = str_replace($headertag, '<'. $smatches[2] . ' id="' . htmlentities($headerid) . '">' . $smatches[1] . '</' . $smatches[2] . '>', $content);
        }
    }

    $matches = null;
    $smatches = null;
    $toc_html = '<ol id="toc">' . "\n";
    $old_depth = 0;
    $hadfirst = false;
    preg_match_all('/<h[0-9].*?>.*?<\/h[0-9]>/i', $content, $matches);
    if (!empty($matches[0]) && count($matches[0]) > 0)
    for ($i=0; $i < count($matches[0]); $i++) {
        $headertag = $matches[0][$i];
    
        preg_match('/<h[0-9][^>]*?id="(.*?)".*?>(.*?)<\/(h[0-9])>/i', $headertag, $smatches);
    
        if (!empty($smatches[1]) && count($smatches[1]) > 0) {
            $headerid = trim($smatches[1]);
            $header_depth = intval(trim(str_ireplace('h', '', $smatches[3]))) - 1;
        
            // don't take heigher than h3 in TOC
            if ($header_depth > 2)
                continue;
        
            if ($header_depth < $old_depth) {
                $diff = $old_depth - $header_depth; //if going multiple levels up
                $toc_html .= '</li>'.str_repeat('</ol></li>', $diff);
            } elseif ($header_depth > $old_depth) {
                $toc_html .= '<ol>';
            } else {
                $toc_html .= ($hadfirst) ? '</li>' : null;
            }
        
            $toc_html .= '<li><a href="#' . $headerid . '">' . htmlentities(trim(strip_tags($smatches[2]))) . '</a>';
        
            $old_depth = $header_depth;
            $hadfirst = true;
        }
    }
    $toc_html .=  str_repeat('</li></ol>', ($old_depth + 1));
于 2009-10-15T07:38:50.017 回答
0

你可能已经解决了这个问题?我没有使用过 dompdf,但我在 Zend_Pdf 中做了类似的事情:我为目录制作了一个空白页,然后继续创建所有其他后续页面,保留 page_number => title 的数组。最后,我返回并使用之前保存的参考更新了内容页面......

于 2009-08-23T07:05:05.550 回答
0

我在 pdf 中创建 TOC 的想法如下:

  1. 生成pdf,其中页面标题将包含随机标记而不是名称
  2. 解析生成的 pdf(使用 Smalot\PdfParser)并找到包含令牌的页码
  3. 生成pdf,其中用真实姓名替换令牌并找到页码。

例子:

$html = "<html>
<div class='toc'>
<a>Article1 ..... {article_1_num}</a>
</div>
...
<div class='article'>
    <div>{article_1_title}</div>
    <div>Article content</div>
</div>
</html>";
//prepare variables to replace in template with random token
$vars = ["{article_1_title}"=>'676TGZGHVGFTRR655R66TTFTF', "{article_1_num}"=>0];
//genetate pdf
$options = new Options();
$options->set('defaultFont', 'Courier');
$options->set('isRemoteEnabled', TRUE);
$options->set('debugKeepTemp', TRUE);
$options->set('isPhpEnabled', TRUE);
$options->set('isHtml5ParserEnabled', true);
$dompdf = new Dompdf($options);
//load html with variables replaced
$dompdf->loadHtml(strtr($html, $vars));
$dompdf->setPaper('A4');
@$dompdf->render();
//create tamporary file
$temp = tempnam(sys_get_temp_dir(), 'prefix');
$output = $dompdf->output();
//save to temporary file
file_put_contents($temp, $output);

// parse pdf 
$parser = new \Smalot\PdfParser\Parser();
$pdf = $parser->parseFile($temp);
$pages = $pdf->getPages();
$pageNum = 0;
//loop the pages and find the one with the token
foreach ($pages as $k=>$page) {
    if(strpos($page,'676TGZGHVGFTRR655R66TTFTF') !== false){
       $pageNum = $k+1;
       break;
    }
}
// remove temp file
unlink($temp);
//prepare variables with real values to replace in template
$vars = ["{article_1_title}"=>'Article no. 1', "{article_1_num}"=>$pageNum];
// generate pdf and stream it to user
$options = new Options();
$options->set('defaultFont', 'Courier');
$options->set('isRemoteEnabled', TRUE);
$options->set('debugKeepTemp', TRUE);
$options->set('isPhpEnabled', TRUE);
$options->set('isHtml5ParserEnabled', true);
$dompdf = new Dompdf($options);
//load html with variables replaced
$dompdf->loadHtml(strtr($html, $vars));
$dompdf->setPaper('A4');
@$dompdf->render();
$dompdf->stream("pdf.pdf", array('Attachment' => 0));
于 2020-05-04T12:57:32.780 回答
0

作为对 vicky shrestha 的回答的扩展,我所拥有的目录可以扩展不止一个页面。

36 只是适合设计的任意数量的项目。

foreach ($GLOBALS['entity_page'] as $key => $val) {
    $GLOBALS["entity_y"] = 88;
    $GLOBALS["entity_val"]  = 0;
    $GLOBALS["entity_per_page"] = 36;
    if($val) {
        $canvas->page_script('
        if(isset($GLOBALS["entity_page"][$GLOBALS["entity_val"]])) {
            if($PAGE_NUM == $GLOBALS["entity_page_number"]){
                $x = 505;
                $y = $GLOBALS["entity_y"];
                $font = $fontMetrics->get_font("Open Sans", "Helvetica Neue", "Helvetica, Arial, sans-serif");

                $pdf->text($x, $y, $GLOBALS["entity_page"][$GLOBALS["entity_val"]]."", $font, 7, array(0, 0, 0, 1));
                $GLOBALS["entity_y"] = $GLOBALS["entity_y"] + 19;
                $GLOBALS["entity_val"] = $GLOBALS["entity_val"] + 1;
                if (($GLOBALS["entity_val"] + 1) % $GLOBALS["entity_per_page"] == 0 ) {
                    $GLOBALS["entity_page_number"] = $GLOBALS["entity_page_number"] + 1;
                    $GLOBALS["entity_y"] = 31;
                }
            }
        }');
    }
}

isset 很重要,因为由于某种原因,foreach 会额外循环一次,最后你会得到一个越界异常。

于 2018-12-12T17:49:36.103 回答