【问题标题】:mPDF creates blank page after TOC when using different orientation使用不同方向时,mPDF 在 TOC 之后创建空白页
【发布时间】:2019-05-22 19:36:28
【问题描述】:

我正在尝试通过 mPDF 创建一个 PDF 文件,其中工作表具有以下方向:

___________
| Page 1   |
|          |
| Portrait |
|          |
___________
___________
| Page 2   |
|  TOC     |
| Portrait |
|          |
___________
__________________
| Page 3          |
| Landscape       |
|                 |
__________________
___________
| Page 4   |
|          |
| Portrait |
|          |
___________

但是,更改第 3 页的方向会使 mPDF 在第 2 页 (TOC) 和第 3 页之间创建一个空白页。

PDF 以 HTML 格式创建,然后处理为 mPDF。代码如下:

HTML:

<html>
<head>
    <style>
        @page page-landscape { size: landscape; }
        @page page-portrait { size: portrait; }

        div.landscape {
            page: page-landscape;
        }
        div.portrait {
            page: page-portrait;
        }

    </style>
</head>
<body>
    <div>
        <div>First page - displayed Portrait. The second page should be the TOC (portrait) and the 3rd should be on landscape</div>
    </div>

    <tocpagebreak />

    <div class="landscape">
       <bookmark content="TOC entry" level="0"/>
        <tocentry content="TOC entry" level="0"/>
        <p>TOC entry - Shouldn\'t have a empty page before</p>
    </div>

    <div class="portrait">
        another page
    </div>
</body>
</html>

PHP

$mpdf = new \Mpdf\Mpdf();
$mpdf->WriteHTML($html);
$mpdf->Output();

我已经尝试了很多方法来完成这项工作,但都没有成功。我将列出其中的一些:

  • &lt;tocpagebreak&gt; 标签上使用toc-selector="page-portrait"
  • &lt;tocpagebreak&gt; 标签上使用toc-orientation="P"
  • &lt;tocpagebreak&gt; 之后添加&lt;pagebreak orientation="L" /&gt;
  • 在TOC之后的div中使用class="landscape",使用@page选择器,如本例所示
  • 在 mPDF 的构造函数上将变量 autoPageBreak 设置为 false
  • 将页面包装在div 中并弄乱&lt;pagebreak&gt; 的位置

我使用的是 mPDF v6.0,现在我正在更新到 mPDF v8.0.1。所有版本(6、7 和 8)都会出现此问题。在版本 6 中,我通过在 $mpdf-&gt;WriteHTML($html); 之后添加 $mpdf-&gt;DeletePages(2); 来使用 hack,但这有两个主要问题:

  1. 此方法未记录在案,似乎有问题
  2. 这样,页码与正确的页面不匹配,所以我无法在页脚添加页码

有没有什么方法可以在没有空白页的情况下完成此操作?还是可行的解决方法?

【问题讨论】:

  • 查看laravel-dompdf。附言。我无法发表评论,所以我发布的只是一个答案。

标签: php mpdf


【解决方案1】:

我想出了如何使这项工作。关键是将class="landscape"(或您在CSS 上设置的名称)添加到&lt;tocpagebreak /&gt; 的容器中,而不是您要横向显示的实际页面。

所以 HTML 应该是:

<html>
<head>
    <style>
         @page page-landscape { size: landscape; }
         @page page-portrait { size: portrait; }

        div.landscape { page: page-landscape; }
        div.portrait { page: page-portrait; }
    </style>
</head>

<body>
    <div class="portrait">
        <div>First page - displayed Portrait. The second page should be the TOC (portrait) and the 3rd should be on landscape</div>
    </div>

    <div class="landscape">
        <tocpagebreak />
   </div>

    <div>
     <bookmark content="TOC entry consolidacao" level="0"/>
        <tocentry content="TOC entry consolidacao" level="0"/>
        <p>TOC entry - Shouldn't have a empty page before</p>
    </div>

    <div class="portrait">
        <bookmark content="2nd page" level="0"/>
        <tocentry content="2nd page" level="0"/>
        <p>2nd page</p>
    </div>
</body>
</html>

注意&lt;div class="landscape"&gt; 包裹&lt;tocpagebreak /&gt;。这实际上并没有改变 TOC 的方向,而是改变了下一页——我想它与 mPDF 的内部有关。 然后,当您想将方向更改为纵向时,只需在您希望应用它的页面上添加class="portrait"(如“第 2 页”所示)。

其他需要注意的是:

  1. 如果您有一个带有填充的所有内容的包装器,它似乎会在顶部或目录之前创建一个空白页面(无论出于何种原因)。我有一个&lt;div class="page-content"&gt; 作为&lt;body&gt; 的子元素,而该类有一个padding: 15px;,这使mPDF 创建了一个新页面。
  2. 如果您正在使用样式表,我建议您在测试时删除它们。此示例按原样工作,但如果您在有外部样式表时尝试它,它可能无法按预期工作。当这种情况发生时,这意味着某种风格迫使 mPDF 创建一个空白页面(这就是我发现 1. 的方式)。此外,我正在使用 Bootstrap 的 rowcol-xx 类并将它们全部删除。
  3. 仅使用&lt;pagebreak /&gt; 创建新页面但保持方向不变。或者使用style="page-break-before: always;"。这一点很重要,因为您可能会发现自己在尝试更改方向时使用&lt;pagebreak /&gt; 创建了一个新页面,从而为您提供了一个新的空白页面。
  4. 最后,如果您使用$mpdf-&gt;SetFooter()$mpdf-&gt;SetHTMLFooter()(或相应的Header 方法),一旦您使用@page 选择器,页眉/页脚将不会显示在页面上。您需要设置一个命名的页眉/页脚并通过 @page 选择器上的 CSS 指定它。请参阅example 5 on the docs 了解更多信息。

【讨论】:

    【解决方案2】:

    我正在使用问题中的代码并将其更新为在 pdf 中的 TOC 之后生成没有空白页面的 pdf。

    给定here TOCpagebreak 将始终从奇数页码开始。此外,还有一个issue with mpdf,它在 TOC 页面之后添加了一个空白页面。

    我把html代码分成两部分,删除TOC后的空白页,得到最终的pdf。

    php中的代码是:

    
    require_once __dir__.'/vendor/autoload.php';
    
    
    $html = '<html>
    <head>
        <style>
            @page page-landscape { size: landscape; }
            @page page-portrait { size: portrait; page-break-inside:avoid; }
    
            div.landscape {
                page: page-landscape;
            }
            div.portrait {
                page: page-portrait;
            }
    
        </style>
    </head>
    <body>
        <div>
            <div>First page - displayed Portrait. The second page should be the TOC (portrait) and the 3rd should be on landscape</div>
        </div>
    
    <tocpagebreak />';
    
    $mpdf = new \Mpdf\Mpdf();
    
    $mpdf->WriteHTML($html);
    $page = $mpdf->page;
    
    
    $html2= '<div class="portrait" style="page-break:avoid !important;">
           <bookmark content="TOC entry" level="0"/>
            <tocentry content="TOC entry" level="0"/>
            <p>TOC entry - Shouldn\'t have a empty page before</p>
        </div>
    
        <div class="landscape">
            another page
        </div>
    </body>
    </html>';
    
    
    $mpdf->WriteHTML($html2);
    $mpdf->DeletePages($page);
    $mpdf->Output();
    

    【讨论】:

    • 嗨@wpexpert。感谢您的贡献。正如我在问题中所说,DeletePages 不是最佳解决方案,因为 TOC 分页和页脚的 {PAGENO}{nbpg} 搞砸了。不确定将 HTML 一分为二有什么好处。经过大量试验/错误后,我确实设法在没有DeletePages 并且没有任何空白页的情况下解决了这个问题(见我的答案)。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多