使用 FPDF 库的表重叠问题

Overlap issue with tables using FPDF library

我正在使用 FPDF 库开发一个 PHP 网络项目,该项目运行良好。我正在进行的任务是在生成的 pdf 页面中插入一个 table。由于我需要以特定方式输出 table(见下图),因此很难使用可以在此处找到的现有脚本:http://www.fpdf.org/fr/script/index.php。我在我的自定义 PDF class.

中使用 link 中提供的 classes 作为特征

我的MySQLtable:

渲染数据的具体方式:

colonne(法语)= column(英语)/ ligne = line

这是我使用的代码:

关于可以帮助我在 pdf 页面中获得 html table 重叠问题和更改 table html 属性的可能性的库的任何想法?

更新:2019 年 10 月 10 日 我刚刚在 Olivier (http://www.fpdf.org/en/script/script3.php) 编写的以下代码中找到了重叠问题的答案:

<?php
require('fpdf.php');

class PDF_MC_Table extends FPDF
{
var $widths;
var $aligns;

function SetWidths($w)
{
    //Set the array of column widths
    $this->widths=$w;
}

function SetAligns($a)
{
    //Set the array of column alignments
    $this->aligns=$a;
}

function Row($data)
{
    //Calculate the height of the row
    $nb=0;
    for($i=0;$i<count($data);$i++)
        $nb=max($nb,$this->NbLines($this->widths[$i],$data[$i]));
    $h=5*$nb;
    //Issue a page break first if needed
    $this->CheckPageBreak($h);
    //Draw the cells of the row
    for($i=0;$i<count($data);$i++)
    {
        $w=$this->widths[$i];
        $a=isset($this->aligns[$i]) ? $this->aligns[$i] : 'L';
        //Save the current position
        $x=$this->GetX();
        $y=$this->GetY();
        //Draw the border
        $this->Rect($x,$y,$w,$h);
        //Print the text
        $this->MultiCell($w,5,$data[$i],0,$a);
        //Put the position to the right of the cell
        $this->SetXY($x+$w,$y);
    }
    //Go to the next line
    $this->Ln($h);
}

function CheckPageBreak($h)
{
    //If the height h would cause an overflow, add a new page immediately
    if($this->GetY()+$h>$this->PageBreakTrigger)
        $this->AddPage($this->CurOrientation);
}

function NbLines($w,$txt)
{
    //Computes the number of lines a MultiCell of width w will take
    $cw=&$this->CurrentFont['cw'];
    if($w==0)
        $w=$this->w-$this->rMargin-$this->x;
    $wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
    $s=str_replace("\r",'',$txt);
    $nb=strlen($s);
    if($nb>0 and $s[$nb-1]=="\n")
        $nb--;
    $sep=-1;
    $i=0;
    $j=0;
    $l=0;
    $nl=1;
    while($i<$nb)
    {
        $c=$s[$i];
        if($c=="\n")
        {
            $i++;
            $sep=-1;
            $j=$i;
            $l=0;
            $nl++;
            continue;
        }
        if($c==' ')
            $sep=$i;
        $l+=$cw[$c];
        if($l>$wmax)
        {
            if($sep==-1)
            {
                if($i==$j)
                    $i++;
            }
            else
                $i=$sep+1;
            $sep=-1;
            $j=$i;
            $l=0;
            $nl++;
        }
        else
            $i++;
    }
    return $nl;
}
}
?>

现在我遇到的唯一问题是在上面的代码中编辑 Row() 函数,以便 table 以我提到的特定方式呈现。

这就是 Row() 函数的用法,如上述 class 的文档所述(参见 http://www.fpdf.org/fr/script/script3.php):

function GenerateWord()
{
    //Get a random word
    $nb=rand(3,10);
    $w='';
    for($i=1;$i<=$nb;$i++)
        $w.=chr(rand(ord('a'),ord('z')));
    return $w;
}

function GenerateSentence()
{
    //Get a random sentence
    $nb=rand(1,10);
    $s='';
    for($i=1;$i<=$nb;$i++)
        $s.=GenerateWord().' ';
    return substr($s,0,-1);
}

$pdf=new PDF_MC_Table();
$pdf->AddPage();
$pdf->SetFont('Arial','',14);
//Table with 20 rows and 4 columns
$pdf->SetWidths(array(30,50,30,40));
srand(microtime()*1000000);
for($i=0;$i<20;$i++)
    $pdf->Row(array(GenerateSentence(),GenerateSentence(),GenerateSentence(),GenerateSentence()));
$pdf->Output();

在我的例子中,传递给 Row 函数的数组是一个三维数组:

$table =
Array
(
    [1] => Array
        (
            [1] => Array
                (
                    [1] => colonne1 ligne1
                )

            [2] => Array
                (
                    [4] => colonne2   ligne1  
                )

            [3] => Array
                (
                    [9] => colonne3 ligne1 

                )

        )

    [pos_paragr_prec] => 0
    [2] => Array
        (
            [1] => Array
                (
                    [2] => colonne1 ligne2  
                )

            [2] => Array
                (
                    [7] => colonne2 ligne2 
                )

            [3] => Array
                (
                    [10] => colonne3 ligne2  
                )

        )

    [3] => Array
        (
            [1] => Array
                (
                    [3] => colonne1 ligne3 
                )

            [2] => Array
                (
                    [8] => colonne2 ligne3
                )

            [3] => Array
                (
                    [11] => colonne3 ligne3
                )

        )

)

关于如何编辑 Row 函数以按上述方式生成 table 的任何提示?

到目前为止,我已经尝试在不编辑 Row 函数的情况下执行类似的操作:

if (count($table) > 0) {
        foreach($table as $row_array) {
            foreach($row_array as $key => $val) {
                for($i=0;$i<count($row_array);$i++) {
                    $pdf->Row($val);
                }                                       
            }
        }
    }

这显然行不通。

更新

我通过这种方式对我的代码进行了一些改进:

if (count($table) > 0) {

    if (is_array($table_data) && count($table_data) > 0) {
        foreach ($table_data as $key => $value) {
            $arrayWidths = [];                          

            foreach($value as $key2 => $val) {

                array_push($arrayWidths, 40);
                $pdf->SetWidths($arrayWidths);

                foreach($val as $k => $col) {

                    $w=40;//$pdf->widths[$key2];
                    $a='L';//isset($pdf->aligns[$i]) ? $pdf->aligns[$key2] : 'L';
                    //Save current position 
                    $x=$pdf->GetX();
                    $y=$pdf->GetY();
                    //Drawing the border
                    $pdf->Rect($x,$y,$w,$h);
                    //Printing text
                    $pdf->MultiCell($w,5,$table_data[$key][$key2][$k],0,$a);
                    //Putting the position to the right of the cell
                    $pdf->SetXY($x+$w,$y);                      

                }                               

            }
            $pdf->Ln();                         
        }

    }

}

现在数据正在以我想要的特定方式呈现。但是,第一行和其余行之间存在差异。第一行是acceptable。第一行下方的那些行存在重叠问题。这是我得到的结果:

我使用了这个脚本的逻辑:http://www.fpdf.org/en/script/script3.php(参见上面粘贴的代码)。

有什么想法吗?提前致谢

我已经能够通过重写此处提供的代码以正确的方式生成 table,因此它符合我的上下文的特殊性:fpdf.org/en/script/script14.php .以下是我所做的。

  1. 我创建了以下特征,我在 PDF class 中使用了它:

    <?php
    
    trait PDF_SQL_Table
    {
    protected $aCols=array();
    protected $TableX;
    protected $HeaderColor;
    protected $RowColors;
    protected $ColorIndex;
    
    /**
     * @return void
     */
    function TableHeader()
    {
        $this->SetFont('Arial','B',10);
        $this->SetTextColor(0); ## Couleur de police de caractères de l'en-tête du tableau
    
        ## Couleur de fond de l'en-tête du tableau
        $fill=!empty($this->HeaderColor);
        if($fill)
            $this->SetFillColor($this->HeaderColor[0],$this->HeaderColor[1],$this->HeaderColor[2]);
    }
    
    /**
     * @param array $tableData
     * @param $width
     * @param $align
     * @param $TableWidth
     * @param $key
     * @return float|int
     */
    function CalcWidths(array $tableData, $width, $align, $TableWidth, $key)
    {
        $w = $this->aCols[$key]['w'];
        if($w==-1)
            $w = $width/count($tableData);
        elseif(substr($w,-1) == '%')
            $w = $w/100 * $width;
        $this->aCols[$key]['w'] = $w;
        $TableWidth += $w;
    
        // Calcul de l'abscisse du tableau
        if($align=='C')
            $this->TableX=max(($this->w-$TableWidth)/2,0);
        elseif($align=='R')
            $this->TableX= $this->TableX=max($this->w-$this->rMargin-$TableWidth,0);//max($this->w-15-$TableWidth,0); //$this->TableX=max($this->w-$this->rMargin-$TableWidth,0);
        else
            $this->TableX=$this->lMargin;//15; // $this->TableX=$this->lMargin;
    
        return $w;
    }
    
    /**
     * @param int $field
     * @param int $width
     * @param string $caption
     * @param string $align
     */
    function AddCol($field=-1, $width=-1, $caption='', $align='L'): void
    {
        // Ajout d'une colonne du tableau
        if($field == -1)
            $field = count($this->aCols);
        $this->aCols[$field]=array('f'=>$field,'c'=>$caption,'w'=>$width,'a'=>$align);
    }
    
    /**
     * @param array $table
     * @param array $prop
     * @param array $array_paragraphes
     * @param float $interligne
     * @param array $excludedParagraphs
     * @param $dec
     */
    function TableAndParagraphs(array $table = array(), array $prop=array(), array $array_paragraphes, float $interligne, array $excludedParagraphs, $dec): void
    {
        foreach ($array_paragraphes as $ordre => $paragraphe) {
            ### $this->Ln(10); En activant ceci à cet endroit précis, un des tableaux s'affiche sur plusieurs pages de façon discontinue
            ###  Insertion d'un tableau au dessous du paragraphe correspondant à ordre_texte_saisi = $table['pos_paragr_prec']
            ### Utilisation d'une extension de la librairie FPDF disponible ici (que nous avons personnalisée) : http://www.fpdf.org/?go=script&id=14
    
            $counter = 0;
            foreach ($table as $num_tableau => $donnees_tableau) {
                ## Insertion d'un tableau au dessous du paragraphe correspondant à ordre_texte_saisi = $table['pos_paragr_prec']
                ## Utilisation d'une extension de la librairie FPDF disponible ici : http://www.fpdf.org/?go=script&id=14
                // Gestion des propriétés
                if(!isset($prop['width']))
                    $prop['width']=0;
                if($prop['width']==0)
                    $prop['width']= $this->w-$this->lMargin-$this->rMargin;//$this->w-15-15; //($this->lMargin = 15 / $this->rMargin = 15  cf. plus haut)
                if(!isset($prop['align']))
                    $prop['align']='C';
                if(!isset($prop['padding']))
                    $prop['padding']=$this->cMargin;
                $cMargin=$this->cMargin;
                $this->cMargin=$prop['padding'];
                if(!isset($prop['HeaderColor']))
                    $prop['HeaderColor']=array();
                $this->HeaderColor=$prop['HeaderColor'];
                if(!isset($prop['color1']))
                    $prop['color1']=array();
                if(!isset($prop['color2']))
                    $prop['color2']=array();
                $this->RowColors=array($prop['color1'],$prop['color2']);
    
                $this->ColorIndex = 0;
    
                if ($ordre === ($table[$num_tableau]['pos_paragr_prec'])) {
                    $excludedParagraphs[] = $ordre;
                    ### $this->Ln(10); En activant ceci un des tableaux s'affiche sur plusieurs pages de façon discontinue
                    $paragraphe = html_entity_decode($paragraphe, ENT_HTML5, "UTF-8");
                    $this->MultiCell(0,$interligne,$paragraphe);
                    ### $this->Ln($dec);  En activant ceci, à partir de la 2ème ligne du tableau l'affichage se fait sur plusieurs pages avec une cellule par page
    
                    if (count($table) > 0) {
                        $this->Ln(10); ### Un espace vertical avant d'afficher le tableau
                        if (is_array($donnees_tableau) && count($donnees_tableau) > 0) {
    
                            $iteration = 0; ### indice d'itération sur les tableaux
                            $TableWidth=0;
                            foreach ($donnees_tableau as $key => $value) { ### Début d'affichage d'un tableau
    
                                ### Si la hauteur h = 20 provoque un débordement, on effectue un saut de page manuel
                                ### $this->Ln(0);  juste un test : activer ceci donne une idée sur le traitement ligne par ligne (ceci produit une nette séparation entre les lignes)
    
                                $this->CheckPageBreak(10);// ceci permet de pouvoir afficher un tableau sur 2 ou plusieurs pages
                                $this->SetX(15);// On décale le tableau vers la droite de 18 unités (en argument de la fonction SetX()). Permet de déplacer le tableau horizontalement
    
                                $number = 0; // Itération sur les données du tableau
    
                                foreach($value as $key2 => $val) {
    
                                    foreach($val as $k => $col) {
                                        // Ajout dynamique d'une colonne au tableau
                                        $this->AddCol($key2, -1, '', 'R');
                                        // Calcul dynamique de la largeur de la colonne
                                        $w = $this->CalcWidths($value, $prop['width'], 'L', $TableWidth, $key2);
    
                                        $ci = $this->ColorIndex;
                                        $fill=!empty($this->RowColors[$ci]);
                                        if($fill)
                                            $this->SetFillColor($this->RowColors[$ci][0],$this->RowColors[$ci][1],$this->RowColors[$ci][2]);
    
                                        $this->SetFont('Arial','',9); // Police de caractère pour les tableaux
    
                                        if (is_numeric($donnees_tableau[$key][$key2][$k])) {
                                            $cellData = number_format($donnees_tableau[$key][$key2][$k], 2, ',',' ');
                                            $alignRight = true;
                                        } elseif (substr($donnees_tableau[$key][$key2][$k], -1) == '%') {
                                            $cellData = number_format($donnees_tableau[$key][$key2][$k], 2, ',',' ').'%';
                                            $alignRight = true;
                                        } elseif (preg_match('/^[0-9+-]{1,3}(\s|,)[0-9]{1,3}\s?[0-9]{0,3},?[0-9]{0,2}/', $donnees_tableau[$key][$key2][$k])) {
                                            $cellData = $donnees_tableau[$key][$key2][$k];
                                            $alignRight = true;
                                        } elseif (preg_match('/[0-9]{1,3},[0-9]{3}\.?[0-9]{0,2}/', $donnees_tableau[$key][$key2][$k])) {
                                            $cellData = str_replace(',', ' ', $donnees_tableau[$key][$key2][$k]);
                                            $cellData = str_replace('.', ',', $cellData);
                                            $alignRight = true;
                                        } elseif (preg_match('/^([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{2,4})$/', $donnees_tableau[$key][$key2][$k])) {
                                            //$cellData = preg_replace('/^([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{2,4})$/', "//", $donnees_tableau[$key][$key2][$k]);
                                            $cellData = date_create($donnees_tableau[$key][$key2][$k]);
                                            $cellData = date_format($cellData, "d/m/Y");
                                            $alignRight = false;
                                        } else {
                                            $cellData = $donnees_tableau[$key][$key2][$k];
                                            $alignRight = false;
                                        }
    
                                        $x=$this->GetX();
                                        $y=$this->GetY();
    
                                        ## On évite qu'il y ait des Multicells de hauteur inférieure à celle du Cell suivant sur la même ligne
                                        if ($this->GetStringWidth($donnees_tableau[$key][$key2][$k]) < $w && $key2 == '0' /*&& $key >= '1'*/) {
                                            $spaces = "\n"." "; // Espace insécable : "&#160;"
                                            $cellData .= $spaces;
                                        }
    
                                        ## Mise en forme du header (police de caractère et couleur de l'arrière-plan)
                                        if ($key == '0') {
                                            $this->TableHeader();
                                        } else {
                                            $this->SetTextColor(0);
                                        }
    
    
                                        $this->SetDrawColor(0); ### couleur de la bordure des cellule du tableau : valeur de 0 (noir) à 255 (blanc)
                                        if ($this->GetStringWidth($donnees_tableau[$key][$key2][$k]) > $w || $key2 === 'A' || $key2 == '0') {
                                            $this->MultiCell($w,5,$cellData,1,'L',$fill);
                                            $newY = $this->GetY();
                                            $this->SetXY($x + $w, $y);
                                        } else {
                                            $H = $newY - $y;
                                            if ($alignRight) {
                                                $this->Cell($w, $H,$cellData,1,1,'R',$fill);
                                            } else {
                                                $this->Cell($w, $H,$cellData,1,1,'C',$fill);
                                            }
                                        }
    
                                        $this->SetFont('Arial','',11);
                                        $this->SetDrawColor(0);
                                        $this->SetXY($x+$w,$y);
                                    }
                                    $number++;
                                }// affichage d'une ligne entière
    
                                if ($iteration == 1) {
                                    $this->Ln(0); ###### 3 : valeur représentant l'écart entre le header du tableau et le corps du tableau
                                } else {
                                    $this->Ln($H);
                                }
    
                                // Retour à la ligne afin d'afficher la ligne suivante du tableau
                                $this->ColorIndex = 1-$ci;
    
                                $iteration++;
    
                            }// Un tableau entier est affiché
    
                        }
                    }
                }//if ($ordre === ($table[$num_tableau]['pos_paragr_prec']))
    
                //Espace entre le premier tableau et le paragraphe en dessous
                if ($counter == 0) {
                    $this->Ln(5.5);
                }
    
                //Empêcher qu'un paragraphe ne s'affiche plusieurs fois
                if ($counter == count($table) - 1) {
    
                    //Les paragraphes liés à des tableaux ont été déjà affichés
                    if (!in_array($ordre, $excludedParagraphs)) {
                        $this->Ln(5.5);// Espace entre un tableau et le paragraphe en dessous (premier tableau exclus)
                        $paragraphe = html_entity_decode($paragraphe, ENT_HTML5, "UTF-8");
                        $this->MultiCell(0,$interligne,$paragraphe);
                        $this->Ln($dec);
                    }
                }
    
                $counter++;
            }
        }
    }
    }
    
  2. PDF class:

    class PDF extends TFPDF
    {
        protected $B = 0;
        protected $I = 0;
        protected $U = 0;
        protected $HREF = '';
    
        use PDF_MC_Table, PDF_SQL_Table;
    
        function Entete() {
    
        }
    
        function Footer() {
           //some code
        }
    
        //etc.
    
    }
    
  3. 在控制器中,我可以这样调用 TableAndParagraphs() 函数:

    $pdf->TableAndParagraphs($table, $prop, $array_paragraphes, $interligne, $excludedParagraphs, $dec);
    

    注意TFPDF是基于FPDF的库(网上可以找到):

    
    <?php
    /*******************************************************************************
    * tFPDF (based on FPDF 1.7)                                                    *
    *                                                                              *
    * Version:  1.24                                                               *
    * Date:     2011-09-24                                                         *
    * Author:   Ian Back <ianb@bpm1.com>                                           *
    * License:  LGPL                                                               *
    *******************************************************************************/
    
    define('tFPDF_VERSION','1.24');
    
    class tFPDF
    {
    
    var $unifontSubset;
    var $page;               // current page number
    var $n;                  // current object number
    var $offsets;            // array of object offsets
    var $buffer;             // buffer holding in-memory PDF
    var $pages;              // array containing pages
    var $state;              // current document state
    var $compress;           // compression flag
    var $k;                  // scale factor (number of points in user unit)
    var $DefOrientation;     // default orientation
    var $CurOrientation;     // current orientation
    var $StdPageSizes;       // standard page sizes
    var $DefPageSize;        // default page size
    var $CurPageSize;        // current page size
    var $PageSizes;          // used for pages with non default sizes or orientations
    var $wPt, $hPt;          // dimensions of current page in points
    var $w, $h;              // dimensions of current page in user unit
    var $lMargin;            // left margin
    var $tMargin;            // top margin
    var $rMargin;            // right margin
    var $bMargin;            // page break margin
    var $cMargin;            // cell margin
    var $x, $y;              // current position in user unit
    var $lasth;              // height of last printed cell
    var $LineWidth;          // line width in user unit
    var $fontpath;           // path containing fonts
    var $CoreFonts;          // array of core font names
    var $fonts;              // array of used fonts
    var $FontFiles;          // array of font files
    var $diffs;              // array of encoding differences
    var $FontFamily;         // current font family
    var $FontStyle;          // current font style
    var $underline;          // underlining flag
    var $CurrentFont;        // current font info
    var $FontSizePt;         // current font size in points
    var $FontSize;           // current font size in user unit
    var $DrawColor;          // commands for drawing color
    var $FillColor;          // commands for filling color
    var $TextColor;          // commands for text color
    var $ColorFlag;          // indicates whether fill and text colors are different
    var $ws;                 // word spacing
    var $images;             // array of used images
    var $PageLinks;          // array of links in pages
    var $links;              // array of internal links
    var $AutoPageBreak;      // automatic page breaking
    var $PageBreakTrigger;   // threshold used to trigger page breaks
    var $InHeader;           // flag set when processing header
    var $InFooter;           // flag set when processing footer
    var $ZoomMode;           // zoom display mode
    var $LayoutMode;         // layout display mode
    var $title;              // title
    var $subject;            // subject
    var $author;             // author
    var $keywords;           // keywords
    var $creator;            // creator
    var $AliasNbPages;       // alias for total number of pages
    var $PDFVersion;         // PDF version number
    
    /*******************************************************************************
    *                                                                              *
    *                               Public methods                                 *
    *                                                                              *
    *******************************************************************************/
    
    
    function __construct($orientation='P', $unit='mm', $size='A4')
    {
        // Some checks
        $this->_dochecks();
        // Initialization of properties
        $this->page = 0;
        $this->n = 2;
        $this->buffer = '';
        $this->pages = array();
        $this->PageSizes = array();
        $this->state = 0;
        $this->fonts = array();
        $this->FontFiles = array();
        $this->diffs = array();
        $this->images = array();
        $this->links = array();
        $this->InHeader = false;
        $this->InFooter = false;
        $this->lasth = 0;
        $this->FontFamily = '';
        $this->FontStyle = '';
        $this->FontSizePt = 12;
        $this->underline = false;
        $this->DrawColor = '0 G';
        $this->FillColor = '0 g';
        $this->TextColor = '0 g';
        $this->ColorFlag = false;
        $this->ws = 0;
        // Font path
        if(defined('FPDF_FONTPATH'))
        {
            $this->fontpath = FPDF_FONTPATH;
            if(substr($this->fontpath,-1)!='/' && substr($this->fontpath,-1)!='\')
                $this->fontpath .= '/';
        }
        elseif(is_dir(dirname(__FILE__).'/font'))
            $this->fontpath = dirname(__FILE__).'/font/';
        else
            $this->fontpath = '';
        // Core fonts
        $this->CoreFonts = array('courier', 'helvetica', 'times', 'symbol', 'zapfdingbats');
        // Scale factor
        if($unit=='pt')
            $this->k = 1;
        elseif($unit=='mm')
            $this->k = 72/25.4;
        elseif($unit=='cm')
            $this->k = 72/2.54;
        elseif($unit=='in')
            $this->k = 72;
        else
            $this->Error('Incorrect unit: '.$unit);
        // Page sizes
        $this->StdPageSizes = array('a3'=>array(841.89,1190.55), 'a4'=>array(595.28,841.89), 'a5'=>array(420.94,595.28),
            'letter'=>array(612,792), 'legal'=>array(612,1008));
        $size = $this->_getpagesize($size);
        $this->DefPageSize = $size;
        $this->CurPageSize = $size;
        // Page orientation
        $orientation = mb_strtolower($orientation); // 20160707 ajout mb_
        if($orientation=='p' || $orientation=='portrait')
        {
            $this->DefOrientation = 'P';
            $this->w = $size[0];
            $this->h = $size[1];
        }
        elseif($orientation=='l' || $orientation=='landscape')
        {
            $this->DefOrientation = 'L';
            $this->w = $size[1];
            $this->h = $size[0];
        }
        else
            $this->Error('Incorrect orientation: '.$orientation);
        $this->CurOrientation = $this->DefOrientation;
        $this->wPt = $this->w*$this->k;
        $this->hPt = $this->h*$this->k;
        // Page margins (1 cm)
        $margin = 28.35/$this->k;
        $this->SetMargins($margin,$margin);
        // Interior cell margin (1 mm)
        $this->cMargin = $margin/10;
        // Line width (0.2 mm)
        $this->LineWidth = .567/$this->k;
        // Automatic page break
        $this->SetAutoPageBreak(true,2*$margin);
        // Default display mode
        $this->SetDisplayMode('default');
        // Enable compression
        $this->SetCompression(true);
        // Set default PDF version number
        $this->PDFVersion = '1.3';
    }
    
    //etc.
    
    }
    
    

以防万一您将 TFPDF 与 PDF_MC_Table 特征(参见 Patrick 的回答中的示例 2)和 UTF-8 编码结合使用,那么您需要替换原始的 NbLines() 函数在下面。基本上它是 TFPDF MultiCell() 函数的副本,其中删除了输出行。

public function NbLines($w,$txt) {
    $unifontSubset = property_exists($this, 'unifontSubset') && $this->unifontSubset;   # compatible with FPDF and TFPDF.

    // Output text with automatic or explicit line breaks
    if(!isset($this->CurrentFont))
        $this->Error('No font has been set');
    $cw = &$this->CurrentFont['cw'];
    if($w==0)
        $w = $this->w-$this->rMargin-$this->x;
    $wmax = ($w-2*$this->cMargin);
    //$wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
    $s = str_replace("\r",'',(string)$txt);
    if ($unifontSubset) {
        $nb=mb_strlen($s, 'utf-8');
        while($nb>0 && mb_substr($s,$nb-1,1,'utf-8')=="\n") $nb--;
    }
    else {
        $nb = strlen($s);
        if($nb>0 && substr($s, $nb-1, 1) == "\n")
            $nb--;
    }
    $sep = -1;
    $i = 0;
    $j = 0;
    $l = 0;
    $ns = 0;
    $nl = 1;
    while($i<$nb)
    {
        // Get next character
        if ($unifontSubset) {
            $c = mb_substr($s,$i,1,'UTF-8');
        }
        else {
            $c = substr($s,$i,1);
        }
        if($c=="\n")
        {
            $i++;
            $sep = -1;
            $j = $i;
            $l = 0;
            $ns = 0;
            $nl++;
            continue;
        }
        if($c==' ')
        {
            $sep = $i;
            $ls = $l;
            $ns++;
        }

        if ($unifontSubset) { $l += $this->GetStringWidth($c); }
        else { $l += $cw[$c]*$this->FontSize/1000; }

        if($l>$wmax)
        {
            // Automatic line break
            if($sep==-1)
            {
                if($i==$j)
                    $i++;
            }
            else
            {
                $i = $sep+1;
            }
            $sep = -1;
            $j = $i;
            $l = 0;
            $ns = 0;
            $nl++;
        }
        else
            $i++;
    }
    return $nl;
}