php - TCPDF 完整页表
问题描述
我尝试了很多方法来使表格适合页面(A4),如图所示: 我搜索了很多,但在网上找不到任何有用的东西。我正在使用动态表格,除了表格的宽度外,一切都很好。这是我的代码:
$content = '<table><thead><tr><th class="bg-dark text-white" align="center">#</th><th align="center" class="bg-dark text-white">Code</th><th align="left" class="bg-dark text-white">Description</th><th align="center" class="bg-dark text-white">Item Type</th></tr></thead><tbody><tr style="background-color: #f2f2f2;"><td align="center">1</td><td align="center">1001</td><td align="left">Pofak</td><td align="center">Fixed Price</td></tr><tr ><td align="center">2</td><td align="center">1002</td><td align="left">Ice</td><td align="center">Weight</td></tr><tr style="background-color: #f2f2f2;"><td align="center">3</td><td align="center">1003</td><td align="left">Minoo</td><td align="center">Fixed Price</td></tr><tr ><td align="center">4</td><td align="center">1004</td><td align="left">Bastani</td><td align="center">Fixed Price</td></tr><tr style="background-color: #f2f2f2;"><td align="center">5</td><td align="center">1005</td><td align="left">Chocolate</td><td align="center">Weight</td></tr><tr ><td align="center">6</td><td align="center">1006</td><td align="left">Brush</td><td align="center">Fixed Price</td></tr><tr style="background-color: #f2f2f2;"><td align="center">7</td><td align="center">1007</td><td align="left">Apple</td><td align="center">Weight</td></tr><tr ><td align="center">8</td><td align="center">1008</td><td align="left">Water</td><td align="center">Fixed Price</td></tr><tr style="background-color: #f2f2f2;"><td align="center">9</td><td align="center">1009</td><td align="left">Cleaner</td><td align="center">Fixed Price</td></tr><tr ><td align="center">10</td><td align="center">1001</td><td align="left">Pofak</td><td align="center">Fixed Price</td></tr><tr style="background-color: #f2f2f2;"><td align="center">11</td><td align="center">1002</td><td align="left">Ice</td><td align="center">Weight</td></tr><tr ><td align="center">12</td><td align="center">1003</td><td align="left">Minoo</td><td align="center">Fixed Price</td></tr><tr style="background-color: #f2f2f2;"><td align="center">13</td><td align="center">1004</td><td align="left">Bastani</td><td align="center">Fixed Price</td></tr><tr ><td align="center">14</td><td align="center">1005</td><td align="left">Chocolate</td><td align="center">Weight</td></tr><tr style="background-color: #f2f2f2;"><td align="center">15</td><td align="center">1006</td><td align="left">Brush</td><td align="center">Fixed Price</td></tr></tbody></table>';
$newContent = '
<style type="text/css">
table{width:100%;}
table, table td, table th{
border-collapse: collapse;
border: solid 1px #ababab;
}
.text-dark, table td{
color: #343a40;
}
.text-white{
color: #ffffff;
}
table td,
table th {
font-size: 11px;
padding: 3px;
line-height: 1.2;
font-family:arial;
}
.bg-dark {
background-color: #343a40;
}
.bg-secondary {
background-color: #6c757d;
}
.bg-white {
background-color: #ffffff;
}
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
.text-center {
text-align: center;
}
</style>
';
$newContent .= '<page>'.$content.'</page>';
try {
$html2pdf = new Html2Pdf('P', 'A4', 'en', true, 'UTF-8', 5);
$html2pdf->pdf->SetDisplayMode('real');
$html2pdf->writeHTML($newContent);
$PDFName = "ItemLists_".date('Y.m.d_H.i.s').".pdf";
$html2pdf->output($PDFName, 'I');
} catch (Html2PdfException $x) {
$html2pdf->clean();
$formatter = new ExceptionFormatter($x);
echo $formatter->getHtmlMessage();
}
非常感谢
解决方案
Html2PDF 不使用 TCPDF 的 HTML 解析器/渲染系统。它实现了自己的,并且它的实现不会自动增加列以填充 100% 的空间。
因此,在 Html2PDF 中,您不仅需要在表格上设置 100% 的宽度,还需要为每个单元格设置百分比宽度。(并且由于width
Html2PDF 中属性的一些奇怪行为,请使用 CSS 设置宽度。)
TCPDF 的本机writeHTML
将每列设置为相同的宽度,否则没有任何规范。(例如,一个 4 列表的所有单元格占 25%)但是,它不支持您正在使用的 CSS,因此标记需要稍微调整才能走这条路。
要在 Html2PDF 中模仿这种基本行为,您可以简单地为您的单元格显式添加等效宽度。例如,将宽度规范添加到您的table td, table th
样式规则。
这是一个包含以下 CSS 规则的四列表示例:
table { width: 100%; }
table th, table td { width: 25%; }
当然,当您指定适合您的内容的宽度时,它看起来最好。
更新
我将在下面留下一些关于 TCPDF 的讨论,因为它在一定程度上会导致为Html2pdf
. TCPDF 有一些有用的方法来测量字符串的长度。如果您测量列内字符串的大小,则可以创建自己的自动列大小调整器。
我在https://github.com/b65sol/random-classes的 github 上创建了一个概念验证类
首先,我们使用类来调解 HTML 的构建。这样就可以添加用于设置宽度的列类,并且我们不必解析 HTML 来提取我们正在测量的内容。
然后我们必须选择一些策略来选择我们的列宽。例如,下面的演示测量列并根据最长单词找到每个列的最小宽度百分比。(避免分词)然后根据最长单词和最长完整单元格内容之间的差异按比例分配任何额外空间。我不会将此产品称为准备就绪,因为它是概念验证,但我希望您(或其他搜索者)发现它是一个有用的起点。
下面的关键部分是:$tablebuilder->determine_column_widths_by_minimum_strategy('100%', 'aaa')
第一个参数为我们提供了我们正在使用的尺寸参考(100% 的页面,因为我需要它以使测量有用),第二个参数提供一些预设填充字符以添加到我们的测量中以说明文本样式和表格填充差异。
这是它运行的演示: https ://b65sol.com/so/59517311_new.php
该课程本身可在此处获得: https ://github.com/b65sol/random-classes
该演示的代码在这里:
<?php
require 'vendor/autoload.php';
include 'random-classes/html2pdf-full-table-optimizer.php';
use Spipu\Html2Pdf\Html2Pdf;
//First let's build a random table!
$wordlist = ['Chocolate', 'Cake', 'Brownies', 'Cupcakes', 'Coreshock', 'Battery', 'Lead', 'Acid', 'Remilia'];
$wordlist2 = ['Reinforcement Learning', 'Initial Latent Vectors', 'Bag-of-Words', 'Multilayer Perceptron Classifier',
'Deconvolutional Neural Network', 'Convolutional Neural Network'];
$number_of_columns = rand(3,11);
$number_of_rows = rand(8, 15);
$possible_column_names = ['Unit', 'Description', 'Variable', 'Moon', 'Cheese', 'Lollipop', 'Orange', 'Gir', 'Gaz', 'Zim', 'Dib'];
$possible_column_content_generators = [
function() {return rand(10,100); },
function() {return rand(1000, 1999); },
function() use ($wordlist) {return $wordlist[rand(0, count($wordlist)-1)]; },
function() use ($wordlist) {return $wordlist[rand(0, count($wordlist)-1)] . ' '. $wordlist[rand(0, count($wordlist)-1)];},
function() use ($wordlist2) {return $wordlist2[rand(0, count($wordlist2)-1)];},
];
shuffle($possible_column_names);
$list_of_generators = [];
$column_classes = [];
$column_names = [];
for($i = 0; $i < $number_of_columns; $i++) {
$list_of_generators[$i] = $possible_column_content_generators[rand(0, count($possible_column_content_generators)-1)];
$column_classes[$i] = ['text-left', 'text-right', 'text-center'][rand(0,2)];
$column_names[$i] = $possible_column_names[$i];
}
//Got our random stuff, onward to generator!
try {
$html2pdf = new Html2Pdf('P', 'A4', 'en', true, 'UTF-8', 5);
$html2pdf->pdf->SetDisplayMode('real');
$tablebuilder = new Html2PdfTableOptimizer($html2pdf->pdf, '11px', 'helvetica');
//run table builder... using random data for testing.
for($i = 0; $i < $number_of_columns; $i++) {
/*Add a header cell, content is the first parameter, CSS class attribute is second.*/
$tablebuilder->add_header_cell($column_names[$i], $column_classes[$i] . ' bg-dark text-white');
}
for($i = 0; $i < $number_of_rows; $i++) {
//Start a row.
$tablebuilder->start_data_row();
for($col = 0; $col < $number_of_columns; $col++) {
//Add content and our column classes for td elements
$tablebuilder->add_data_row_cell($list_of_generators[$col](), $column_classes[$col]);
}
//End the row.
$tablebuilder->end_data_row();
}
//Get the table HTML.
$render = $tablebuilder->render_html();
$newContent = '
<style type="text/css">
table{width:100%;}
table, table td, table th{
border-collapse: collapse;
border: solid 1px #ababab;
}
.text-dark, table td{
color: #343a40;
}
.text-white{
color: #ffffff;
}
table td,
table th {
font-size: 11px;
padding: 3px;
line-height: 1.2;
font-family:arial;
}
.bg-dark {
background-color: #343a40;
}
.bg-secondary {
background-color: #6c757d;
}
.bg-white {
background-color: #ffffff;
}
.row-even {
background-color: #d1d1d1;
}
.text-left {
text-align: left;
}
.text-right {
text-align: right;
}
.text-center {
text-align: center;
}
'.$tablebuilder->determine_column_widths_by_minimum_strategy('100%', 'aaa').'
</style>
';
$newContent .= '<page>'.$render.'</page>';
if(!empty($_GET['html'])) {
echo $newContent;
} else {
$html2pdf->writeHTML($newContent);
$PDFName = "ItemLists_".date('Y.m.d_H.i.s').".pdf";
$html2pdf->output($PDFName, 'I');
}
} catch (Html2PdfException $x) {
$html2pdf->clean();
$formatter = new ExceptionFormatter($x);
echo $formatter->getHtmlMessage();
}
更新结束
如果您不想显式指定宽度,则可以使用 TCPDFwriteHTML
而不是使用Html2PDF
库,但所做的只是使用相同大小的列。我实际上认为如果您只指定一两个,它会重新计算列大小,但我错了。此外,TCPDF 受到一些相同的限制Html2PDF
- 如果您指定一列的大小,它不会自动调整其他列的大小以适应。
它也不会像浏览器那样根据内容调整列的大小。这实际上很难做好,所以我对 TCPDF 没有尝试它并不感到惊讶。一个可能省力的解决方案是使用大小“比例”标记列,并根据选择的每个比例大小的列的数量动态计算每个列的宽度。(例如,数字列是“小”,而描述列将是“大”,因此它会以 10% 的比例划分两个小列,在 80% 处划分一个描述。5% 的两个小列和 45% 的大列每个。这需要一些实验。)
推荐阅读
- shell - 如何将所有参数分组为`xargs`的位置参数
- javascript - 为什么记录此对象属性会给出不同的结果,然后记录对象本身并查看属性?
- tcl - “发送命令”和“发送-命令”之间的期望有什么区别
- vba - 使用 vba 用前一天数据填充 Access 表中缺少的日期间隔
- python - 如何在python中将字符串数组传递给fastapi
- vim - VSCode 的 Vim 扩展:重新映射 ^
- javascript - React Native:json.data 不是一个函数。(在 'json.data()' 中,'json.data' 是 Array 的一个实例)]
- c++ - 在 C++ 中复制字符串“读取字符串字符时出错。”
- java - 按字典顺序排序字符串数组,然后按数字排序(因为字符串包含数字)
- terminal - 以前不在 MBP 的终端?