TCPDF full page table

Html2PDF doesn't use TCPDF's HTML parser/render system. It implements it's own, and it's implementation won't grow the columns automatically to fill 100% of the space.

As such, in Html2PDF, not only do you need to set 100% width on the table, but you need to set percentage widths for each of the cells. (And due to some odd behavior with the width attribute in Html2PDF, use CSS to set the widths.)

TCPDF's native writeHTML will set each column to be the same width absent any specifications otherwise. (For example, a 4-column table has all cells at 25%) However, it doesn't support the CSS you're using so the markup would require a little tweaking to go that route.

To mimic this basic behavior in Html2PDF, you could simply add equivalent widths to your cells explicitly. For example, adding a width specification to your table td, table th style rules.

Here's an example with the following CSS rules for a four-column table:

table { width: 100%; }
table th, table td { width: 25%; }

Of course, it looks best when you specify widths that fit your content.

Example with equivalent columns


UPDATE

I'm going to leave some of the discussion about TCPDF below as it lead somewhat to the creation of a potentially useful class for Html2pdf. TCPDF has some useful methods for measuring the length of a string. If you measure the size of the strings inside the columns, you can create your own automatic column sizer.

I created a proof-of-concept class on github at https://github.com/b65sol/random-classes

First, we use the class to mediate the construction of the HTML. This is so the column classes for setting the widths get added and we don't have to parse HTML to extract the content we're measuring.

Then we have to pick some strategy for selecting our column widths. For example, the demo below measures the columns and finds minimum width percentages for each based on longest word. (Avoids wordbreaks) Then distributes any extra space proportionally based on the difference between longest word and longest full cell content. I wouldn't call this production ready since it's a proof-of-concept, but I'm hoping you (or other searchers) find it as a useful starting point.

The key part for that below is this: $tablebuilder->determine_column_widths_by_minimum_strategy('100%', 'aaa')

The first parameter gives us the size reference we're working with (100% of the page as I needed this to make the measurements useful), and the second provides some preset padding characters to add to our measurements to account for text style and table padding differences.

Here is a demo of it running: https://b65sol.com/so/59517311_new.php

The class itself is available here: https://github.com/b65sol/random-classes

The code for that demo is here:

<?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();
}

END OF UPDATE


If you'd prefer not to specify the widths explicitly, you could use TCPDF's writeHTML instead of using the Html2PDF library, but all that will do is use equally sized columns. I actually thought it would do some recalculation of column sizes if you only specified one or two, but I was incorrect. Further, TCPDF suffers from some of the same limitations as Html2PDF - if you specify the size of one column, it will not automatically resize the other columns to fit.

It also does not size columns to the content the way a browser does. This is actually pretty hard to do well so I'm not surprised TCPDF doesn't try it. A potentially low-effort solution would be to tag your columns with a size 'proportion' and calculate the widths on the fly for each depending on how many of each proportional sized columns are selected. (e.g. numeric columns are 'small', and a description column would be 'large' and so it breaks out two small ones at 10% each and a single description at 80%. Two smalls at 5% and to large columns at 45% each. It would take some experimentation.)

Tags:

Html

Css

Php

Tcpdf