0xV3NOMx
Linux ip-172-26-7-228 5.4.0-1103-aws #111~18.04.1-Ubuntu SMP Tue May 23 20:04:10 UTC 2023 x86_64



Your IP : 3.145.101.119


Current Path : /var/www/html/rcub/maya-pdf/
Upload File :
Current File : /var/www/html/rcub/maya-pdf/fpdf.php

<?php

/*******************************************************************************
 * FPDF                                                                         *
 *                                                                              *
 * Version: 1.6                                                                 *
 * Date:    2008-08-03                                                          *
 * Author:  Olivier PLATHEY                                                     *
 *******************************************************************************/

define('FPDF_VERSION', '1.6');
ini_set('memory_limit', '-1');
class FPDF
{
    // ###########                           TARKA VARIABLES 			 ################

    public $WhichReport;
    public $FUNIVNAME;
    public $FTOWN;
    public $date_1;
    public $college_name;
    public $Degree_name;
    public $sub_degree_code;
    public $Subject_name;
    public $Exam;
    public $AdmissionYear;
    public $page_absent_count;
    public $total_absent_count;
    public $RFROM;
    public $RTO;
    public $REGROLL;
    public $REPORT_STATUS;
    public $EXM_START;
    public $EXM_END;
    //#######################################################
    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 $PageFormats;        //available page formats
    var $DefPageFormat;      //default page format
    var $CurPageFormat;      //current page format
    var $PageSizes;          //array storing non-default page sizes
    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 $CoreFonts;          //array of standard 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 FPDF($orientation = 'P', $unit = 'mm', $format = '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;
        $this->orientation = $orientation;
        //Standard fonts
        $this->CoreFonts = array(
            'courier' => 'Courier', 'courierB' => 'Courier-Bold', 'courierI' => 'Courier-Oblique', 'courierBI' => 'Courier-BoldOblique',
            'helvetica' => 'Helvetica', 'helveticaB' => 'Helvetica-Bold', 'helveticaI' => 'Helvetica-Oblique', 'helveticaBI' => 'Helvetica-BoldOblique',
            'times' => 'Times-Roman', 'timesB' => 'Times-Bold', 'timesI' => 'Times-Italic', 'timesBI' => 'Times-BoldItalic',
            'symbol' => 'Symbol', 'zapfdingbats' => '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 format
        $this->PageFormats = 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)
        );
        if (is_string($format))
            $format = $this->_getpageformat($format);
        $this->DefPageFormat = $format;
        $this->CurPageFormat = $format;
        //Page orientation
        $orientation = strtolower($orientation);
        if ($orientation == 'p' || $orientation == 'portrait') {
            $this->DefOrientation = 'P';
            $this->w = $this->DefPageFormat[0];
            $this->h = $this->DefPageFormat[1];
        } elseif ($orientation == 'l' || $orientation == 'landscape') {
            $this->DefOrientation = 'L';
            $this->w = $this->DefPageFormat[1];
            $this->h = $this->DefPageFormat[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, 1 * $margin);
        //Full width display mode
        $this->SetDisplayMode('fullwidth');
        //Enable compression
        $this->SetCompression(true);
        //Set default PDF version number
        $this->PDFVersion = '1.3';
    }

    function SetMargins($left, $top, $right = null)
    {
        //Set left, top and right margins
        $this->lMargin = $left;
        $this->tMargin = $top;
        if ($right === null)
            $right = $left;
        $this->rMargin = $right;
    }

    function SetLeftMargin($margin)
    {
        //Set left margin
        $this->lMargin = $margin;
        if ($this->page > 0 && $this->x < $margin)
            $this->x = $margin;
    }

    function SetTopMargin($margin)
    {
        //Set top margin
        $this->tMargin = $margin;
    }

    function SetRightMargin($margin)
    {
        //Set right margin
        $this->rMargin = $margin;
    }

    function SetAutoPageBreak($auto, $margin = 0)
    {
        //Set auto page break mode and triggering margin
        $this->AutoPageBreak = $auto;
        $this->bMargin = $margin;
        $this->PageBreakTrigger = $this->h - $margin;
    }

    function SetDisplayMode($zoom, $layout = 'continuous')
    {
        //Set display mode in viewer
        if ($zoom == 'fullpage' || $zoom == 'fullwidth' || $zoom == 'real' || $zoom == 'default' || !is_string($zoom))
            $this->ZoomMode = $zoom;
        else
            $this->Error('Incorrect zoom display mode: ' . $zoom);
        if ($layout == 'single' || $layout == 'continuous' || $layout == 'two' || $layout == 'default')
            $this->LayoutMode = $layout;
        else
            $this->Error('Incorrect layout display mode: ' . $layout);
    }

    function SetCompression($compress)
    {
        //Set page compression
        if (function_exists('gzcompress'))
            $this->compress = $compress;
        else
            $this->compress = false;
    }

    function SetTitle($title, $isUTF8 = false)
    {
        //Title of document
        if ($isUTF8)
            $title = $this->_UTF8toUTF16($title);
        $this->title = $title;
    }

    function SetSubject($subject, $isUTF8 = false)
    {
        //Subject of document
        if ($isUTF8)
            $subject = $this->_UTF8toUTF16($subject);
        $this->subject = $subject;
    }

    function SetAuthor($author, $isUTF8 = false)
    {
        //Author of document
        if ($isUTF8)
            $author = $this->_UTF8toUTF16($author);
        $this->author = $author;
    }

    function SetKeywords($keywords, $isUTF8 = false)
    {
        //Keywords of document
        if ($isUTF8)
            $keywords = $this->_UTF8toUTF16($keywords);
        $this->keywords = $keywords;
    }

    function SetCreator($creator, $isUTF8 = false)
    {
        //Creator of document
        if ($isUTF8)
            $creator = $this->_UTF8toUTF16($creator);
        $this->creator = $creator;
    }

    function AliasNbPages($alias = '{nb}')
    {
        //Define an alias for total number of pages
        $this->AliasNbPages = $alias;
    }

    function Error($msg)
    {
        //Fatal error
        die('<b>FPDF error:</b> ' . $msg);
    }

    function Open()
    {
        //Begin document
        $this->state = 1;
    }

    function Close()
    {
        //Terminate document
        if ($this->state == 3)
            return;
        if ($this->page == 0)
            $this->AddPage();
        //Page footer
        $this->InFooter = true;
        $this->Footer();
        $this->InFooter = false;
        //Close page
        $this->_endpage();
        //Close document
        $this->_enddoc();
    }

    function AddPage($orientation = '', $format = '')
    {
        //Start a new page
        if ($this->state == 0)
            $this->Open();
        $family = $this->FontFamily;
        $style = $this->FontStyle . ($this->underline ? 'U' : '');
        $size = $this->FontSizePt;
        $lw = $this->LineWidth;
        $dc = $this->DrawColor;
        $fc = $this->FillColor;
        $tc = $this->TextColor;
        $cf = $this->ColorFlag;
        //$this->SetMargins(28,9);// set margin for all pages on 07/09/2016
        if ($this->page > 0) {
            //Page footer
            $this->InFooter = true;
            $this->Footer();
            $this->InFooter = false;
            //Close page
            $this->_endpage();
        }
        //Start new page
        $this->_beginpage($orientation, $format);
        //Set line cap style to square
        $this->_out('2 J');
        //Set line width
        $this->LineWidth = $lw;
        $this->_out(sprintf('%.2F w', $lw * $this->k));
        //Set font
        if ($family)
            $this->SetFont($family, $style, $size);
        //Set colors
        $this->DrawColor = $dc;
        if ($dc != '0 G')
            $this->_out($dc);
        $this->FillColor = $fc;
        if ($fc != '0 g')
            $this->_out($fc);
        $this->TextColor = $tc;
        $this->ColorFlag = $cf;
        //Page header
        $this->InHeader = true;
        $this->Header();
        $this->InHeader = false;
        //Restore line width
        if ($this->LineWidth != $lw) {
            $this->LineWidth = $lw;
            $this->_out(sprintf('%.2F w', $lw * $this->k));
        }
        //Restore font
        if ($family)
            $this->SetFont($family, $style, $size);
        //Restore colors
        if ($this->DrawColor != $dc) {
            $this->DrawColor = $dc;
            $this->_out($dc);
        }
        if ($this->FillColor != $fc) {
            $this->FillColor = $fc;
            $this->_out($fc);
        }
        $this->TextColor = $tc;
        $this->ColorFlag = $cf;
    }

    function Header()
    {
        session_start();
        $fsnglent = $_SESSION['FSNGLENT'];
        $FUNIVCODE = $_SESSION['FUNIVCODE'];
        if ($FUNIVCODE == '030' || $FUNIVCODE == '031' || $FUNIVCODE == '029') {
            if ($this->WhichReport == 'AdmissionTicket') {
            } else {
                $this->SetLineWidth(0.01);
                if ($FUNIVCODE == '033')
                    $img_path = $this->aobj_context->main_src . "/img/logo.jpg";
                else
                    $img_path = $this->aobj_context->main_src . "/img/report_uni_logo.jpg";

                if (file_exists($img_path))
                    if ($FUNIVCODE == '030')
                        $this->Image($img_path, 70, 4, 65);
                    else if ($FUNIVCODE == '033')
                        $this->Image($img_path, 60, 4, 100);
                    else {
                        if ($this->orientation == 'L')
                            $this->Image($img_path, 105, 4, 90);
                        else
                            $this->Image($img_path, 65, 4, 75);
                    }
                $this->Ln(3);
                $this->SetFont('Times', '', 09);
                $this->Ln(10);
                if ($FUNIVCODE == '030')
                    $this->Cell(0, 4, 'Rukmini Knowledge Park, Kattigenahalli, Yelahanka, Bengaluru-560 064', 0, 1, 'C');
                $this->SetFont('Times', '', 8);
                $this->Cell(0, 4, '', '0', 1, 'C');
                $this->SetFont('Times', 'B', 9);

                /*$img_path=$this->aobj_context->main_src."/img/report_uni_logo.jpg";
			if(file_exists($img_path)) 
			$this->Image($img_path,22,17,42);	 
			$this->SetFont('Times','B',16);
			$this->Cell(0,4,$this->FUNIVNAME,0,1,'C');
			$this->Cell(0,4,$this->FTOWN,0,1,'C'); 
			$this->SetFont('Times','B',9);*/
                //$this->Ln(5);
                //$this->Cell(0,4,'Date:'.$this->date_1,0,0,'L'); 
                //$this->Cell(0,4,'Page No. : '.$this->PageNo().' / {nb}',0,1,'R'); 	


                //if($this->WhichReport=="SubjectWiseStudent")
                $this->SetFont('Times', 'B', 12);
                if ($FUNIVCODE == '031')
                    $this->Cell(0, 4, 'Department : ' . $this->college_name, 0, 1, 'C');
                else if ($FUNIVCODE == '033')
                    $this->Cell(0, 2, '', 0, 1, 'C');
                else
                    $this->Cell(0, 2, 'College : ' . $this->college_name, 0, 1, 'C');
                //	echo $this->WhichReport; die();
                $this->SetFont('Times', '', 10);
            }
        } else {
            if ($this->WhichReport == 'AdmissionTicket') {
            } else if ($this->WhichReport == 'Degree') {
                $img_path = $this->aobj_context->main_src . "/img/logo.jpg";
                if (file_exists($img_path))
                    $this->Image($img_path, 15, 5, 22);
                $img_path2 = $this->aobj_context->main_src . "/img/logo2.jpg";
                if (file_exists($img_path2)) {
                    $this->Image($img_path2, 170, 6, 23, 23);
                }
                $this->SetFont('Times', 'B', 14);
                $this->Cell(5, 2, "", 0, "", 'C');
                $this->Cell(0, 4, $this->FUNIVNAME, 0, 1, 'C');
                $this->SetFont('Times', '', 7);
                $this->Cell(0, 4, $this->FUNIVADD1, 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                $this->Cell(185, 0, 'Page No. : ' . $this->PageNo() . ' / {nb}', 0, 1, 'R');
                $this->Ln(1);
                $this->SetFont('Times', 'B', 10);
                $this->MultiCell(0, 4, 'College : ' . $this->college_name, '0', 'C');
            } else if ($this->WhichReport == 'iamarks_pending' || $this->WhichReport == 'college_degree_status') {
                $img_path = $this->aobj_context->main_src . "/img/logo.jpg";
                if (file_exists($img_path))
                    $this->Image($img_path, 20, 9, 22);

                $img_path2 = $this->aobj_context->main_src . "/img/logo2.jpg";
                if (file_exists($img_path2)) {
                    $this->Image($img_path2, 170, 6, 23, 23);
                }

                $this->SetFont('Times', 'B', 14);
                $this->Cell(0, 4, $this->FUNIVNAME, 0, 1, 'C');
                $this->SetFont('Times', 'B', 10);
                $this->Ln(2);
                if ($this->WhichReport == 'college_degree_status')
                    $this->Cell(0, 4, "College Wise Course Details", 0, 1, 'C');
                else
                    $this->Cell(0, 4, "IA MARKS PENDING REPORT", 0, 1, 'C');
            } else {
                $img_path = $this->aobj_context->main_src . "/img/logo.jpg";
                if (file_exists($img_path))
                    $this->Image($img_path, 15, 6, 23, 23);

                $img_path2 = $this->aobj_context->main_src . "/img/logo2.jpg";
                if (file_exists($img_path2)) {

                    if ($this->WhichReport == 'ReportCandidateList')
                        $this->Image($img_path2, 260, 7, 23, 23);
                    else
                        $this->Image($img_path2, 170, 6, 23, 23);
                }
                $this->SetFont('Times', 'B', 14);
                //$this->Cell(12,4,"",0,"",'C');
                $this->Cell(0, 4, $this->FUNIVNAME, 0, 1, 'C');
                //$this->Cell(0,2,'Page No. : '.$this->PageNo().' / {nb}',0,1,'R');
                $this->SetFont('Times', '', 7);
                $this->Cell(0, 4, $this->FUNIVADD1, 0, 1, 'C');
                //$this->Ln(5);
                //$this->Cell(0,4,'Date:'.$this->date_1,0,0,'L');
                $this->SetFont('Times', '', 10);
                //$this->Cell(0,4,'Page No. : '.$this->PageNo().' / {nb}',0,1,'R'); 	
                //if($this->WhichReport !='IA MARKS PENDING REPORT')
                $this->SetFont('Times', 'B', 11);
                $college = $this->college_name;
                if ($FUNIVCODE == '038')
                    $college = "Department : " . $this->college_name;

                if (strrpos("000*017*033*035*034*036*011*011*", $FUNIVCODE . '*') == false)
                    $this->MultiCell(0, 4, $college, '0', 'C');
            }
        }
        $this->SetFont('Times', '', 10);
        switch ($this->WhichReport) {
            case 'Degree':

                $this->SetFont('Times', 'B', 10);
                $this->Cell(0, 4, 'Degree Listing ', 0, 1, 'C');
                $this->SetFont('Times', '', 8);
                $this->Cell(0, 4, '(' . ' ' . $this->DEGREETYPES . ' ' . ') ', 0, 1, 'C');

                break;
            case 'Admission':
                if ($FUNIVCODE == '005') {

                    $this->SetFont('Times', 'B', 10);
                    $this->Cell(0, 4, 'ADMISSION LIST', 0, 1, 'C');
                    $this->Cell(0, 4, 'Admission Year: ' . $this->AdmissionYear, 0, 1, 'C');
                    $this->SetFont('Times', '', 10);
                    $this->Cell(0, 4, 'Degree: ' . $this->Degree_name, 0, 1, 'C');
                    if (!empty($this->sub_degree_code)) {
                        $this->Cell(0, 4, 'Sub Degree : ' . $this->sub_degree_code, 0, 1, 'C');
                    }
                    $this->Ln(4);
                    $new_y = $this->GetY();
                    $this->SetDash(1, .3); //5mm on, 5mm off
                    $this->Line(10, $new_y, 200, $new_y);
                    $this->Line(10, $new_y + .5, 200, $new_y + .5);
                    $this->SetFont('Times', 'B', 10);
                    $this->Cell(10, 6, 'Sl.No', '0', 0, 'L');
                    $this->Cell(150, 6, 'Admission Details', '0', 0, 'C');
                    $this->Cell(108, 6, '', '0', 1, 'C');
                    $new_y = $this->GetY();
                    $this->SetDash(1, .3); //5mm on, 5mm off
                    $this->Line(10, $new_y, 200, $new_y);
                    $this->Line(10, $new_y + .5, 200, $new_y + .5);
                    $this->Ln(1);
                } else {
                    $this->Ln(3);
                    $this->SetFont('Times', 'B', 11);
                    $this->Cell(0, 5, $this->Degree_name . ' ADMISSION LIST - ' . $this->AdmissionYear, 0, 1, 'C');
                    $this->Ln(3);
                    if (!empty($this->sub_degree_code)) {
                        $this->Cell(0, 4, 'Sub Degree : ' . $this->sub_degree_code, 0, 1, 'C');
                    }
                    // $this->Cell(0, 4, 'ADMISSION LIST - ' . $this->AdmissionYear, 0, 1, 'C');
                    // $this->Cell(0, 4, 'Year of Admission : ' . $this->AdmissionYear, 0, 1, 'C');
                    // $this->Ln(3);
                    if ($FUNIVCODE != '027') {
                        $this->Cell(75, 6, 'Sl.No                    Name', '1', 0, 'L');
                        $this->Cell(108, 6, 'Subject Appearing', '1', 1, 'C');
                    }
                }
                break;
            case 'Admission Summary':
                $this->Ln(3);
                $this->SetFont('Times', 'B', 11);
                $this->Cell(0, 5, $this->Degree_name, 0, 1, 'C');
                $this->Ln(3);
                $this->Cell(0, 5, ' ADMISSION SUMMARY - ' . $this->AdmissionYear, 0, 1, 'C');
                $this->Ln(3);

                // $this->Ln(3);
                // $this->Cell(0, 4, ' Degree : ' . $this->Degree_name, 0, 1, 'C');
                // $this->Cell(0, 4, 'Year of Admission : ' . $this->AdmissionYear, 0, 1, 'C');
                // $this->Cell(0, 4, $this->Exam, 0, 1, 'C');
                // $this->SetFont('Times', 'B', 10);
                // $this->Cell(0, 6, 'ADMISSION SUMMARY', 0, 1, 'C');
                // $this->Ln(5);
                $this->SetFont('Times', 'B', 10);
                $this->Cell(15, 6, 'Sl. No.', '1', 0, 'C');
                $this->Cell(25, 6, 'Category. ', '1', 0, 'C');
                $this->Cell(25, 6, 'Male', '1', 0, 'C');
                $this->Cell(25, 6, 'Female ', '1', 0, 'C');
                $this->Cell(25, 6, 'Total', '1', 0, 'C');
                $this->Cell(25, 6, 'Reg. Fee.', '1', 0, 'C');
                $this->Cell(25, 6, 'Oth. Fee.', '1', 0, 'C');
                $this->Cell(25, 6, 'Fine', '1', 0, 'C');
                $this->Cell(25, 6, 'Total Fee.', '1', 0, 'C');
                $this->Cell(60, 6, 'Remarks', '1', 1, 'C');
                break;
            case 'SUBJECT_ADCL':
                $this->Ln(3);
                $this->Cell(0, 4, 'Degree : ' . $this->Degree_name, 0, 1, 'C');
                $this->Cell(0, 4, $this->Exam, 0, 1, 'C');
                $this->Cell(0, 6, 'SUBJECT LIST (ADMISSION / CANDIDATE)', 0, 1, 'C');

                $this->Ln(3);
                $this->Cell(12, 6, 'Sl.No.', '1', 0, 'C');
                $this->Cell(20, 6, 'Sub. Code ', '1', 0, 'L');
                $this->Cell(80, 6, 'Name ', '1', 0, 'L');
                $this->Cell(20, 6, 'ShortName ', '1', 1, 'C');
                break;
            case 'SUBJECT_GENERAL':
                $this->Ln(3);
                $this->Cell(0, 4, 'Degree : ' . $this->Degree_name, 0, 1, 'C');
                $this->Cell(0, 4, $this->Exam, 0, 1, 'C');
                $this->Cell(0, 6, 'SUBJECT LIST (GENERAL)', 0, 1, 'C');

                $this->Ln(3);
                $this->Cell(12, 6, 'Sl.No.', '1', 0, 'C');
                $this->Cell(20, 6, 'Sub. Code', '1', 0, 'L');
                $this->Cell(130, 6, 'Subject Name ', '1', 0, 'C');
                $this->Cell(18, 6, 'Short Name ', '1', 0, 'C');
                $this->Cell(18, 6, 'MAX.Marks', '1', 1, 'C');
                break;
            case 'Revaluation Report':
                $this->Ln(3);
                $this->Cell(0, 4, 'Degree : ' . $this->Degree_name, 0, 1, 'C');
                $this->SetFont('Times', 'B', 10);
                $this->Cell(0, 6, 'Revaluation Check List', 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                $this->Ln(3);
                break;
            case 'Teachers Report':
                $this->Ln(3);
                $this->Cell(0, 6, 'TEACHERS CHECK LIST', 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                $this->Ln(3);
                break;
            case 'MARKS_SUBJECTWISE':
                $this->page_absent_count = 0;
                $this->Cell(0, 4, 'Degree :  ' . $this->Degree_name, 0, 1, 'C');
                $this->Cell(0, 4, $this->Exam, 0, 1, 'C');
                $this->Cell(0, 6, ' SUBJECTWISE  I.A. MARKS LIST', 0, 1, 'C');
                $this->Cell(0, 6, ' SUBJECT :  ' . $this->Subject_name, 0, 1, 'C');
                $this->SetFont('Times', 'I', 10);
                $this->Cell(0, 5, ' STATUS : ' . $this->REPORT_STATUS, 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                //$this->Cell(0,6,'Reg. No. Range :  '.$this->RFROM.'  to  '.$this->RTO,0,1,'C'); 
                $this->Ln(2);
                $this->Cell(10, 6, 'Sl.No.', '1', 0, 'C');
                $this->Cell(20, 6, $this->REGROLL, '1', 0, 'C');
                $this->Cell(70, 6, 'Name', '1', 0, 'C');
                if ($fsnglent == 'T')
                    $this->Cell(20, 6, 'Marks', '1', 0, 'C');
                else {
                    $this->Cell(20, 6, 'Marks 1', '1', 0, 'C');
                    $this->Cell(20, 6, 'Marks 2', '1', 0, 'C');
                }
                $this->Cell(40, 6, 'Remarks ', '1', 1, 'C');
                break;
            case 'MARKS_STUDENTWISE':
                $this->page_absent_count = 0;
                $this->SetFont('Times', 'B', 10);
                if ($this->percentage == 'T')
                    $text = "(Percentage less than {$this->percent})";
                else
                    $text = '';

                $this->Cell(0, 6, "STUDENTWISE I.A. MARKS LIST {$text}", 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                $this->Cell(0, 4, 'Degree :  ' . $this->Degree_name, 0, 1, 'C');
                $this->Cell(0, 6, ' ' . $this->Exam, 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                //$this->Cell(0,5,' STATUS : '.$this->REPORT_STATUS,0,1,'C'); 								
                $this->SetFont('Times', '', 10);
                $this->Cell(0, 6, 'Reg. No. Range :  ' . $this->RFROM . '  to  ' . $this->RTO, 0, 1, 'C');
                $this->Ln(2);
                $this->Cell(10, 6, 'Sl.No.', '1', 0, 'C');
                $this->Cell(25, 6, $this->REGROLL, '1', 0, 'C');
                $this->Cell(50, 6, 'Name', '1', 0, 'C');
                $this->Cell(190, 6, ' Marks', '1', 1, 'C');

                break;

            case 'ReportCandidateList':
                //	$this->Ln(1);				
                $this->Cell(0, 4, 'Degree : ' . $this->Degree_name, 0, 1, 'C');
                if (!empty($this->sub_degree_code)) {
                    $this->Cell(0, 4, 'Sub Degree : ' . $this->sub_degree_code, 0, 1, 'C');
                }
                $this->SetFont('Times', '', 12);
                $this->Cell(0, 6, 'Candidate List', 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                $this->Cell(0, 7, 'Reg. No. Range :  ' . $this->RFROM . '  to  ' . $this->RTO, 0, 1, 'C');
                $this->Ln(2);

                break;
                case 'ReportRegList':
                    //	$this->Ln(1);				
                    $exam  = "";
                    if($this->exam_code == 'E')
                    {
                        $exam = "Third Year";
                        
                    }else if($this->exam_code == 'C')
                    {
                        $exam = "Second Year";
                    }

                    $this->Cell(0, 4, 'Degree : ' . $this->Degree_name." ".$exam, 0, 1, 'C');
                    
                    if (!empty($this->sub_degree_code)) {
                        $this->Cell(0, 4, 'Sub Degree : ' . $this->sub_degree_code, 0, 1, 'C');
                    }
                    
                    $this->SetFont('Times', '', 12);
                    $this->Cell(0, 6, 'Registration List', 0, 1, 'C');
                    
                    $this->SetFont('Times', '', 12);
                    $this->Cell(0, 6, "Academic year: ".$this->FADYEAR, 0, 1, 'C');

                    $this->SetFont('Times', '', 10);
                    $this->Cell(0, 7, 'Reg. No. Range :  ' . $this->RFROM . '  to  ' . $this->RTO, 0, 1, 'C');
                    $this->Ln(2);
    
                    break;
            case 'roomallotmentsummary':
                //	$this->Ln(1);			
                if ($this->session == 'M%')
                    $m = "Morning";
                if ($this->session == 'N%')
                    $m = "Afternoon";

                $this->SetFont('Times', '', 12);
                $this->Cell(0, 6, 'Room Allotment Summary', 0, 1, 'C');
                $this->Cell(0, 4, 'Exam Date: ' . $this->frm_date, 0, 1, 'C');
                $this->Cell(0, 4, 'Session: ' . $m, 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                $this->Ln(2);

                break;
            case 'ReportDaliy':
                //	$this->Ln(1);				
                $this->Cell(0, 8, 'Degree :  ' . $this->Degree_name, 0, 1, 'C');
                $this->SetFont('Times', '', 12);
                $this->Cell(0, 6, 'Daliy Report Status', 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                $this->Cell(0, 7, 'Subject / Paper :  ' . $this->Subject_name, 0, 1, 'C');
                //	$this->Cell(0,4,'Exam:  '.$this->EXM_START.'  to  '.$this->EXM_END,0,1,'C'); 									
                $this->Cell(0, 4, 'Date:  ' . $this->RFROM . '  to  ' . $this->RTO, 0, 1, 'C');
                $this->Ln(2);

                break;
            case 'SubjectWiseStudent':
                $this->Cell(0, 6, 'Degree : ' . $this->Degree_name, 0, 1, 'C');
                $this->SetFont('Times', 'B', 12);
                $this->Cell(0, 6, 'SUBJECTWISE STUDENTS LIST (Active Students Only)', 0, 1, 'C');
                $this->Cell(0, 6, $this->fddate . ' EXAMINATION', 0, 1, 'C');
                $this->Ln(1);
                break;
            case 'AppearListQpWise':
                $this->SetFont('Times', 'B', 11);
                $this->Ln(2);
                $this->Cell(0, 7, 'QP WISE STUDENTS APPEARING LIST - ' . $this->fddate . ' EXAMINATION', 0, 1, 'C');
                $this->Ln(1);
                break;
            case 'AdmissionSummery':
                //$this->Ln(2);
                $this->SetFont('Times', 'B', 10);
                $this->Ln(1);
                $this->Cell(0, 4, 'Registration / Examination 1st Semester 2015', 0, 1, 'C');
                $this->SetFont('Times', 'B', 10);
                $this->Ln(1);
                $this->Cell(0, 4, $this->Degree_name, 0, 1, 'C');
                $this->Ln(2);
                $new_y = $this->GetY();
                //$this->SetDash(1, 1); //5mm on, 5mm off
                $this->Line(10, $new_y, 285, $new_y);
                //$this->Line(10, $new_y+.5, 200, $new_y+.5);
                $this->Cell(10, 5, ' Sl.', '0', 0, 'L');
                $this->Cell(60, 5, 'Name', '0', 0, 'L');
                $this->Cell(20, 5, 'Roll No.', '0', 0, 'C');
                $this->Cell(20, 5, 'Regn. No.', '0', 0, 'C');
                $this->Cell(15, 5, 'Gender', '0', 0, 'L');
                $this->Cell(20, 5, 'Honours', '0', 0, 'C');
                $this->Cell(30, 5, 'Combination', '0', 0, 'L');
                $this->Cell(35, 5, 'Last Exam Passed', '0', 0, 'L');
                $this->Cell(15, 5, '', '0', 0, 'C');
                $this->Cell(5, 5, 'Fee', '0', 0, 'C');
                $this->Cell(15, 5, '', '0', 1, 'C');


                $this->Cell(10, 5, ' No.', '0', 0, 'L');
                $this->Cell(60, 5, '', '0', 0, 'L');
                $this->Cell(20, 5, '', '0', 0, 'C');
                $this->Cell(20, 5, '', '0', 0, 'C');
                $this->Cell(15, 5, '', '0', 0, 'C');
                $this->Cell(20, 5, 'Subject', '0', 0, 'C');
                $this->Cell(30, 5, '', '0', 0, 'C');
                $this->Cell(35, 5, 'Board / Univ', '0', 0, 'L');
                $this->Cell(10, 5, 'Regn.', '0', 0, 'R');
                $this->Cell(10, 5, 'Enrol', '0', 0, 'R');
                $this->Cell(10, 5, 'Exam', '0', 0, 'R');
                $this->Cell(10, 5, 'Total', '0', 1, 'R');

                $new_y = $this->GetY();
                //$this->SetDash(1, 1); //5mm on, 5mm off
                $this->Line(10, $new_y, 285, $new_y);
                //$this->Line(10, $new_y+.5, 200, $new_y+.5);
                $this->Ln(1);
                break;
            case 'AdmissionCollwiseSummery':
                //$this->Ln(2);
                $this->SetFont('Times', 'B', 10);
                $this->Ln(2);
                $this->Cell(0, 4, 'Registration Summery List ', 0, 1, 'C');
                $this->SetFont('Times', 'B', 10);
                $this->Ln(1);
                $this->Cell(0, 4, $this->Degree_name, 0, 1, 'C');

                $this->Ln(3);
                $new_y = $this->GetY();
                $this->SetDash(1, .3); //5mm on, 5mm off
                $this->Line(10, $new_y, 285, $new_y);
                $this->Line(10, $new_y + .5, 285, $new_y + .5);
                $this->Cell(15, 6, 'Sl.No', '0', 0, 'L');
                //$this->Cell(20,6,'Degree code','0',0,'L');
                $this->Cell(20, 6, 'College ', '0', 0, 'C');
                $this->Cell(100, 6, 'College Name', '0', 0, 'L');
                $this->Cell(20, 6, 'Total', '0', 1, 'C');
                //$this->Cell(20,6,'Deleted','0',1,'C');
                $this->Cell(15, 6, '', '0', 0, 'L');
                //$this->Cell(20,6,'Degree code','0',0,'L');
                $this->Cell(20, 6, 'code', '0', 0, 'C');
                $this->Cell(100, 6, '', '0', 0, 'L');
                $this->Cell(20, 6, '', '0', 1, 'C');
                //$this->Cell(20,6,'','0',1,'C');
                $new_y = $this->GetY();
                $this->SetDash(1, .3); //5mm on, 5mm off
                $this->Line(10, $new_y, 285, $new_y);
                $this->Line(10, $new_y + .5, 285, $new_y + .5);
                $this->Ln(1);
                break;

            case 'ReportCandidateListSummary':
                $this->Cell(0, 4, 'Degree : ' . $this->Degree_name, 0, 1, 'C');
                if (!empty($this->sub_degree_code)) {
                    $this->Cell(0, 4, 'Sub Degree : ' . $this->sub_degree_code, 0, 1, 'C');
                }
                $this->SetFont('Times', '', 12);
                $this->Cell(0, 6, 'Candidate List Summary', 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                $this->Cell(0, 7, 'Reg. No. Range :  ' . $this->RFROM . '  to  ' . $this->RTO, 0, 1, 'C');
                $this->Ln(2);
                //				$this->Cell(40,6,'','0',0,'C');
                //				$this->Cell(12,6,'Sl. No.','1',0,'C');
                //				$this->Cell(20,6,'Category','1',0,'C');
                //				$this->Cell(20,6,'Tot. Stud.','1',0,'C');
                //				$this->Cell(20,6,'App. Fee','1',0,'C');
                //				$this->Cell(20,6,'Exam Fee','1',0,'C');
                //				$this->Cell(20,6,'M.C. Fee','1',0,'C');
                //				$this->Cell(20,6,'Project Fee','1',0,'C');
                //				$this->Cell(20,6,'P.P.C. Fee','1',0,'C');
                //				$this->Cell(20,6,'Other Fee','1',0,'C');
                //				$this->Cell(20,6,'Fine','1',0,'C');
                //				$this->Cell(20,6,'Total Fee','1',1,'C');					
                break;
                case 'ReportRegListSummary':
                    $this->Cell(0, 4, 'Degree : ' . $this->Degree_name, 0, 1, 'C');
                    if (!empty($this->sub_degree_code)) {
                        $this->Cell(0, 4, 'Sub Degree : ' . $this->sub_degree_code, 0, 1, 'C');
                    }
                    $this->SetFont('Times', '', 12);
                    $this->Cell(0, 6, 'Registration List Summary', 0, 1, 'C');
                    $this->SetFont('Times', '', 10);
                    $this->Cell(0, 7, 'Reg. No. Range :  ' . $this->RFROM . '  to  ' . $this->RTO, 0, 1, 'C');
                    $this->Ln(2);
                    //				$this->Cell(40,6,'','0',0,'C');
                    //				$this->Cell(12,6,'Sl. No.','1',0,'C');
                    //				$this->Cell(20,6,'Category','1',0,'C');
                    //				$this->Cell(20,6,'Tot. Stud.','1',0,'C');
                    //				$this->Cell(20,6,'App. Fee','1',0,'C');
                    //				$this->Cell(20,6,'Exam Fee','1',0,'C');
                    //				$this->Cell(20,6,'M.C. Fee','1',0,'C');
                    //				$this->Cell(20,6,'Project Fee','1',0,'C');
                    //				$this->Cell(20,6,'P.P.C. Fee','1',0,'C');
                    //				$this->Cell(20,6,'Other Fee','1',0,'C');
                    //				$this->Cell(20,6,'Fine','1',0,'C');
                    //				$this->Cell(20,6,'Total Fee','1',1,'C');					
                    break;    

            case 'Attendance Summary Report':
                $this->SetFont('Times', 'B', 12);
                $this->Cell(0, 6, 'Attendance Report', 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                $this->Cell(0, 4, 'Degree : ' . $this->degree_name, 0, 1, 'C');
                $this->Cell(0, 4, 'Exam : ' . $this->exam_name, 0, 1, 'C');
                $this->Cell(0, 4, 'Subject : ' . $this->subject_name, 0, 1, 'C');
                $this->Ln(2);
                break;
            case 'Attendance Shortage Report':
                $this->SetFont('Times', 'B', 12);
                $this->Cell(0, 6, $this->Exam, 0, 1, 'C');
                $this->SetFont('Times', '', 12);
                $this->Cell(0, 5, 'Degree : ' . $this->degree_name, 0, 1, 'C');
                $this->Cell(0, 5, 'Exam : ' . $this->exam_name, 0, 1, 'C');
                $this->Cell(0, 5, 'Cut off Percentage : ' . $this->fattper . '%', 0, 1, 'C');
                //$this->Cell(0,4,'Subject : '.$this->subject_name,0,1,'C');    
                $this->Ln(2);
                break;
            case 'Student Wise Attendance Report':
                $this->SetFont('Times', 'B', 12);
                $this->Cell(0, 6, 'Student Wise Attendance Report', 0, 1, 'C');
                $this->SetFont('Times', '', 10);
                $this->Cell(0, 4, 'Degree : ' . $this->Degree_name, 0, 1, 'C');
                $this->Cell(0, 4, 'Exam : ' . $this->Exam, 0, 1, 'C');

                $this->Ln(2);
                break;


                //IA MARKS PENDING REPORT
            default:
                $this->Ln();
                break;
        }
    }

    function Footer()
    {
        //To be implemented in your own inherited class
        switch ($this->WhichReport) {
            case 'MARKS_SUBJECTWISE':
                $this->SetY(-20);

                $this->SetFont('Arial', 'I', 8);
                $this->Cell(0, 3, 'Absent On This Page : ' . $this->page_absent_count, '0', 1, 'C');
                $this->Cell(0, 3, '       Total Absent : ' . $this->total_absent_count, '0', 1, 'C');
                //$this->toatal_absent_count=0;
                break;
            case 'MARKS_STUDENTWISE':
                $this->SetY(-20);
                $this->SetFont('Arial', 'I', 8);
                //$this->Cell(0,3,'Absent On This Page : '.$this->page_absent_count,'0',1,'C');											
                break;
            case 'SUBJECT_ADCL':
                $this->SetY(-8);
                $this->SetFont('Arial', 'I', 8);
                $this->Cell(0, 3, 'Note : * Mandatory Subjects', '0', 1, 'C');
                break;
            case 'SUBJECT_GENERAL':
                $this->SetY(-8);
                $this->SetFont('Arial', 'I', 8);
                $this->Cell(0, 3, 'Note : * Mandatory Subjects', '0', 1, 'C');
                break;

            case 'AppearListQpWise':
                $this->ip = $_SERVER["REMOTE_ADDR"];
                $this->SetY(-8);
                $this->SetFont('Arial', '', 8);
                $this->Cell(140, 6, 'Printed   : IP Address : ' . $this->ip . " Date " . $this->date_1, '0', 0, 'L');
                break;
            case 'roomallotmentsummary':
                $this->ip = $_SERVER["REMOTE_ADDR"];
                $this->SetY(-8);
                $this->SetFont('Arial', 'I', 8);
                $this->Cell(140, 6, 'Printed   : IP Address : ' . $this->ip . " Date " . $this->date_1, '0', 0, 'L');
                break;

            case 'Attendance Summary Report':
                $this->ip = $_SERVER["REMOTE_ADDR"];
                $this->SetY(-8);
                $this->SetFont('Arial', 'I', 8);
                $this->Cell(140, 6, 'Printed   : IP Address : ' . $this->ip . " Date " . $this->date_1, '0', 0, 'L');
                break;
            case 'Attendance Shortage Report':
                $this->ip = $_SERVER["REMOTE_ADDR"];
                $this->SetY(-8);
                $this->SetFont('Arial', 'I', 8);
                $this->Cell(140, 6, 'Printed   : IP Address : ' . $this->ip . " Date " . $this->date_1, '0', 0, 'L');
                break;
            case 'iamarks_pending':
                $this->ip = $_SERVER["REMOTE_ADDR"];
                $this->SetY(-8);
                $this->SetFont('Arial', 'I', 8);
                $this->Cell(140, 6, 'Printed   : IP Address : ' . $this->ip . " Date " . $this->date_1, '0', 0, 'L');
                break;

            case 'Student Wise Attendance Report':
                $this->ip = $_SERVER["REMOTE_ADDR"];
                $this->SetY(-13);
                $this->SetFont('Arial', 'I', 8);
                $this->Cell(0, 6, "Note : Att. : Class Attended , Con. : Class Conducted ", '0', 0, 'L');
                $this->Cell(0, 6, 'Printed   : IP Address : ' . $this->ip . "   Date " . $this->date_1, '0', 1, 'R');
                break;
        }
    }

    function PageNo()
    {
        //Get current page number
        return $this->page;
    }

    function SetDrawColor($r, $g = null, $b = null)
    {
        //Set color for all stroking operations
        if (($r == 0 && $g == 0 && $b == 0) || $g === null)
            $this->DrawColor = sprintf('%.3F G', $r / 255);
        else
            $this->DrawColor = sprintf('%.3F %.3F %.3F RG', $r / 255, $g / 255, $b / 255);
        if ($this->page > 0)
            $this->_out($this->DrawColor);
    }

    function SetFillColor($r, $g = null, $b = null)
    {
        //Set color for all filling operations
        if (($r == 0 && $g == 0 && $b == 0) || $g === null)
            $this->FillColor = sprintf('%.3F g', $r / 255);
        else
            $this->FillColor = sprintf('%.3F %.3F %.3F rg', $r / 255, $g / 255, $b / 255);
        $this->ColorFlag = ($this->FillColor != $this->TextColor);
        if ($this->page > 0)
            $this->_out($this->FillColor);
    }

    function SetTextColor($r, $g = null, $b = null)
    {
        //Set color for text
        if (($r == 0 && $g == 0 && $b == 0) || $g === null)
            $this->TextColor = sprintf('%.3F g', $r / 255);
        else
            $this->TextColor = sprintf('%.3F %.3F %.3F rg', $r / 255, $g / 255, $b / 255);
        $this->ColorFlag = ($this->FillColor != $this->TextColor);
    }

    function GetStringWidth($s)
    {
        //Get width of a string in the current font
        $s = (string)$s;
        $cw = &$this->CurrentFont['cw'];
        $w = 0;
        $l = strlen($s);
        for ($i = 0; $i < $l; $i++)
            $w += $cw[$s[$i]];
        return $w * $this->FontSize / 1000;
    }

    function SetLineWidth($width)
    {
        //Set line width
        $this->LineWidth = $width;
        if ($this->page > 0)
            $this->_out(sprintf('%.2F w', $width * $this->k));
    }

    function Line($x1, $y1, $x2, $y2)
    {
        //Draw a line
        $this->_out(sprintf('%.2F %.2F m %.2F %.2F l S', $x1 * $this->k, ($this->h - $y1) * $this->k, $x2 * $this->k, ($this->h - $y2) * $this->k));
    }

    function Rect($x, $y, $w, $h, $style = '')
    {
        //Draw a rectangle
        if ($style == 'F')
            $op = 'f';
        elseif ($style == 'FD' || $style == 'DF')
            $op = 'B';
        else
            $op = 'S';
        $this->_out(sprintf('%.2F %.2F %.2F %.2F re %s', $x * $this->k, ($this->h - $y) * $this->k, $w * $this->k, -$h * $this->k, $op));
    }

    function AddFont($family, $style = '', $file = '')
    {
        //Add a TrueType or Type1 font
        $family = strtolower($family);
        if ($file == '')
            $file = str_replace(' ', '', $family) . strtolower($style) . '.php';
        if ($family == 'arial')
            $family = 'helvetica';
        $style = strtoupper($style);
        if ($style == 'IB')
            $style = 'BI';
        $fontkey = $family . $style;
        if (isset($this->fonts[$fontkey]))
            return;
        include($this->_getfontpath() . $file);
        if (!isset($name))
            $this->Error('Could not include font definition file');
        $i = count($this->fonts) + 1;
        $this->fonts[$fontkey] = array('i' => $i, 'type' => $type, 'name' => $name, 'desc' => $desc, 'up' => $up, 'ut' => $ut, 'cw' => $cw, 'enc' => $enc, 'file' => $file);
        if ($diff) {
            //Search existing encodings
            $d = 0;
            $nb = count($this->diffs);
            for ($i = 1; $i <= $nb; $i++) {
                if ($this->diffs[$i] == $diff) {
                    $d = $i;
                    break;
                }
            }
            if ($d == 0) {
                $d = $nb + 1;
                $this->diffs[$d] = $diff;
            }
            $this->fonts[$fontkey]['diff'] = $d;
        }
        if ($file) {
            if ($type == 'TrueType')
                $this->FontFiles[$file] = array('length1' => $originalsize);
            else
                $this->FontFiles[$file] = array('length1' => $size1, 'length2' => $size2);
        }
    }

    function SetFont($family, $style = '', $size = 0)
    {
        //Select a font; size given in points
        global $fpdf_charwidths;

        $family = strtolower($family);
        if ($family == '')
            $family = $this->FontFamily;
        if ($family == 'arial')
            $family = 'helvetica';
        elseif ($family == 'symbol' || $family == 'zapfdingbats')
            $style = '';
        $style = strtoupper($style);
        if (strpos($style, 'U') !== false) {
            $this->underline = true;
            $style = str_replace('U', '', $style);
        } else
            $this->underline = false;
        if ($style == 'IB')
            $style = 'BI';
        if ($size == 0)
            $size = $this->FontSizePt;
        //Test if font is already selected
        if ($this->FontFamily == $family && $this->FontStyle == $style && $this->FontSizePt == $size)
            return;
        //Test if used for the first time
        $fontkey = $family . $style;
        if (!isset($this->fonts[$fontkey])) {
            //Check if one of the standard fonts
            if (isset($this->CoreFonts[$fontkey])) {
                if (!isset($fpdf_charwidths[$fontkey])) {
                    //Load metric file
                    $file = $family;
                    if ($family == 'times' || $family == 'helvetica')
                        $file .= strtolower($style);
                    include($this->_getfontpath() . $file . '.php');
                    if (!isset($fpdf_charwidths[$fontkey]))
                        $this->Error('Could not include font metric file');
                }
                $i = count($this->fonts) + 1;
                $name = $this->CoreFonts[$fontkey];
                $cw = $fpdf_charwidths[$fontkey];
                $this->fonts[$fontkey] = array('i' => $i, 'type' => 'core', 'name' => $name, 'up' => -100, 'ut' => 50, 'cw' => $cw);
            } else
                $this->Error('Undefined font: ' . $family . ' ' . $style);
        }
        //Select it
        $this->FontFamily = $family;
        $this->FontStyle = $style;
        $this->FontSizePt = $size;
        $this->FontSize = $size / $this->k;
        $this->CurrentFont = &$this->fonts[$fontkey];
        if ($this->page > 0)
            $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
    }

    function SetFontSize($size)
    {
        //Set font size in points
        if ($this->FontSizePt == $size)
            return;
        $this->FontSizePt = $size;
        $this->FontSize = $size / $this->k;
        if ($this->page > 0)
            $this->_out(sprintf('BT /F%d %.2F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
    }

    function AddLink()
    {
        //Create a new internal link
        $n = count($this->links) + 1;
        $this->links[$n] = array(0, 0);
        return $n;
    }

    function SetLink($link, $y = 0, $page = -1)
    {
        //Set destination of internal link
        if ($y == -1)
            $y = $this->y;
        if ($page == -1)
            $page = $this->page;
        $this->links[$link] = array($page, $y);
    }

    function Link($x, $y, $w, $h, $link)
    {
        //Put a link on the page
        $this->PageLinks[$this->page][] = array($x * $this->k, $this->hPt - $y * $this->k, $w * $this->k, $h * $this->k, $link);
    }

    function Text($x, $y, $txt)
    {
        //Output a string
        $s = sprintf('BT %.2F %.2F Td (%s) Tj ET', $x * $this->k, ($this->h - $y) * $this->k, $this->_escape($txt));
        if ($this->underline && $txt != '')
            $s .= ' ' . $this->_dounderline($x, $y, $txt);
        if ($this->ColorFlag)
            $s = 'q ' . $this->TextColor . ' ' . $s . ' Q';
        $this->_out($s);
    }

    function AcceptPageBreak()
    {
        /* if($this->col<8)
    {
        //Go to next column
        $this->SetCol($this->col+1);
        $this->SetY(10);
        return false;
    }
    else
    {
        //Go back to first column and issue page break
        $this->SetCol(0);
        return true;
    }	 */

        //Accept automatic page break or not
        return $this->AutoPageBreak;
    }

    function Cell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = false, $link = '')
    {
        //Output a cell
        $k = $this->k;
        if ($this->y + $h > $this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak()) {
            //Automatic page break
            $x = $this->x;
            $ws = $this->ws;
            if ($ws > 0) {
                $this->ws = 0;
                $this->_out('0 Tw');
            }
            $this->AddPage($this->CurOrientation, $this->CurPageFormat);
            $this->x = $x;
            if ($ws > 0) {
                $this->ws = $ws;
                $this->_out(sprintf('%.3F Tw', $ws * $k));
            }
        }
        if ($w == 0)
            $w = $this->w - $this->rMargin - $this->x;
        $s = '';
        if ($fill || $border == 1) {
            if ($fill)
                $op = ($border == 1) ? 'B' : 'f';
            else
                $op = 'S';
            $s = sprintf('%.2F %.2F %.2F %.2F re %s ', $this->x * $k, ($this->h - $this->y) * $k, $w * $k, -$h * $k, $op);
        }
        if (is_string($border)) {
            $x = $this->x;
            $y = $this->y;
            if (strpos($border, 'L') !== false)
                $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x * $k, ($this->h - $y) * $k, $x * $k, ($this->h - ($y + $h)) * $k);
            if (strpos($border, 'T') !== false)
                $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - $y) * $k);
            if (strpos($border, 'R') !== false)
                $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', ($x + $w) * $k, ($this->h - $y) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k);
            if (strpos($border, 'B') !== false)
                $s .= sprintf('%.2F %.2F m %.2F %.2F l S ', $x * $k, ($this->h - ($y + $h)) * $k, ($x + $w) * $k, ($this->h - ($y + $h)) * $k);
        }
        if ($txt !== '') {
            if ($align == 'R')
                $dx = $w - $this->cMargin - $this->GetStringWidth($txt);
            elseif ($align == 'C')
                $dx = ($w - $this->GetStringWidth($txt)) / 2;
            else
                $dx = $this->cMargin;
            if ($this->ColorFlag)
                $s .= 'q ' . $this->TextColor . ' ';
            $txt2 = str_replace(')', '\\)', str_replace('(', '\\(', str_replace('\\', '\\\\', $txt)));
            $s .= sprintf('BT %.2F %.2F Td (%s) Tj ET', ($this->x + $dx) * $k, ($this->h - ($this->y + .5 * $h + .3 * $this->FontSize)) * $k, $txt2);
            if ($this->underline)
                $s .= ' ' . $this->_dounderline($this->x + $dx, $this->y + .5 * $h + .3 * $this->FontSize, $txt);
            if ($this->ColorFlag)
                $s .= ' Q';
            if ($link)
                $this->Link($this->x + $dx, $this->y + .5 * $h - .5 * $this->FontSize, $this->GetStringWidth($txt), $this->FontSize, $link);
        }
        if ($s)
            $this->_out($s);
        $this->lasth = $h;
        if ($ln > 0) {
            //Go to next line
            $this->y += $h;
            if ($ln == 1)
                $this->x = $this->lMargin;
        } else
            $this->x += $w;
    }

    function MultiCell($w, $h, $txt, $border = 0, $align = 'J', $fill = false)
    {
        //Output text with automatic or explicit line breaks
        $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 && $s[$nb - 1] == "\n")
            $nb--;
        $b = 0;
        if ($border) {
            if ($border == 1) {
                $border = 'LTRB';
                $b = 'LRT';
                $b2 = 'LR';
            } else {
                $b2 = '';
                if (strpos($border, 'L') !== false)
                    $b2 .= 'L';
                if (strpos($border, 'R') !== false)
                    $b2 .= 'R';
                $b = (strpos($border, 'T') !== false) ? $b2 . 'T' : $b2;
            }
        }
        $sep = -1;
        $i = 0;
        $j = 0;
        $l = 0;
        $ns = 0;
        $nl = 1;
        while ($i < $nb) {
            //Get next character
            $c = $s[$i];
            if ($c == "\n") {
                //Explicit line break
                if ($this->ws > 0) {
                    $this->ws = 0;
                    $this->_out('0 Tw');
                }
                $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);
                $i++;
                $sep = -1;
                $j = $i;
                $l = 0;
                $ns = 0;
                $nl++;
                if ($border && $nl == 2)
                    $b = $b2;
                continue;
            }
            if ($c == ' ') {
                $sep = $i;
                $ls = $l;
                $ns++;
            }
            $l += $cw[$c];
            if ($l > $wmax) {
                //Automatic line break
                if ($sep == -1) {
                    if ($i == $j)
                        $i++;
                    if ($this->ws > 0) {
                        $this->ws = 0;
                        $this->_out('0 Tw');
                    }
                    $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);
                } else {
                    if ($align == 'J') {
                        $this->ws = ($ns > 1) ? ($wmax - $ls) / 1000 * $this->FontSize / ($ns - 1) : 0;
                        $this->_out(sprintf('%.3F Tw', $this->ws * $this->k));
                    }
                    $this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill);
                    $i = $sep + 1;
                }
                $sep = -1;
                $j = $i;
                $l = 0;
                $ns = 0;
                $nl++;
                if ($border && $nl == 2)
                    $b = $b2;
            } else
                $i++;
        }
        //Last chunk
        if ($this->ws > 0) {
            $this->ws = 0;
            $this->_out('0 Tw');
        }
        if ($border && strpos($border, 'B') !== false)
            $b .= 'B';
        $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);
        $this->x = $this->lMargin;
    }

    function Write($h, $txt, $link = '')
    {
        //Output text in flowing mode
        $cw = &$this->CurrentFont['cw'];
        $w = $this->w - $this->rMargin - $this->x;
        $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
        $s = str_replace("\r", '', $txt);
        $nb = strlen($s);
        $sep = -1;
        $i = 0;
        $j = 0;
        $l = 0;
        $nl = 1;
        while ($i < $nb) {
            //Get next character
            $c = $s[$i];
            if ($c == "\n") {
                //Explicit line break
                $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', 0, $link);
                $i++;
                $sep = -1;
                $j = $i;
                $l = 0;
                if ($nl == 1) {
                    $this->x = $this->lMargin;
                    $w = $this->w - $this->rMargin - $this->x;
                    $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
                }
                $nl++;
                continue;
            }
            if ($c == ' ')
                $sep = $i;
            $l += $cw[$c];
            if ($l > $wmax) {
                //Automatic line break
                if ($sep == -1) {
                    if ($this->x > $this->lMargin) {
                        //Move to next line
                        $this->x = $this->lMargin;
                        $this->y += $h;
                        $w = $this->w - $this->rMargin - $this->x;
                        $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
                        $i++;
                        $nl++;
                        continue;
                    }
                    if ($i == $j)
                        $i++;
                    $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', 0, $link);
                } else {
                    $this->Cell($w, $h, substr($s, $j, $sep - $j), 0, 2, '', 0, $link);
                    $i = $sep + 1;
                }
                $sep = -1;
                $j = $i;
                $l = 0;
                if ($nl == 1) {
                    $this->x = $this->lMargin;
                    $w = $this->w - $this->rMargin - $this->x;
                    $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
                }
                $nl++;
            } else
                $i++;
        }
        //Last chunk
        if ($i != $j)
            $this->Cell($l / 1000 * $this->FontSize, $h, substr($s, $j), 0, 0, '', 0, $link);
    }

    function Ln($h = null)
    {
        //Line feed; default value is last cell height
        $this->x = $this->lMargin;
        if ($h === null)
            $this->y += $this->lasth;
        else
            $this->y += $h;
    }

    function Image($file, $x = null, $y = null, $w = 0, $h = 0, $type = '', $link = '')
    {
        //Put an image on the page
        if (!isset($this->images[$file])) {
            //First use of this image, get info
            if ($type == '') {
                $pos = strrpos($file, '.');
                if (!$pos)
                    $this->Error('Image file has no extension and no type was specified: ' . $file);
                $type = substr($file, $pos + 1);
            }
            $type = strtolower($type);
            if ($type == 'jpeg')
                $type = 'jpg';
            $mtd = '_parse' . $type;
            if (!method_exists($this, $mtd))
                $this->Error('Unsupported image type: ' . $type);
            $info = $this->$mtd($file);
            $info['i'] = count($this->images) + 1;
            $this->images[$file] = $info;
        } else
            $info = $this->images[$file];
        //Automatic width and height calculation if needed
        if ($w == 0 && $h == 0) {
            //Put image at 72 dpi
            $w = $info['w'] / $this->k;
            $h = $info['h'] / $this->k;
        } elseif ($w == 0)
            $w = $h * $info['w'] / $info['h'];
        elseif ($h == 0)
            $h = $w * $info['h'] / $info['w'];
        //Flowing mode
        if ($y === null) {
            if ($this->y + $h > $this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak()) {
                //Automatic page break
                $x2 = $this->x;
                $this->AddPage($this->CurOrientation, $this->CurPageFormat);
                $this->x = $x2;
            }
            $y = $this->y;
            $this->y += $h;
        }
        if ($x === null)
            $x = $this->x;
        $this->_out(sprintf('q %.2F 0 0 %.2F %.2F %.2F cm /I%d Do Q', $w * $this->k, $h * $this->k, $x * $this->k, ($this->h - ($y + $h)) * $this->k, $info['i']));
        if ($link)
            $this->Link($x, $y, $w, $h, $link);
    }

    function GetX()
    {
        //Get x position
        return $this->x;
    }

    function SetX($x)
    {
        //Set x position
        if ($x >= 0)
            $this->x = $x;
        else
            $this->x = $this->w + $x;
    }

    function GetY()
    {
        //Get y position
        return $this->y;
    }

    function SetY($y)
    {
        //Set y position and reset x
        $this->x = $this->lMargin;
        if ($y >= 0)
            $this->y = $y;
        else
            $this->y = $this->h + $y;
    }

    function SetXY($x, $y)
    {
        //Set x and y positions
        $this->SetY($y);
        $this->SetX($x);
    }

    function Output($name = '', $dest = '')
    {
        //Output PDF to some destination
        if ($this->state < 3)
            $this->Close();
        $dest = strtoupper($dest);
        if ($dest == '') {
            if ($name == '') {
                $name = 'doc.pdf';
                $dest = 'I';
            } else
                $dest = 'F';
        }
        switch ($dest) {
            case 'I':
                //Send to standard output
                if (ob_get_length())
                    $this->Error('Some data has already been output, can\'t send PDF file');
                if (php_sapi_name() != 'cli') {
                    //We send to a browser
                    header('Content-Type: application/pdf');
                    if (headers_sent())
                        $this->Error('Some data has already been output, can\'t send PDF file');
                    header('Content-Length: ' . strlen($this->buffer));
                    header('Content-Disposition: inline; filename="' . $name . '"');
                    header('Cache-Control: private, max-age=0, must-revalidate');
                    header('Pragma: public');
                    ini_set('zlib.output_compression', '0');
                }
                echo $this->buffer;
                break;
            case 'D':
                //Download file
                if (ob_get_length())
                    $this->Error('Some data has already been output, can\'t send PDF file');
                header('Content-Type: application/x-download');
                if (headers_sent())
                    $this->Error('Some data has already been output, can\'t send PDF file');
                header('Content-Length: ' . strlen($this->buffer));
                header('Content-Disposition: attachment; filename="' . $name . '"');
                header('Cache-Control: private, max-age=0, must-revalidate');
                header('Pragma: public');
                ini_set('zlib.output_compression', '0');
                echo $this->buffer;
                break;
            case 'F':
                //Save to local file
                $f = fopen($name, 'wb');
                if (!$f)
                    $this->Error('Unable to create output file: ' . $name);
                fwrite($f, $this->buffer, strlen($this->buffer));
                fclose($f);
                break;
            case 'S':
                //Return as a string
                return $this->buffer;
            default:
                $this->Error('Incorrect output destination: ' . $dest);
        }
        return '';
    }

    /*******************************************************************************
     *                                                                              *
     *                              Protected methods                               *
     *                                                                              *
     *******************************************************************************/
    function _dochecks()
    {
        //Check availability of %F
        if (sprintf('%.1F', 1.0) != '1.0')
            $this->Error('This version of PHP is not supported');
        //Check mbstring overloading
        if (ini_get('mbstring.func_overload') & 2)
            $this->Error('mbstring overloading must be disabled');
        //Disable runtime magic quotes
        if (get_magic_quotes_runtime())
            @set_magic_quotes_runtime(0);
    }

    function _getpageformat($format)
    {
        $format = strtolower($format);
        if (!isset($this->PageFormats[$format]))
            $this->Error('Unknown page format: ' . $format);
        $a = $this->PageFormats[$format];
        return array($a[0] / $this->k, $a[1] / $this->k);
    }

    function _getfontpath()
    {
        if (!defined('FPDF_FONTPATH') && is_dir(dirname(__FILE__) . '/font'))
            define('FPDF_FONTPATH', dirname(__FILE__) . '/font/');
        return defined('FPDF_FONTPATH') ? FPDF_FONTPATH : '';
    }

    function _beginpage($orientation, $format)
    {
        $this->page++;
        $this->pages[$this->page] = '';
        $this->state = 2;
        $this->x = $this->lMargin;
        $this->y = $this->tMargin;
        $this->FontFamily = '';
        //Check page size
        if ($orientation == '')
            $orientation = $this->DefOrientation;
        else
            $orientation = strtoupper($orientation[0]);
        if ($format == '')
            $format = $this->DefPageFormat;
        else {
            if (is_string($format))
                $format = $this->_getpageformat($format);
        }
        if ($orientation != $this->CurOrientation || $format[0] != $this->CurPageFormat[0] || $format[1] != $this->CurPageFormat[1]) {
            //New size
            if ($orientation == 'P') {
                $this->w = $format[0];
                $this->h = $format[1];
            } else {
                $this->w = $format[1];
                $this->h = $format[0];
            }
            $this->wPt = $this->w * $this->k;
            $this->hPt = $this->h * $this->k;
            $this->PageBreakTrigger = $this->h - $this->bMargin;
            $this->CurOrientation = $orientation;
            $this->CurPageFormat = $format;
        }
        if ($orientation != $this->DefOrientation || $format[0] != $this->DefPageFormat[0] || $format[1] != $this->DefPageFormat[1])
            $this->PageSizes[$this->page] = array($this->wPt, $this->hPt);
    }

    function _endpage()
    {
        $this->state = 1;
    }

    function _escape($s)
    {
        //Escape special characters in strings
        $s = str_replace('\\', '\\\\', $s);
        $s = str_replace('(', '\\(', $s);
        $s = str_replace(')', '\\)', $s);
        $s = str_replace("\r", '\\r', $s);
        return $s;
    }

    function _textstring($s)
    {
        //Format a text string
        return '(' . $this->_escape($s) . ')';
    }

    function _UTF8toUTF16($s)
    {
        //Convert UTF-8 to UTF-16BE with BOM
        $res = "\xFE\xFF";
        $nb = strlen($s);
        $i = 0;
        while ($i < $nb) {
            $c1 = ord($s[$i++]);
            if ($c1 >= 224) {
                //3-byte character
                $c2 = ord($s[$i++]);
                $c3 = ord($s[$i++]);
                $res .= chr((($c1 & 0x0F) << 4) + (($c2 & 0x3C) >> 2));
                $res .= chr((($c2 & 0x03) << 6) + ($c3 & 0x3F));
            } elseif ($c1 >= 192) {
                //2-byte character
                $c2 = ord($s[$i++]);
                $res .= chr(($c1 & 0x1C) >> 2);
                $res .= chr((($c1 & 0x03) << 6) + ($c2 & 0x3F));
            } else {
                //Single-byte character
                $res .= "\0" . chr($c1);
            }
        }
        return $res;
    }

    function _dounderline($x, $y, $txt)
    {
        //Underline text
        $up = $this->CurrentFont['up'];
        $ut = $this->CurrentFont['ut'];
        $w = $this->GetStringWidth($txt) + $this->ws * substr_count($txt, ' ');
        return sprintf('%.2F %.2F %.2F %.2F re f', $x * $this->k, ($this->h - ($y - $up / 1000 * $this->FontSize)) * $this->k, $w * $this->k, -$ut / 1000 * $this->FontSizePt);
    }

    function _parsejpg($file)
    {
        //Extract info from a JPEG file
        $a = GetImageSize($file);
        if (!$a)
            $this->Error('Missing or incorrect image file: ' . $file);
        if ($a[2] != 2)
            $this->Error('Not a JPEG file: ' . $file);
        if (!isset($a['channels']) || $a['channels'] == 3)
            $colspace = 'DeviceRGB';
        elseif ($a['channels'] == 4)
            $colspace = 'DeviceCMYK';
        else
            $colspace = 'DeviceGray';
        $bpc = isset($a['bits']) ? $a['bits'] : 8;
        //Read whole file
        $f = fopen($file, 'rb');
        $data = '';
        while (!feof($f))
            $data .= fread($f, 8192);
        fclose($f);
        return array('w' => $a[0], 'h' => $a[1], 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'DCTDecode', 'data' => $data);
    }

    function _parsepng($file)
    {
        //Extract info from a PNG file
        $f = fopen($file, 'rb');
        if (!$f)
            $this->Error('Can\'t open image file: ' . $file);
        //Check signature
        if ($this->_readstream($f, 8) != chr(137) . 'PNG' . chr(13) . chr(10) . chr(26) . chr(10))
            $this->Error('Not a PNG file: ' . $file);
        //Read header chunk
        $this->_readstream($f, 4);
        if ($this->_readstream($f, 4) != 'IHDR')
            $this->Error('Incorrect PNG file: ' . $file);
        $w = $this->_readint($f);
        $h = $this->_readint($f);
        $bpc = ord($this->_readstream($f, 1));
        if ($bpc > 8)
            $this->Error('16-bit depth not supported: ' . $file);
        $ct = ord($this->_readstream($f, 1));
        if ($ct == 0)
            $colspace = 'DeviceGray';
        elseif ($ct == 2)
            $colspace = 'DeviceRGB';
        elseif ($ct == 3)
            $colspace = 'Indexed';
        else
            $this->Error('Alpha channel not supported: ' . $file);
        if (ord($this->_readstream($f, 1)) != 0)
            $this->Error('Unknown compression method: ' . $file);
        if (ord($this->_readstream($f, 1)) != 0)
            $this->Error('Unknown filter method: ' . $file);
        if (ord($this->_readstream($f, 1)) != 0)
            $this->Error('Interlacing not supported: ' . $file);
        $this->_readstream($f, 4);
        $parms = '/DecodeParms <</Predictor 15 /Colors ' . ($ct == 2 ? 3 : 1) . ' /BitsPerComponent ' . $bpc . ' /Columns ' . $w . '>>';
        //Scan chunks looking for palette, transparency and image data
        $pal = '';
        $trns = '';
        $data = '';
        do {
            $n = $this->_readint($f);
            $type = $this->_readstream($f, 4);
            if ($type == 'PLTE') {
                //Read palette
                $pal = $this->_readstream($f, $n);
                $this->_readstream($f, 4);
            } elseif ($type == 'tRNS') {
                //Read transparency info
                $t = $this->_readstream($f, $n);
                if ($ct == 0)
                    $trns = array(ord(substr($t, 1, 1)));
                elseif ($ct == 2)
                    $trns = array(ord(substr($t, 1, 1)), ord(substr($t, 3, 1)), ord(substr($t, 5, 1)));
                else {
                    $pos = strpos($t, chr(0));
                    if ($pos !== false)
                        $trns = array($pos);
                }
                $this->_readstream($f, 4);
            } elseif ($type == 'IDAT') {
                //Read image data block
                $data .= $this->_readstream($f, $n);
                $this->_readstream($f, 4);
            } elseif ($type == 'IEND')
                break;
            else
                $this->_readstream($f, $n + 4);
        } while ($n);
        if ($colspace == 'Indexed' && empty($pal))
            $this->Error('Missing palette in ' . $file);
        fclose($f);
        return array('w' => $w, 'h' => $h, 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'FlateDecode', 'parms' => $parms, 'pal' => $pal, 'trns' => $trns, 'data' => $data);
    }

    function _readstream($f, $n)
    {
        //Read n bytes from stream
        $res = '';
        while ($n > 0 && !feof($f)) {
            $s = fread($f, $n);
            if ($s === false)
                $this->Error('Error while reading stream');
            $n -= strlen($s);
            $res .= $s;
        }
        if ($n > 0)
            $this->Error('Unexpected end of stream');
        return $res;
    }

    function _readint($f)
    {
        //Read a 4-byte integer from stream
        $a = unpack('Ni', $this->_readstream($f, 4));
        return $a['i'];
    }

    function _parsegif($file)
    {
        //Extract info from a GIF file (via PNG conversion)
        if (!function_exists('imagepng'))
            $this->Error('GD extension is required for GIF support');
        if (!function_exists('imagecreatefromgif'))
            $this->Error('GD has no GIF read support');
        $im = imagecreatefromgif($file);
        if (!$im)
            $this->Error('Missing or incorrect image file: ' . $file);
        imageinterlace($im, 0);
        $tmp = tempnam('.', 'gif');
        if (!$tmp)
            $this->Error('Unable to create a temporary file');
        if (!imagepng($im, $tmp))
            $this->Error('Error while saving to temporary file');
        imagedestroy($im);
        $info = $this->_parsepng($tmp);
        unlink($tmp);
        return $info;
    }

    function _newobj()
    {
        //Begin a new object
        $this->n++;
        $this->offsets[$this->n] = strlen($this->buffer);
        $this->_out($this->n . ' 0 obj');
    }

    function _putstream($s)
    {
        $this->_out('stream');
        $this->_out($s);
        $this->_out('endstream');
    }

    function _out($s)
    {
        //Add a line to the document
        if ($this->state == 2)
            $this->pages[$this->page] .= $s . "\n";
        else
            $this->buffer .= $s . "\n";
    }

    function _putpages()
    {
        $nb = $this->page;
        if (!empty($this->AliasNbPages)) {
            //Replace number of pages
            for ($n = 1; $n <= $nb; $n++)
                $this->pages[$n] = str_replace($this->AliasNbPages, $nb, $this->pages[$n]);
        }
        if ($this->DefOrientation == 'P') {
            $wPt = $this->DefPageFormat[0] * $this->k;
            $hPt = $this->DefPageFormat[1] * $this->k;
        } else {
            $wPt = $this->DefPageFormat[1] * $this->k;
            $hPt = $this->DefPageFormat[0] * $this->k;
        }
        $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
        for ($n = 1; $n <= $nb; $n++) {
            //Page
            $this->_newobj();
            $this->_out('<</Type /Page');
            $this->_out('/Parent 1 0 R');
            if (isset($this->PageSizes[$n]))
                $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]', $this->PageSizes[$n][0], $this->PageSizes[$n][1]));
            $this->_out('/Resources 2 0 R');
            if (isset($this->PageLinks[$n])) {
                //Links
                $annots = '/Annots [';
                foreach ($this->PageLinks[$n] as $pl) {
                    $rect = sprintf('%.2F %.2F %.2F %.2F', $pl[0], $pl[1], $pl[0] + $pl[2], $pl[1] - $pl[3]);
                    $annots .= '<</Type /Annot /Subtype /Link /Rect [' . $rect . '] /Border [0 0 0] ';
                    if (is_string($pl[4]))
                        $annots .= '/A <</S /URI /URI ' . $this->_textstring($pl[4]) . '>>>>';
                    else {
                        $l = $this->links[$pl[4]];
                        $h = isset($this->PageSizes[$l[0]]) ? $this->PageSizes[$l[0]][1] : $hPt;
                        $annots .= sprintf('/Dest [%d 0 R /XYZ 0 %.2F null]>>', 1 + 2 * $l[0], $h - $l[1] * $this->k);
                    }
                }
                $this->_out($annots . ']');
            }
            $this->_out('/Contents ' . ($this->n + 1) . ' 0 R>>');
            $this->_out('endobj');
            //Page content
            $p = ($this->compress) ? gzcompress($this->pages[$n]) : $this->pages[$n];
            $this->_newobj();
            $this->_out('<<' . $filter . '/Length ' . strlen($p) . '>>');
            $this->_putstream($p);
            $this->_out('endobj');
        }
        //Pages root
        $this->offsets[1] = strlen($this->buffer);
        $this->_out('1 0 obj');
        $this->_out('<</Type /Pages');
        $kids = '/Kids [';
        for ($i = 0; $i < $nb; $i++)
            $kids .= (3 + 2 * $i) . ' 0 R ';
        $this->_out($kids . ']');
        $this->_out('/Count ' . $nb);
        $this->_out(sprintf('/MediaBox [0 0 %.2F %.2F]', $wPt, $hPt));
        $this->_out('>>');
        $this->_out('endobj');
    }

    function _putfonts()
    {
        $nf = $this->n;
        foreach ($this->diffs as $diff) {
            //Encodings
            $this->_newobj();
            $this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [' . $diff . ']>>');
            $this->_out('endobj');
        }
        foreach ($this->FontFiles as $file => $info) {
            //Font file embedding
            $this->_newobj();
            $this->FontFiles[$file]['n'] = $this->n;
            $font = '';
            $f = fopen($this->_getfontpath() . $file, 'rb', 1);
            if (!$f)
                $this->Error('Font file not found');
            while (!feof($f))
                $font .= fread($f, 8192);
            fclose($f);
            $compressed = (substr($file, -2) == '.z');
            if (!$compressed && isset($info['length2'])) {
                $header = (ord($font[0]) == 128);
                if ($header) {
                    //Strip first binary header
                    $font = substr($font, 6);
                }
                if ($header && ord($font[$info['length1']]) == 128) {
                    //Strip second binary header
                    $font = substr($font, 0, $info['length1']) . substr($font, $info['length1'] + 6);
                }
            }
            $this->_out('<</Length ' . strlen($font));
            if ($compressed)
                $this->_out('/Filter /FlateDecode');
            $this->_out('/Length1 ' . $info['length1']);
            if (isset($info['length2']))
                $this->_out('/Length2 ' . $info['length2'] . ' /Length3 0');
            $this->_out('>>');
            $this->_putstream($font);
            $this->_out('endobj');
        }
        foreach ($this->fonts as $k => $font) {
            //Font objects
            $this->fonts[$k]['n'] = $this->n + 1;
            $type = $font['type'];
            $name = $font['name'];
            if ($type == 'core') {
                //Standard font
                $this->_newobj();
                $this->_out('<</Type /Font');
                $this->_out('/BaseFont /' . $name);
                $this->_out('/Subtype /Type1');
                if ($name != 'Symbol' && $name != 'ZapfDingbats')
                    $this->_out('/Encoding /WinAnsiEncoding');
                $this->_out('>>');
                $this->_out('endobj');
            } elseif ($type == 'Type1' || $type == 'TrueType') {
                //Additional Type1 or TrueType font
                $this->_newobj();
                $this->_out('<</Type /Font');
                $this->_out('/BaseFont /' . $name);
                $this->_out('/Subtype /' . $type);
                $this->_out('/FirstChar 32 /LastChar 255');
                $this->_out('/Widths ' . ($this->n + 1) . ' 0 R');
                $this->_out('/FontDescriptor ' . ($this->n + 2) . ' 0 R');
                if ($font['enc']) {
                    if (isset($font['diff']))
                        $this->_out('/Encoding ' . ($nf + $font['diff']) . ' 0 R');
                    else
                        $this->_out('/Encoding /WinAnsiEncoding');
                }
                $this->_out('>>');
                $this->_out('endobj');
                //Widths
                $this->_newobj();
                $cw = &$font['cw'];
                $s = '[';
                for ($i = 32; $i <= 255; $i++)
                    $s .= $cw[chr($i)] . ' ';
                $this->_out($s . ']');
                $this->_out('endobj');
                //Descriptor
                $this->_newobj();
                $s = '<</Type /FontDescriptor /FontName /' . $name;
                foreach ($font['desc'] as $k => $v)
                    $s .= ' /' . $k . ' ' . $v;
                $file = $font['file'];
                if ($file)
                    $s .= ' /FontFile' . ($type == 'Type1' ? '' : '2') . ' ' . $this->FontFiles[$file]['n'] . ' 0 R';
                $this->_out($s . '>>');
                $this->_out('endobj');
            } else {
                //Allow for additional types
                $mtd = '_put' . strtolower($type);
                if (!method_exists($this, $mtd))
                    $this->Error('Unsupported font type: ' . $type);
                $this->$mtd($font);
            }
        }
    }

    function _putimages()
    {
        $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
        reset($this->images);
        while (list($file, $info) = each($this->images)) {
            $this->_newobj();
            $this->images[$file]['n'] = $this->n;
            $this->_out('<</Type /XObject');
            $this->_out('/Subtype /Image');
            $this->_out('/Width ' . $info['w']);
            $this->_out('/Height ' . $info['h']);
            if ($info['cs'] == 'Indexed')
                $this->_out('/ColorSpace [/Indexed /DeviceRGB ' . (strlen($info['pal']) / 3 - 1) . ' ' . ($this->n + 1) . ' 0 R]');
            else {
                $this->_out('/ColorSpace /' . $info['cs']);
                if ($info['cs'] == 'DeviceCMYK')
                    $this->_out('/Decode [1 0 1 0 1 0 1 0]');
            }
            $this->_out('/BitsPerComponent ' . $info['bpc']);
            if (isset($info['f']))
                $this->_out('/Filter /' . $info['f']);
            if (isset($info['parms']))
                $this->_out($info['parms']);
            if (isset($info['trns']) && is_array($info['trns'])) {
                $trns = '';
                for ($i = 0; $i < count($info['trns']); $i++)
                    $trns .= $info['trns'][$i] . ' ' . $info['trns'][$i] . ' ';
                $this->_out('/Mask [' . $trns . ']');
            }
            $this->_out('/Length ' . strlen($info['data']) . '>>');
            $this->_putstream($info['data']);
            unset($this->images[$file]['data']);
            $this->_out('endobj');
            //Palette
            if ($info['cs'] == 'Indexed') {
                $this->_newobj();
                $pal = ($this->compress) ? gzcompress($info['pal']) : $info['pal'];
                $this->_out('<<' . $filter . '/Length ' . strlen($pal) . '>>');
                $this->_putstream($pal);
                $this->_out('endobj');
            }
        }
    }

    function _putxobjectdict()
    {
        foreach ($this->images as $image)
            $this->_out('/I' . $image['i'] . ' ' . $image['n'] . ' 0 R');
    }

    function _putresourcedict()
    {
        $this->_out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
        $this->_out('/Font <<');
        foreach ($this->fonts as $font)
            $this->_out('/F' . $font['i'] . ' ' . $font['n'] . ' 0 R');
        $this->_out('>>');
        $this->_out('/XObject <<');
        $this->_putxobjectdict();
        $this->_out('>>');
    }

    function _putresources()
    {
        $this->_putfonts();
        $this->_putimages();
        //Resource dictionary
        $this->offsets[2] = strlen($this->buffer);
        $this->_out('2 0 obj');
        $this->_out('<<');
        $this->_putresourcedict();
        $this->_out('>>');
        $this->_out('endobj');
    }

    function _putinfo()
    {
        $this->_out('/Producer ' . $this->_textstring('FPDF ' . FPDF_VERSION));
        if (!empty($this->title))
            $this->_out('/Title ' . $this->_textstring($this->title));
        if (!empty($this->subject))
            $this->_out('/Subject ' . $this->_textstring($this->subject));
        if (!empty($this->author))
            $this->_out('/Author ' . $this->_textstring($this->author));
        if (!empty($this->keywords))
            $this->_out('/Keywords ' . $this->_textstring($this->keywords));
        if (!empty($this->creator))
            $this->_out('/Creator ' . $this->_textstring($this->creator));
        $this->_out('/CreationDate ' . $this->_textstring('D:' . @date('YmdHis')));
    }

    function _putcatalog()
    {
        $this->_out('/Type /Catalog');
        $this->_out('/Pages 1 0 R');
        if ($this->ZoomMode == 'fullpage')
            $this->_out('/OpenAction [3 0 R /Fit]');
        elseif ($this->ZoomMode == 'fullwidth')
            $this->_out('/OpenAction [3 0 R /FitH null]');
        elseif ($this->ZoomMode == 'real')
            $this->_out('/OpenAction [3 0 R /XYZ null null 1]');
        elseif (!is_string($this->ZoomMode))
            $this->_out('/OpenAction [3 0 R /XYZ null null ' . ($this->ZoomMode / 100) . ']');
        if ($this->LayoutMode == 'single')
            $this->_out('/PageLayout /SinglePage');
        elseif ($this->LayoutMode == 'continuous')
            $this->_out('/PageLayout /OneColumn');
        elseif ($this->LayoutMode == 'two')
            $this->_out('/PageLayout /TwoColumnLeft');
    }

    function _putheader()
    {
        $this->_out('%PDF-' . $this->PDFVersion);
    }

    function _puttrailer()
    {
        $this->_out('/Size ' . ($this->n + 1));
        $this->_out('/Root ' . $this->n . ' 0 R');
        $this->_out('/Info ' . ($this->n - 1) . ' 0 R');
    }

    function _enddoc()
    {
        $this->_putheader();
        $this->_putpages();
        $this->_putresources();
        //Info
        $this->_newobj();
        $this->_out('<<');
        $this->_putinfo();
        $this->_out('>>');
        $this->_out('endobj');
        //Catalog
        $this->_newobj();
        $this->_out('<<');
        $this->_putcatalog();
        $this->_out('>>');
        $this->_out('endobj');
        //Cross-ref
        $o = strlen($this->buffer);
        $this->_out('xref');
        $this->_out('0 ' . ($this->n + 1));
        $this->_out('0000000000 65535 f ');
        for ($i = 1; $i <= $this->n; $i++)
            $this->_out(sprintf('%010d 00000 n ', $this->offsets[$i]));
        //Trailer
        $this->_out('trailer');
        $this->_out('<<');
        $this->_puttrailer();
        $this->_out('>>');
        $this->_out('startxref');
        $this->_out($o);
        $this->_out('%%EOF');
        $this->state = 3;
    }

    function SetDash($black = false, $white = false)
    {
        if ($black and $white)
            $s = sprintf('[%.3f %.3f] 0 d', $black * $this->k, $white * $this->k);
        else
            $s = '[] 0 d';
        $this->_out($s);
    }

    function writeHTMLCell($w, $h, $x, $y, $html = '', $border = 0, $ln = 0, $fill = false, $reseth = true, $align = '', $autopadding = true)
    {
        return $this->MultiCell($w, $h, $html, $border, $align, $fill, $ln, $x, $y, $reseth, 0, true, $autopadding, 0, 'T', false);
    }
    protected function getGraphicVars()
    {
        $grapvars = array(
            'FontFamily' => $this->FontFamily,
            'FontStyle' => $this->FontStyle,
            'FontSizePt' => $this->FontSizePt,
            'rMargin' => $this->rMargin,
            'lMargin' => $this->lMargin,
            'cell_padding' => $this->cell_padding,
            'cell_margin' => $this->cell_margin,
            'LineWidth' => $this->LineWidth,
            'linestyleWidth' => $this->linestyleWidth,
            'linestyleCap' => $this->linestyleCap,
            'linestyleJoin' => $this->linestyleJoin,
            'linestyleDash' => $this->linestyleDash,
            'textrendermode' => $this->textrendermode,
            'textstrokewidth' => $this->textstrokewidth,
            'DrawColor' => $this->DrawColor,
            'FillColor' => $this->FillColor,
            'TextColor' => $this->TextColor,
            'ColorFlag' => $this->ColorFlag,
            'bgcolor' => $this->bgcolor,
            'fgcolor' => $this->fgcolor,
            'htmlvspace' => $this->htmlvspace,
            'listindent' => $this->listindent,
            'listindentlevel' => $this->listindentlevel,
            'listnum' => $this->listnum,
            'listordered' => $this->listordered,
            'listcount' => $this->listcount,
            'lispacer' => $this->lispacer,
            'cell_height_ratio' => $this->cell_height_ratio,
            'font_stretching' => $this->font_stretching,
            'font_spacing' => $this->font_spacing,
            'alpha' => $this->alpha,
            // extended
            'lasth' => $this->lasth,
            'tMargin' => $this->tMargin,
            'bMargin' => $this->bMargin,
            'AutoPageBreak' => $this->AutoPageBreak,
            'PageBreakTrigger' => $this->PageBreakTrigger,
            'x' => $this->x,
            'y' => $this->y,
            'w' => $this->w,
            'h' => $this->h,
            'wPt' => $this->wPt,
            'hPt' => $this->hPt,
            'fwPt' => $this->fwPt,
            'fhPt' => $this->fhPt,
            'page' => $this->page,
            'current_column' => $this->current_column,
            'num_columns' => $this->num_columns
        );
        return $grapvars;
    }

    public function getFontAscent($font, $style = '', $size = 0)
    {
        $fontdata = $this->AddFont($font, $style);
        $fontinfo = $this->getFontBuffer($fontdata['fontkey']);
        if (isset($fontinfo['desc']['Ascent']) and ($fontinfo['desc']['Ascent'] > 0)) {
            $ascent = ($fontinfo['desc']['Ascent'] * $size / 1000);
        } else {
            $ascent = 1.219 * 0.76 * $size;
        }
        return ($ascent / $this->k);
    }
    protected function getFontBuffer($font)
    {
        if ($this->diskcache and isset($this->fonts[$font])) {
            return unserialize($this->readDiskCache($this->fonts[$font]));
        } elseif (isset($this->fonts[$font])) {
            return $this->fonts[$font];
        }
        return false;
    }
    public function getFontDescent($font, $style = '', $size = 0)
    {
        $fontdata = $this->AddFont($font, $style);
        $fontinfo = $this->getFontBuffer($fontdata['fontkey']);
        if (isset($fontinfo['desc']['Descent']) and ($fontinfo['desc']['Descent'] <= 0)) {
            $descent = (-$fontinfo['desc']['Descent'] * $size / 1000);
        } else {
            $descent = (1.219 * 0.24 * $size);
        }
        return ($descent / $this->k);
    }

    function writeHTML($html, $ln = true, $fill = false, $reseth = false, $cell = false, $align = '')
    {
        $gvars = $this->getGraphicVars();
        // store current values
        $prev_cell_margin = $this->cell_margin;
        $prev_cell_padding = $this->cell_padding;
        $prevPage = $this->page;
        $prevlMargin = $this->lMargin;
        $prevrMargin = $this->rMargin;
        $curfontname = $this->FontFamily;
        $curfontstyle = $this->FontStyle;
        $curfontsize = $this->FontSizePt;
        $curfontascent = $this->getFontAscent($curfontname, $curfontstyle, $curfontsize);
        $curfontdescent = $this->getFontDescent($curfontname, $curfontstyle, $curfontsize);
        $curfontstretcing = $this->font_stretching;
        $curfonttracking = $this->font_spacing;
        $this->newline = true;
        $newline = true;
        $startlinepage = $this->page;
        $minstartliney = $this->y;
        $maxbottomliney = 0;
        $startlinex = $this->x;
        $startliney = $this->y;
        $yshift = 0;
        $loop = 0;
        $curpos = 0;
        $this_method_vars = array();
        $undo = false;
        $fontaligned = false;
        $reverse_dir = false; // true when the text direction is reversed
        $this->premode = false;
        if ($this->inxobj) {
            // we are inside an XObject template
            $pask = count($this->xobjects[$this->xobjid]['annotations']);
        } elseif (isset($this->PageAnnots[$this->page])) {
            $pask = count($this->PageAnnots[$this->page]);
        } else {
            $pask = 0;
        }
        if ($this->inxobj) {
            // we are inside an XObject template
            $startlinepos = strlen($this->xobjects[$this->xobjid]['outdata']);
        } elseif (!$this->InFooter) {
            if (isset($this->footerlen[$this->page])) {
                $this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page];
            } else {
                $this->footerpos[$this->page] = $this->pagelen[$this->page];
            }
            $startlinepos = $this->footerpos[$this->page];
        } else {
            // we are inside the footer
            $startlinepos = $this->pagelen[$this->page];
        }
        $lalign = $align;
        $plalign = $align;
        if ($this->rtl) {
            $w = $this->x - $this->lMargin;
        } else {
            $w = $this->w - $this->rMargin - $this->x;
        }
        $w -= ($this->cell_padding['L'] + $this->cell_padding['R']);
        if ($cell) {
            if ($this->rtl) {
                $this->x -= $this->cell_padding['R'];
                $this->lMargin += $this->cell_padding['R'];
            } else {
                $this->x += $this->cell_padding['L'];
                $this->rMargin += $this->cell_padding['L'];
            }
        }
        if ($this->customlistindent >= 0) {
            $this->listindent = $this->customlistindent;
        } else {
            $this->listindent = $this->GetStringWidth('000000');
        }
        $this->listindentlevel = 0;
        // save previous states
        $prev_cell_height_ratio = $this->cell_height_ratio;
        $prev_listnum = $this->listnum;
        $prev_listordered = $this->listordered;
        $prev_listcount = $this->listcount;
        $prev_lispacer = $this->lispacer;
        $this->listnum = 0;
        $this->listordered = array();
        $this->listcount = array();
        $this->lispacer = '';
        if ((TCPDF_STATIC::empty_string($this->lasth)) or ($reseth)) {
            // reset row height
            $this->resetLastH();
        }
        $dom = $this->getHtmlDomArray($html);
        $maxel = count($dom);
        $key = 0;
        while ($key < $maxel) {
            if ($dom[$key]['tag'] and $dom[$key]['opening'] and $dom[$key]['hide']) {
                // store the node key
                $hidden_node_key = $key;
                if ($dom[$key]['self']) {
                    // skip just this self-closing tag
                    ++$key;
                } else {
                    // skip this and all children tags
                    while (($key < $maxel) and (!$dom[$key]['tag'] or $dom[$key]['opening'] or ($dom[$key]['parent'] != $hidden_node_key))) {
                        // skip hidden objects
                        ++$key;
                    }
                    ++$key;
                }
            }
            if ($dom[$key]['tag'] and isset($dom[$key]['attribute']['pagebreak'])) {
                // check for pagebreak
                if (($dom[$key]['attribute']['pagebreak'] == 'true') or ($dom[$key]['attribute']['pagebreak'] == 'left') or ($dom[$key]['attribute']['pagebreak'] == 'right')) {
                    // add a page (or trig AcceptPageBreak() for multicolumn mode)
                    $this->checkPageBreak($this->PageBreakTrigger + 1);
                    $this->htmlvspace = ($this->PageBreakTrigger + 1);
                }
                if ((($dom[$key]['attribute']['pagebreak'] == 'left') and (((!$this->rtl) and (($this->page % 2) == 0)) or (($this->rtl) and (($this->page % 2) != 0))))
                    or (($dom[$key]['attribute']['pagebreak'] == 'right') and (((!$this->rtl) and (($this->page % 2) != 0)) or (($this->rtl) and (($this->page % 2) == 0))))
                ) {
                    // add a page (or trig AcceptPageBreak() for multicolumn mode)
                    $this->checkPageBreak($this->PageBreakTrigger + 1);
                    $this->htmlvspace = ($this->PageBreakTrigger + 1);
                }
            }
            if ($dom[$key]['tag'] and $dom[$key]['opening'] and isset($dom[$key]['attribute']['nobr']) and ($dom[$key]['attribute']['nobr'] == 'true')) {
                if (isset($dom[($dom[$key]['parent'])]['attribute']['nobr']) and ($dom[($dom[$key]['parent'])]['attribute']['nobr'] == 'true')) {
                    $dom[$key]['attribute']['nobr'] = false;
                } else {
                    // store current object
                    $this->startTransaction();
                    // save this method vars
                    $this_method_vars['html'] = $html;
                    $this_method_vars['ln'] = $ln;
                    $this_method_vars['fill'] = $fill;
                    $this_method_vars['reseth'] = $reseth;
                    $this_method_vars['cell'] = $cell;
                    $this_method_vars['align'] = $align;
                    $this_method_vars['gvars'] = $gvars;
                    $this_method_vars['prevPage'] = $prevPage;
                    $this_method_vars['prev_cell_margin'] = $prev_cell_margin;
                    $this_method_vars['prev_cell_padding'] = $prev_cell_padding;
                    $this_method_vars['prevlMargin'] = $prevlMargin;
                    $this_method_vars['prevrMargin'] = $prevrMargin;
                    $this_method_vars['curfontname'] = $curfontname;
                    $this_method_vars['curfontstyle'] = $curfontstyle;
                    $this_method_vars['curfontsize'] = $curfontsize;
                    $this_method_vars['curfontascent'] = $curfontascent;
                    $this_method_vars['curfontdescent'] = $curfontdescent;
                    $this_method_vars['curfontstretcing'] = $curfontstretcing;
                    $this_method_vars['curfonttracking'] = $curfonttracking;
                    $this_method_vars['minstartliney'] = $minstartliney;
                    $this_method_vars['maxbottomliney'] = $maxbottomliney;
                    $this_method_vars['yshift'] = $yshift;
                    $this_method_vars['startlinepage'] = $startlinepage;
                    $this_method_vars['startlinepos'] = $startlinepos;
                    $this_method_vars['startlinex'] = $startlinex;
                    $this_method_vars['startliney'] = $startliney;
                    $this_method_vars['newline'] = $newline;
                    $this_method_vars['loop'] = $loop;
                    $this_method_vars['curpos'] = $curpos;
                    $this_method_vars['pask'] = $pask;
                    $this_method_vars['lalign'] = $lalign;
                    $this_method_vars['plalign'] = $plalign;
                    $this_method_vars['w'] = $w;
                    $this_method_vars['prev_cell_height_ratio'] = $prev_cell_height_ratio;
                    $this_method_vars['prev_listnum'] = $prev_listnum;
                    $this_method_vars['prev_listordered'] = $prev_listordered;
                    $this_method_vars['prev_listcount'] = $prev_listcount;
                    $this_method_vars['prev_lispacer'] = $prev_lispacer;
                    $this_method_vars['fontaligned'] = $fontaligned;
                    $this_method_vars['key'] = $key;
                    $this_method_vars['dom'] = $dom;
                }
            }
            // print THEAD block
            if (($dom[$key]['value'] == 'tr') and isset($dom[$key]['thead']) and $dom[$key]['thead']) {
                if (isset($dom[$key]['parent']) and isset($dom[$dom[$key]['parent']]['thead']) and !TCPDF_STATIC::empty_string($dom[$dom[$key]['parent']]['thead'])) {
                    $this->inthead = true;
                    // print table header (thead)
                    $this->writeHTML($this->thead, false, false, false, false, '');
                    // check if we are on a new page or on a new column
                    if (($this->y < $this->start_transaction_y) or ($this->checkPageBreak($this->lasth, '', false))) {
                        // we are on a new page or on a new column and the total object height is less than the available vertical space.
                        // restore previous object
                        $this->rollbackTransaction(true);
                        // restore previous values
                        foreach ($this_method_vars as $vkey => $vval) {
                            $$vkey = $vval;
                        }
                        // disable table header
                        $tmp_thead = $this->thead;
                        $this->thead = '';
                        // add a page (or trig AcceptPageBreak() for multicolumn mode)
                        $pre_y = $this->y;
                        if ((!$this->checkPageBreak($this->PageBreakTrigger + 1)) and ($this->y < $pre_y)) {
                            // fix for multicolumn mode
                            $startliney = $this->y;
                        }
                        $this->start_transaction_page = $this->page;
                        $this->start_transaction_y = $this->y;
                        // restore table header
                        $this->thead = $tmp_thead;
                        // fix table border properties
                        if (isset($dom[$dom[$key]['parent']]['attribute']['cellspacing'])) {
                            $tmp_cellspacing = $this->getHTMLUnitToUnits($dom[$dom[$key]['parent']]['attribute']['cellspacing'], 1, 'px');
                        } elseif (isset($dom[$dom[$key]['parent']]['border-spacing'])) {
                            $tmp_cellspacing = $dom[$dom[$key]['parent']]['border-spacing']['V'];
                        } else {
                            $tmp_cellspacing = 0;
                        }
                        $dom[$dom[$key]['parent']]['borderposition']['page'] = $this->page;
                        $dom[$dom[$key]['parent']]['borderposition']['column'] = $this->current_column;
                        $dom[$dom[$key]['parent']]['borderposition']['y'] = $this->y + $tmp_cellspacing;
                        $xoffset = ($this->x - $dom[$dom[$key]['parent']]['borderposition']['x']);
                        $dom[$dom[$key]['parent']]['borderposition']['x'] += $xoffset;
                        $dom[$dom[$key]['parent']]['borderposition']['xmax'] += $xoffset;
                        // print table header (thead)
                        $this->writeHTML($this->thead, false, false, false, false, '');
                    }
                }
                // move $key index forward to skip THEAD block
                while (($key < $maxel) and (!(
                    ($dom[$key]['tag'] and $dom[$key]['opening'] and ($dom[$key]['value'] == 'tr') and (!isset($dom[$key]['thead']) or !$dom[$key]['thead']))
                    or ($dom[$key]['tag'] and (!$dom[$key]['opening']) and ($dom[$key]['value'] == 'table'))))) {
                    ++$key;
                }
            }
            if ($dom[$key]['tag'] or ($key == 0)) {
                if ((($dom[$key]['value'] == 'table') or ($dom[$key]['value'] == 'tr')) and (isset($dom[$key]['align']))) {
                    $dom[$key]['align'] = ($this->rtl) ? 'R' : 'L';
                }
                // vertically align image in line
                if ((!$this->newline) and ($dom[$key]['value'] == 'img') and (isset($dom[$key]['height'])) and ($dom[$key]['height'] > 0)) {
                    // get image height
                    $imgh = $this->getHTMLUnitToUnits($dom[$key]['height'], $this->lasth, 'px');
                    $autolinebreak = false;
                    if (isset($dom[$key]['width']) and ($dom[$key]['width'] > 0)) {
                        $imgw = $this->getHTMLUnitToUnits($dom[$key]['width'], 1, 'px', false);
                        if (($imgw <= ($this->w - $this->lMargin - $this->rMargin - $this->cell_padding['L'] - $this->cell_padding['R']))
                            and ((($this->rtl) and (($this->x - $imgw) < ($this->lMargin + $this->cell_padding['L'])))
                                or ((!$this->rtl) and (($this->x + $imgw) > ($this->w - $this->rMargin - $this->cell_padding['R']))))
                        ) {
                            // add automatic line break
                            $autolinebreak = true;
                            $this->Ln('', $cell);
                            if ((!$dom[($key - 1)]['tag']) and ($dom[($key - 1)]['value'] == ' ')) {
                                // go back to evaluate this line break
                                --$key;
                            }
                        }
                    }
                    if (!$autolinebreak) {
                        if ($this->inPageBody()) {
                            $pre_y = $this->y;
                            // check for page break
                            if ((!$this->checkPageBreak($imgh)) and ($this->y < $pre_y)) {
                                // fix for multicolumn mode
                                $startliney = $this->y;
                            }
                        }
                        if ($this->page > $startlinepage) {
                            // fix line splitted over two pages
                            if (isset($this->footerlen[$startlinepage])) {
                                $curpos = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
                            }
                            // line to be moved one page forward
                            $pagebuff = $this->getPageBuffer($startlinepage);
                            $linebeg = substr($pagebuff, $startlinepos, ($curpos - $startlinepos));
                            $tstart = substr($pagebuff, 0, $startlinepos);
                            $tend = substr($this->getPageBuffer($startlinepage), $curpos);
                            // remove line from previous page
                            $this->setPageBuffer($startlinepage, $tstart . '' . $tend);
                            $pagebuff = $this->getPageBuffer($this->page);
                            $tstart = substr($pagebuff, 0, $this->cntmrk[$this->page]);
                            $tend = substr($pagebuff, $this->cntmrk[$this->page]);
                            // add line start to current page
                            $yshift = ($minstartliney - $this->y);
                            if ($fontaligned) {
                                $yshift += ($curfontsize / $this->k);
                            }
                            $try = sprintf('1 0 0 1 0 %F cm', ($yshift * $this->k));
                            $this->setPageBuffer($this->page, $tstart . "\nq\n" . $try . "\n" . $linebeg . "\nQ\n" . $tend);
                            // shift the annotations and links
                            if (isset($this->PageAnnots[$this->page])) {
                                $next_pask = count($this->PageAnnots[$this->page]);
                            } else {
                                $next_pask = 0;
                            }
                            if (isset($this->PageAnnots[$startlinepage])) {
                                foreach ($this->PageAnnots[$startlinepage] as $pak => $pac) {
                                    if ($pak >= $pask) {
                                        $this->PageAnnots[$this->page][] = $pac;
                                        unset($this->PageAnnots[$startlinepage][$pak]);
                                        $npak = count($this->PageAnnots[$this->page]) - 1;
                                        $this->PageAnnots[$this->page][$npak]['y'] -= $yshift;
                                    }
                                }
                            }
                            $pask = $next_pask;
                            $startlinepos = $this->cntmrk[$this->page];
                            $startlinepage = $this->page;
                            $startliney = $this->y;
                            $this->newline = false;
                        }
                        $this->y += (($this->getCellHeight($curfontsize / $this->k) + $curfontascent - $curfontdescent) / 2) - $imgh;
                        $minstartliney = min($this->y, $minstartliney);
                        $maxbottomliney = ($startliney + $this->getCellHeight($this->FontSize));
                    }
                } elseif (isset($dom[$key]['fontname']) or isset($dom[$key]['fontstyle']) or isset($dom[$key]['fontsize']) or isset($dom[$key]['line-height'])) {
                    // account for different font size
                    $pfontname = $curfontname;
                    $pfontstyle = $curfontstyle;
                    $pfontsize = $curfontsize;
                    $fontname = (isset($dom[$key]['fontname']) ? $dom[$key]['fontname'] : $curfontname);
                    $fontstyle = (isset($dom[$key]['fontstyle']) ? $dom[$key]['fontstyle'] : $curfontstyle);
                    $fontsize = (isset($dom[$key]['fontsize']) ? $dom[$key]['fontsize'] : $curfontsize);
                    $fontascent = $this->getFontAscent($fontname, $fontstyle, $fontsize);
                    $fontdescent = $this->getFontDescent($fontname, $fontstyle, $fontsize);
                    if (($fontname != $curfontname) or ($fontstyle != $curfontstyle) or ($fontsize != $curfontsize)
                        or ($this->cell_height_ratio != $dom[$key]['line-height'])
                        or ($dom[$key]['tag'] and $dom[$key]['opening'] and ($dom[$key]['value'] == 'li'))
                    ) {
                        if (($key < ($maxel - 1)) and (
                            ($dom[$key]['tag'] and $dom[$key]['opening'] and ($dom[$key]['value'] == 'li'))
                            or ($this->cell_height_ratio != $dom[$key]['line-height'])
                            or (!$this->newline and is_numeric($fontsize) and is_numeric($curfontsize) and ($fontsize >= 0) and ($curfontsize >= 0) and ($fontsize != $curfontsize)))) {
                            if ($this->page > $startlinepage) {
                                // fix lines splitted over two pages
                                if (isset($this->footerlen[$startlinepage])) {
                                    $curpos = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
                                }
                                // line to be moved one page forward
                                $pagebuff = $this->getPageBuffer($startlinepage);
                                $linebeg = substr($pagebuff, $startlinepos, ($curpos - $startlinepos));
                                $tstart = substr($pagebuff, 0, $startlinepos);
                                $tend = substr($this->getPageBuffer($startlinepage), $curpos);
                                // remove line start from previous page
                                $this->setPageBuffer($startlinepage, $tstart . '' . $tend);
                                $pagebuff = $this->getPageBuffer($this->page);
                                $tstart = substr($pagebuff, 0, $this->cntmrk[$this->page]);
                                $tend = substr($pagebuff, $this->cntmrk[$this->page]);
                                // add line start to current page
                                $yshift = ($minstartliney - $this->y);
                                $try = sprintf('1 0 0 1 0 %F cm', ($yshift * $this->k));
                                $this->setPageBuffer($this->page, $tstart . "\nq\n" . $try . "\n" . $linebeg . "\nQ\n" . $tend);
                                // shift the annotations and links
                                if (isset($this->PageAnnots[$this->page])) {
                                    $next_pask = count($this->PageAnnots[$this->page]);
                                } else {
                                    $next_pask = 0;
                                }
                                if (isset($this->PageAnnots[$startlinepage])) {
                                    foreach ($this->PageAnnots[$startlinepage] as $pak => $pac) {
                                        if ($pak >= $pask) {
                                            $this->PageAnnots[$this->page][] = $pac;
                                            unset($this->PageAnnots[$startlinepage][$pak]);
                                            $npak = count($this->PageAnnots[$this->page]) - 1;
                                            $this->PageAnnots[$this->page][$npak]['y'] -= $yshift;
                                        }
                                    }
                                }
                                $pask = $next_pask;
                                $startlinepos = $this->cntmrk[$this->page];
                                $startlinepage = $this->page;
                                $startliney = $this->y;
                            }
                            if (!isset($dom[$key]['line-height'])) {
                                $dom[$key]['line-height'] = $this->cell_height_ratio;
                            }
                            if (!$dom[$key]['block']) {
                                if (!(isset($dom[($key + 1)]) and $dom[($key + 1)]['tag'] and (!$dom[($key + 1)]['opening']) and ($dom[($key + 1)]['value'] != 'li') and $dom[$key]['tag'] and (!$dom[$key]['opening']))) {
                                    $this->y += (((($curfontsize * $this->cell_height_ratio) - ($fontsize * $dom[$key]['line-height'])) / $this->k) + $curfontascent - $fontascent - $curfontdescent + $fontdescent) / 2;
                                }
                                if (($dom[$key]['value'] != 'sup') and ($dom[$key]['value'] != 'sub')) {
                                    $current_line_align_data = array($key, $minstartliney, $maxbottomliney);
                                    if (isset($line_align_data) and (($line_align_data[0] == ($key - 1)) or (($line_align_data[0] == ($key - 2)) and (isset($dom[($key - 1)])) and (preg_match('/^([\s]+)$/', $dom[($key - 1)]['value']) > 0)))) {
                                        $minstartliney = min($this->y, $line_align_data[1]);
                                        $maxbottomliney = max(($this->y + $this->getCellHeight($fontsize / $this->k)), $line_align_data[2]);
                                    } else {
                                        $minstartliney = min($this->y, $minstartliney);
                                        $maxbottomliney = max(($this->y + $this->getCellHeight($fontsize / $this->k)), $maxbottomliney);
                                    }
                                    $line_align_data = $current_line_align_data;
                                }
                            }
                            $this->cell_height_ratio = $dom[$key]['line-height'];
                            $fontaligned = true;
                        }
                        $this->SetFont($fontname, $fontstyle, $fontsize);
                        // reset row height
                        $this->resetLastH();
                        $curfontname = $fontname;
                        $curfontstyle = $fontstyle;
                        $curfontsize = $fontsize;
                        $curfontascent = $fontascent;
                        $curfontdescent = $fontdescent;
                    }
                }
                // set text rendering mode
                $textstroke = isset($dom[$key]['stroke']) ? $dom[$key]['stroke'] : $this->textstrokewidth;
                $textfill = isset($dom[$key]['fill']) ? $dom[$key]['fill'] : (($this->textrendermode % 2) == 0);
                $textclip = isset($dom[$key]['clip']) ? $dom[$key]['clip'] : ($this->textrendermode > 3);
                $this->setTextRenderingMode($textstroke, $textfill, $textclip);
                if (isset($dom[$key]['font-stretch']) and ($dom[$key]['font-stretch'] !== false)) {
                    $this->setFontStretching($dom[$key]['font-stretch']);
                }
                if (isset($dom[$key]['letter-spacing']) and ($dom[$key]['letter-spacing'] !== false)) {
                    $this->setFontSpacing($dom[$key]['letter-spacing']);
                }
                if (($plalign == 'J') and $dom[$key]['block']) {
                    $plalign = '';
                }
                // get current position on page buffer
                $curpos = $this->pagelen[$startlinepage];
                if (isset($dom[$key]['bgcolor']) and ($dom[$key]['bgcolor'] !== false)) {
                    $this->SetFillColorArray($dom[$key]['bgcolor']);
                    $wfill = true;
                } else {
                    $wfill = $fill | false;
                }
                if (isset($dom[$key]['fgcolor']) and ($dom[$key]['fgcolor'] !== false)) {
                    $this->SetTextColorArray($dom[$key]['fgcolor']);
                }
                if (isset($dom[$key]['strokecolor']) and ($dom[$key]['strokecolor'] !== false)) {
                    $this->SetDrawColorArray($dom[$key]['strokecolor']);
                }
                if (isset($dom[$key]['align'])) {
                    $lalign = $dom[$key]['align'];
                }
                if (TCPDF_STATIC::empty_string($lalign)) {
                    $lalign = $align;
                }
            }
            // align lines
            if ($this->newline and (strlen($dom[$key]['value']) > 0) and ($dom[$key]['value'] != 'td') and ($dom[$key]['value'] != 'th')) {
                $newline = true;
                $fontaligned = false;
                // we are at the beginning of a new line
                if (isset($startlinex)) {
                    $yshift = ($minstartliney - $startliney);
                    if (($yshift > 0) or ($this->page > $startlinepage)) {
                        $yshift = 0;
                    }
                    $t_x = 0;
                    // the last line must be shifted to be aligned as requested
                    $linew = abs($this->endlinex - $startlinex);
                    if ($this->inxobj) {
                        // we are inside an XObject template
                        $pstart = substr($this->xobjects[$this->xobjid]['outdata'], 0, $startlinepos);
                        if (isset($opentagpos)) {
                            $midpos = $opentagpos;
                        } else {
                            $midpos = 0;
                        }
                        if ($midpos > 0) {
                            $pmid = substr($this->xobjects[$this->xobjid]['outdata'], $startlinepos, ($midpos - $startlinepos));
                            $pend = substr($this->xobjects[$this->xobjid]['outdata'], $midpos);
                        } else {
                            $pmid = substr($this->xobjects[$this->xobjid]['outdata'], $startlinepos);
                            $pend = '';
                        }
                    } else {
                        $pstart = substr($this->getPageBuffer($startlinepage), 0, $startlinepos);
                        if (isset($opentagpos) and isset($this->footerlen[$startlinepage]) and (!$this->InFooter)) {
                            $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
                            $midpos = min($opentagpos, $this->footerpos[$startlinepage]);
                        } elseif (isset($opentagpos)) {
                            $midpos = $opentagpos;
                        } elseif (isset($this->footerlen[$startlinepage]) and (!$this->InFooter)) {
                            $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
                            $midpos = $this->footerpos[$startlinepage];
                        } else {
                            $midpos = 0;
                        }
                        if ($midpos > 0) {
                            $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos, ($midpos - $startlinepos));
                            $pend = substr($this->getPageBuffer($startlinepage), $midpos);
                        } else {
                            $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos);
                            $pend = '';
                        }
                    }
                    if ((isset($plalign) and ((($plalign == 'C') or ($plalign == 'J') or (($plalign == 'R') and (!$this->rtl)) or (($plalign == 'L') and ($this->rtl)))))) {
                        // calculate shifting amount
                        $tw = $w;
                        if (($plalign == 'J') and $this->isRTLTextDir() and ($this->num_columns > 1)) {
                            $tw += $this->cell_padding['R'];
                        }
                        if ($this->lMargin != $prevlMargin) {
                            $tw += ($prevlMargin - $this->lMargin);
                        }
                        if ($this->rMargin != $prevrMargin) {
                            $tw += ($prevrMargin - $this->rMargin);
                        }
                        $one_space_width = $this->GetStringWidth(chr(32));
                        $no = 0; // number of spaces on a line contained on a single block
                        if ($this->isRTLTextDir()) { // RTL
                            // remove left space if exist
                            $pos1 = TCPDF_STATIC::revstrpos($pmid, '[(');
                            if ($pos1 > 0) {
                                $pos1 = intval($pos1);
                                if ($this->isUnicodeFont()) {
                                    $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, '[(' . chr(0) . chr(32)));
                                    $spacelen = 2;
                                } else {
                                    $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, '[(' . chr(32)));
                                    $spacelen = 1;
                                }
                                if ($pos1 == $pos2) {
                                    $pmid = substr($pmid, 0, ($pos1 + 2)) . substr($pmid, ($pos1 + 2 + $spacelen));
                                    if (substr($pmid, $pos1, 4) == '[()]') {
                                        $linew -= $one_space_width;
                                    } elseif ($pos1 == strpos($pmid, '[(')) {
                                        $no = 1;
                                    }
                                }
                            }
                        } else { // LTR
                            // remove right space if exist
                            $pos1 = TCPDF_STATIC::revstrpos($pmid, ')]');
                            if ($pos1 > 0) {
                                $pos1 = intval($pos1);
                                if ($this->isUnicodeFont()) {
                                    $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, chr(0) . chr(32) . ')]')) + 2;
                                    $spacelen = 2;
                                } else {
                                    $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, chr(32) . ')]')) + 1;
                                    $spacelen = 1;
                                }
                                if ($pos1 == $pos2) {
                                    $pmid = substr($pmid, 0, ($pos1 - $spacelen)) . substr($pmid, $pos1);
                                    $linew -= $one_space_width;
                                }
                            }
                        }
                        $mdiff = ($tw - $linew);
                        if ($plalign == 'C') {
                            if ($this->rtl) {
                                $t_x = - ($mdiff / 2);
                            } else {
                                $t_x = ($mdiff / 2);
                            }
                        } elseif ($plalign == 'R') {
                            // right alignment on LTR document
                            $t_x = $mdiff;
                        } elseif ($plalign == 'L') {
                            // left alignment on RTL document
                            $t_x = -$mdiff;
                        } elseif (($plalign == 'J') and ($plalign == $lalign)) {
                            // Justification
                            if ($this->isRTLTextDir()) {
                                // align text on the left
                                $t_x = -$mdiff;
                            }
                            $ns = 0; // number of spaces
                            $pmidtemp = $pmid;
                            // escape special characters
                            $pmidtemp = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmidtemp);
                            $pmidtemp = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmidtemp);
                            // search spaces
                            if (preg_match_all('/\[\(([^\)]*)\)\]/x', $pmidtemp, $lnstring, PREG_PATTERN_ORDER)) {
                                $spacestr = $this->getSpaceString();
                                $maxkk = count($lnstring[1]) - 1;
                                for ($kk = 0; $kk <= $maxkk; ++$kk) {
                                    // restore special characters
                                    $lnstring[1][$kk] = str_replace('#!#OP#!#', '(', $lnstring[1][$kk]);
                                    $lnstring[1][$kk] = str_replace('#!#CP#!#', ')', $lnstring[1][$kk]);
                                    // store number of spaces on the strings
                                    $lnstring[2][$kk] = substr_count($lnstring[1][$kk], $spacestr);
                                    // count total spaces on line
                                    $ns += $lnstring[2][$kk];
                                    $lnstring[3][$kk] = $ns;
                                }
                                if ($ns == 0) {
                                    $ns = 1;
                                }
                                // calculate additional space to add to each existing space
                                $spacewidth = ($mdiff / ($ns - $no)) * $this->k;
                                if ($this->FontSize <= 0) {
                                    $this->FontSize = 1;
                                }
                                $spacewidthu = -1000 * ($mdiff + (($ns + $no) * $one_space_width)) / $ns / $this->FontSize;
                                if ($this->font_spacing != 0) {
                                    // fixed spacing mode
                                    $osw = -1000 * $this->font_spacing / $this->FontSize;
                                    $spacewidthu += $osw;
                                }
                                $nsmax = $ns;
                                $ns = 0;
                                reset($lnstring);
                                $offset = 0;
                                $strcount = 0;
                                $prev_epsposbeg = 0;
                                $textpos = 0;
                                if ($this->isRTLTextDir()) {
                                    $textpos = $this->wPt;
                                }
                                while (preg_match('/([0-9\.\+\-]*)[\s](Td|cm|m|l|c|re)[\s]/x', $pmid, $strpiece, PREG_OFFSET_CAPTURE, $offset) == 1) {
                                    // check if we are inside a string section '[( ... )]'
                                    $stroffset = strpos($pmid, '[(', $offset);
                                    if (($stroffset !== false) and ($stroffset <= $strpiece[2][1])) {
                                        // set offset to the end of string section
                                        $offset = strpos($pmid, ')]', $stroffset);
                                        while (($offset !== false) and ($pmid[($offset - 1)] == '\\')) {
                                            $offset = strpos($pmid, ')]', ($offset + 1));
                                        }
                                        if ($offset === false) {
                                            $this->Error('HTML Justification: malformed PDF code.');
                                        }
                                        continue;
                                    }
                                    if ($this->isRTLTextDir()) {
                                        $spacew = ($spacewidth * ($nsmax - $ns));
                                    } else {
                                        $spacew = ($spacewidth * $ns);
                                    }
                                    $offset = $strpiece[2][1] + strlen($strpiece[2][0]);
                                    $epsposbeg = strpos($pmid, 'q' . $this->epsmarker, $offset);
                                    $epsposend = strpos($pmid, $this->epsmarker . 'Q', $offset) + strlen($this->epsmarker . 'Q');
                                    if ((($epsposbeg > 0) and ($epsposend > 0) and ($offset > $epsposbeg) and ($offset < $epsposend))
                                        or (($epsposbeg === false) and ($epsposend > 0) and ($offset < $epsposend))
                                    ) {
                                        // shift EPS images
                                        $trx = sprintf('1 0 0 1 %F 0 cm', $spacew);
                                        $epsposbeg = strpos($pmid, 'q' . $this->epsmarker, ($prev_epsposbeg - 6));
                                        $pmid_b = substr($pmid, 0, $epsposbeg);
                                        $pmid_m = substr($pmid, $epsposbeg, ($epsposend - $epsposbeg));
                                        $pmid_e = substr($pmid, $epsposend);
                                        $pmid = $pmid_b . "\nq\n" . $trx . "\n" . $pmid_m . "\nQ\n" . $pmid_e;
                                        $offset = $epsposend;
                                        continue;
                                    }
                                    $prev_epsposbeg = $epsposbeg;
                                    $currentxpos = 0;
                                    // shift blocks of code
                                    switch ($strpiece[2][0]) {
                                        case 'Td':
                                        case 'cm':
                                        case 'm':
                                        case 'l': {
                                                // get current X position
                                                preg_match('/([0-9\.\+\-]*)[\s](' . $strpiece[1][0] . ')[\s](' . $strpiece[2][0] . ')([\s]*)/x', $pmid, $xmatches);
                                                if (!isset($xmatches[1])) {
                                                    break;
                                                }
                                                $currentxpos = $xmatches[1];
                                                $textpos = $currentxpos;
                                                if (($strcount <= $maxkk) and ($strpiece[2][0] == 'Td')) {
                                                    $ns = $lnstring[3][$strcount];
                                                    if ($this->isRTLTextDir()) {
                                                        $spacew = ($spacewidth * ($nsmax - $ns));
                                                    }
                                                    ++$strcount;
                                                }
                                                // justify block
                                                if (preg_match('/([0-9\.\+\-]*)[\s](' . $strpiece[1][0] . ')[\s](' . $strpiece[2][0] . ')([\s]*)/x', $pmid, $pmatch) == 1) {
                                                    $newpmid = sprintf('%F', (floatval($pmatch[1]) + $spacew)) . ' ' . $pmatch[2] . ' x*#!#*x' . $pmatch[3] . $pmatch[4];
                                                    $pmid = str_replace($pmatch[0], $newpmid, $pmid);
                                                    unset($pmatch, $newpmid);
                                                }
                                                break;
                                            }
                                        case 're': {
                                                // justify block
                                                if (!TCPDF_STATIC::empty_string($this->lispacer)) {
                                                    $this->lispacer = '';
                                                    continue;
                                                }
                                                preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s](' . $strpiece[1][0] . ')[\s](re)([\s]*)/x', $pmid, $xmatches);
                                                if (!isset($xmatches[1])) {
                                                    break;
                                                }
                                                $currentxpos = $xmatches[1];
                                                $x_diff = 0;
                                                $w_diff = 0;
                                                if ($this->isRTLTextDir()) { // RTL
                                                    if ($currentxpos < $textpos) {
                                                        $x_diff = ($spacewidth * ($nsmax - $lnstring[3][$strcount]));
                                                        $w_diff = ($spacewidth * $lnstring[2][$strcount]);
                                                    } else {
                                                        if ($strcount > 0) {
                                                            $x_diff = ($spacewidth * ($nsmax - $lnstring[3][($strcount - 1)]));
                                                            $w_diff = ($spacewidth * $lnstring[2][($strcount - 1)]);
                                                        }
                                                    }
                                                } else { // LTR
                                                    if ($currentxpos > $textpos) {
                                                        if ($strcount > 0) {
                                                            $x_diff = ($spacewidth * $lnstring[3][($strcount - 1)]);
                                                        }
                                                        $w_diff = ($spacewidth * $lnstring[2][$strcount]);
                                                    } else {
                                                        if ($strcount > 1) {
                                                            $x_diff = ($spacewidth * $lnstring[3][($strcount - 2)]);
                                                        }
                                                        if ($strcount > 0) {
                                                            $w_diff = ($spacewidth * $lnstring[2][($strcount - 1)]);
                                                        }
                                                    }
                                                }
                                                if (preg_match('/(' . $xmatches[1] . ')[\s](' . $xmatches[2] . ')[\s](' . $xmatches[3] . ')[\s](' . $strpiece[1][0] . ')[\s](re)([\s]*)/x', $pmid, $pmatch) == 1) {
                                                    $newx = sprintf('%F', (floatval($pmatch[1]) + $x_diff));
                                                    $neww = sprintf('%F', (floatval($pmatch[3]) + $w_diff));
                                                    $newpmid = $newx . ' ' . $pmatch[2] . ' ' . $neww . ' ' . $pmatch[4] . ' x*#!#*x' . $pmatch[5] . $pmatch[6];
                                                    $pmid = str_replace($pmatch[0], $newpmid, $pmid);
                                                    unset($pmatch, $newpmid, $newx, $neww);
                                                }
                                                break;
                                            }
                                        case 'c': {
                                                // get current X position
                                                preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s](' . $strpiece[1][0] . ')[\s](c)([\s]*)/x', $pmid, $xmatches);
                                                if (!isset($xmatches[1])) {
                                                    break;
                                                }
                                                $currentxpos = $xmatches[1];
                                                // justify block
                                                if (preg_match('/(' . $xmatches[1] . ')[\s](' . $xmatches[2] . ')[\s](' . $xmatches[3] . ')[\s](' . $xmatches[4] . ')[\s](' . $xmatches[5] . ')[\s](' . $strpiece[1][0] . ')[\s](c)([\s]*)/x', $pmid, $pmatch) == 1) {
                                                    $newx1 = sprintf('%F', (floatval($pmatch[1]) + $spacew));
                                                    $newx2 = sprintf('%F', (floatval($pmatch[3]) + $spacew));
                                                    $newx3 = sprintf('%F', (floatval($pmatch[5]) + $spacew));
                                                    $newpmid = $newx1 . ' ' . $pmatch[2] . ' ' . $newx2 . ' ' . $pmatch[4] . ' ' . $newx3 . ' ' . $pmatch[6] . ' x*#!#*x' . $pmatch[7] . $pmatch[8];
                                                    $pmid = str_replace($pmatch[0], $newpmid, $pmid);
                                                    unset($pmatch, $newpmid, $newx1, $newx2, $newx3);
                                                }
                                                break;
                                            }
                                    }
                                    // shift the annotations and links
                                    $cxpos = ($currentxpos / $this->k);
                                    $lmpos = ($this->lMargin + $this->cell_padding['L'] + $this->feps);
                                    if ($this->inxobj) {
                                        // we are inside an XObject template
                                        foreach ($this->xobjects[$this->xobjid]['annotations'] as $pak => $pac) {
                                            if (($pac['y'] >= $minstartliney) and (($pac['x'] * $this->k) >= ($currentxpos - $this->feps)) and (($pac['x'] * $this->k) <= ($currentxpos + $this->feps))) {
                                                if ($cxpos > $lmpos) {
                                                    $this->xobjects[$this->xobjid]['annotations'][$pak]['x'] += ($spacew / $this->k);
                                                    $this->xobjects[$this->xobjid]['annotations'][$pak]['w'] += (($spacewidth * $pac['numspaces']) / $this->k);
                                                } else {
                                                    $this->xobjects[$this->xobjid]['annotations'][$pak]['w'] += (($spacewidth * $pac['numspaces']) / $this->k);
                                                }
                                                break;
                                            }
                                        }
                                    } elseif (isset($this->PageAnnots[$this->page])) {
                                        foreach ($this->PageAnnots[$this->page] as $pak => $pac) {
                                            if (($pac['y'] >= $minstartliney) and (($pac['x'] * $this->k) >= ($currentxpos - $this->feps)) and (($pac['x'] * $this->k) <= ($currentxpos + $this->feps))) {
                                                if ($cxpos > $lmpos) {
                                                    $this->PageAnnots[$this->page][$pak]['x'] += ($spacew / $this->k);
                                                    $this->PageAnnots[$this->page][$pak]['w'] += (($spacewidth * $pac['numspaces']) / $this->k);
                                                } else {
                                                    $this->PageAnnots[$this->page][$pak]['w'] += (($spacewidth * $pac['numspaces']) / $this->k);
                                                }
                                                break;
                                            }
                                        }
                                    }
                                } // end of while
                                // remove markers
                                $pmid = str_replace('x*#!#*x', '', $pmid);
                                if ($this->isUnicodeFont()) {
                                    // multibyte characters
                                    $spacew = $spacewidthu;
                                    if ($this->font_stretching != 100) {
                                        // word spacing is affected by stretching
                                        $spacew /= ($this->font_stretching / 100);
                                    }
                                    // escape special characters
                                    $pmid = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmid);
                                    $pmid = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmid);
                                    if (preg_match_all('/\[\(([^\)]*)\)\]/x', $pmid, $pamatch) > 0) {
                                        foreach ($pamatch[0] as $pk => $pmatch) {
                                            $pmatch = str_replace('#!#OP#!#', '(', $pmatch);
                                            $pmatch = str_replace('#!#CP#!#', ')', $pmatch);
                                            $newpmid = '[(' . str_replace(chr(0) . chr(32), ') ' . sprintf('%F', $spacew) . ' (', $pamatch[1][$pk]) . ')]';
                                            $pmid = str_replace($pmatch, $newpmid, $pmid);
                                        }
                                        unset($pamatch);
                                    }
                                    if ($this->inxobj) {
                                        // we are inside an XObject template
                                        $this->xobjects[$this->xobjid]['outdata'] = $pstart . "\n" . $pmid . "\n" . $pend;
                                    } else {
                                        $this->setPageBuffer($startlinepage, $pstart . "\n" . $pmid . "\n" . $pend);
                                    }
                                    $endlinepos = strlen($pstart . "\n" . $pmid . "\n");
                                } else {
                                    // non-unicode (single-byte characters)
                                    if ($this->font_stretching != 100) {
                                        // word spacing (Tw) is affected by stretching
                                        $spacewidth /= ($this->font_stretching / 100);
                                    }
                                    $rs = sprintf('%F Tw', $spacewidth);
                                    $pmid = preg_replace("/\[\(/x", $rs . ' [(', $pmid);
                                    if ($this->inxobj) {
                                        // we are inside an XObject template
                                        $this->xobjects[$this->xobjid]['outdata'] = $pstart . "\n" . $pmid . "\nBT 0 Tw ET\n" . $pend;
                                    } else {
                                        $this->setPageBuffer($startlinepage, $pstart . "\n" . $pmid . "\nBT 0 Tw ET\n" . $pend);
                                    }
                                    $endlinepos = strlen($pstart . "\n" . $pmid . "\nBT 0 Tw ET\n");
                                }
                            }
                        } // end of J
                    } // end if $startlinex
                    if (($t_x != 0) or ($yshift < 0)) {
                        // shift the line
                        $trx = sprintf('1 0 0 1 %F %F cm', ($t_x * $this->k), ($yshift * $this->k));
                        $pstart .= "\nq\n" . $trx . "\n" . $pmid . "\nQ\n";
                        $endlinepos = strlen($pstart);
                        if ($this->inxobj) {
                            // we are inside an XObject template
                            $this->xobjects[$this->xobjid]['outdata'] = $pstart . $pend;
                            foreach ($this->xobjects[$this->xobjid]['annotations'] as $pak => $pac) {
                                if ($pak >= $pask) {
                                    $this->xobjects[$this->xobjid]['annotations'][$pak]['x'] += $t_x;
                                    $this->xobjects[$this->xobjid]['annotations'][$pak]['y'] -= $yshift;
                                }
                            }
                        } else {
                            $this->setPageBuffer($startlinepage, $pstart . $pend);
                            // shift the annotations and links
                            if (isset($this->PageAnnots[$this->page])) {
                                foreach ($this->PageAnnots[$this->page] as $pak => $pac) {
                                    if ($pak >= $pask) {
                                        $this->PageAnnots[$this->page][$pak]['x'] += $t_x;
                                        $this->PageAnnots[$this->page][$pak]['y'] -= $yshift;
                                    }
                                }
                            }
                        }
                        $this->y -= $yshift;
                    }
                }
                $pbrk = $this->checkPageBreak($this->lasth);
                $this->newline = false;
                $startlinex = $this->x;
                $startliney = $this->y;
                if ($dom[$dom[$key]['parent']]['value'] == 'sup') {
                    $startliney -= ((0.3 * $this->FontSizePt) / $this->k);
                } elseif ($dom[$dom[$key]['parent']]['value'] == 'sub') {
                    $startliney -= (($this->FontSizePt / 0.7) / $this->k);
                } else {
                    $minstartliney = $startliney;
                    $maxbottomliney = ($this->y + $this->getCellHeight($fontsize / $this->k));
                }
                $startlinepage = $this->page;
                if (isset($endlinepos) and (!$pbrk)) {
                    $startlinepos = $endlinepos;
                } else {
                    if ($this->inxobj) {
                        // we are inside an XObject template
                        $startlinepos = strlen($this->xobjects[$this->xobjid]['outdata']);
                    } elseif (!$this->InFooter) {
                        if (isset($this->footerlen[$this->page])) {
                            $this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page];
                        } else {
                            $this->footerpos[$this->page] = $this->pagelen[$this->page];
                        }
                        $startlinepos = $this->footerpos[$this->page];
                    } else {
                        $startlinepos = $this->pagelen[$this->page];
                    }
                }
                unset($endlinepos);
                $plalign = $lalign;
                if (isset($this->PageAnnots[$this->page])) {
                    $pask = count($this->PageAnnots[$this->page]);
                } else {
                    $pask = 0;
                }
                if (!($dom[$key]['tag'] and !$dom[$key]['opening'] and ($dom[$key]['value'] == 'table')
                    and (isset($this->emptypagemrk[$this->page]))
                    and ($this->emptypagemrk[$this->page] == $this->pagelen[$this->page]))) {
                    $this->SetFont($fontname, $fontstyle, $fontsize);
                    if ($wfill) {
                        $this->SetFillColorArray($this->bgcolor);
                    }
                }
            } // end newline
            if (isset($opentagpos)) {
                unset($opentagpos);
            }
            if ($dom[$key]['tag']) {
                if ($dom[$key]['opening']) {
                    // get text indentation (if any)
                    if (isset($dom[$key]['text-indent']) and $dom[$key]['block']) {
                        $this->textindent = $dom[$key]['text-indent'];
                        $this->newline = true;
                    }
                    // table
                    if (($dom[$key]['value'] == 'table') and isset($dom[$key]['cols']) and ($dom[$key]['cols'] > 0)) {
                        // available page width
                        if ($this->rtl) {
                            $wtmp = $this->x - $this->lMargin;
                        } else {
                            $wtmp = $this->w - $this->rMargin - $this->x;
                        }
                        // get cell spacing
                        if (isset($dom[$key]['attribute']['cellspacing'])) {
                            $clsp = $this->getHTMLUnitToUnits($dom[$key]['attribute']['cellspacing'], 1, 'px');
                            $cellspacing = array('H' => $clsp, 'V' => $clsp);
                        } elseif (isset($dom[$key]['border-spacing'])) {
                            $cellspacing = $dom[$key]['border-spacing'];
                        } else {
                            $cellspacing = array('H' => 0, 'V' => 0);
                        }
                        // table width
                        if (isset($dom[$key]['width'])) {
                            $table_width = $this->getHTMLUnitToUnits($dom[$key]['width'], $wtmp, 'px');
                        } else {
                            $table_width = $wtmp;
                        }
                        $table_width -= (2 * $cellspacing['H']);
                        if (!$this->inthead) {
                            $this->y += $cellspacing['V'];
                        }
                        if ($this->rtl) {
                            $cellspacingx = -$cellspacing['H'];
                        } else {
                            $cellspacingx = $cellspacing['H'];
                        }
                        // total table width without cellspaces
                        $table_columns_width = ($table_width - ($cellspacing['H'] * ($dom[$key]['cols'] - 1)));
                        // minimum column width
                        $table_min_column_width = ($table_columns_width / $dom[$key]['cols']);
                        // array of custom column widths
                        $table_colwidths = array_fill(0, $dom[$key]['cols'], $table_min_column_width);
                    }
                    // table row
                    if ($dom[$key]['value'] == 'tr') {
                        // reset column counter
                        $colid = 0;
                    }
                    // table cell
                    if (($dom[$key]['value'] == 'td') or ($dom[$key]['value'] == 'th')) {
                        $trid = $dom[$key]['parent'];
                        $table_el = $dom[$trid]['parent'];
                        if (!isset($dom[$table_el]['cols'])) {
                            $dom[$table_el]['cols'] = $dom[$trid]['cols'];
                        }
                        // store border info
                        $tdborder = 0;
                        if (isset($dom[$key]['border']) and !empty($dom[$key]['border'])) {
                            $tdborder = $dom[$key]['border'];
                        }
                        $colspan = intval($dom[$key]['attribute']['colspan']);
                        if ($colspan <= 0) {
                            $colspan = 1;
                        }
                        $old_cell_padding = $this->cell_padding;
                        if (isset($dom[($dom[$trid]['parent'])]['attribute']['cellpadding'])) {
                            $crclpd = $this->getHTMLUnitToUnits($dom[($dom[$trid]['parent'])]['attribute']['cellpadding'], 1, 'px');
                            $current_cell_padding = array('L' => $crclpd, 'T' => $crclpd, 'R' => $crclpd, 'B' => $crclpd);
                        } elseif (isset($dom[($dom[$trid]['parent'])]['padding'])) {
                            $current_cell_padding = $dom[($dom[$trid]['parent'])]['padding'];
                        } else {
                            $current_cell_padding = array('L' => 0, 'T' => 0, 'R' => 0, 'B' => 0);
                        }
                        $this->cell_padding = $current_cell_padding;
                        if (isset($dom[$key]['height'])) {
                            // minimum cell height
                            $cellh = $this->getHTMLUnitToUnits($dom[$key]['height'], 0, 'px');
                        } else {
                            $cellh = 0;
                        }
                        if (isset($dom[$key]['content'])) {
                            $cell_content = stripslashes($dom[$key]['content']);
                        } else {
                            $cell_content = '&nbsp;';
                        }
                        $tagtype = $dom[$key]['value'];
                        $parentid = $key;
                        while (($key < $maxel) and (!(($dom[$key]['tag']) and (!$dom[$key]['opening']) and ($dom[$key]['value'] == $tagtype) and ($dom[$key]['parent'] == $parentid)))) {
                            // move $key index forward
                            ++$key;
                        }
                        if (!isset($dom[$trid]['startpage'])) {
                            $dom[$trid]['startpage'] = $this->page;
                        } else {
                            $this->setPage($dom[$trid]['startpage']);
                        }
                        if (!isset($dom[$trid]['startcolumn'])) {
                            $dom[$trid]['startcolumn'] = $this->current_column;
                        } elseif ($this->current_column != $dom[$trid]['startcolumn']) {
                            $tmpx = $this->x;
                            $this->selectColumn($dom[$trid]['startcolumn']);
                            $this->x = $tmpx;
                        }
                        if (!isset($dom[$trid]['starty'])) {
                            $dom[$trid]['starty'] = $this->y;
                        } else {
                            $this->y = $dom[$trid]['starty'];
                        }
                        if (!isset($dom[$trid]['startx'])) {
                            $dom[$trid]['startx'] = $this->x;
                            $this->x += $cellspacingx;
                        } else {
                            $this->x += ($cellspacingx / 2);
                        }
                        if (isset($dom[$parentid]['attribute']['rowspan'])) {
                            $rowspan = intval($dom[$parentid]['attribute']['rowspan']);
                        } else {
                            $rowspan = 1;
                        }
                        // skip row-spanned cells started on the previous rows
                        if (isset($dom[$table_el]['rowspans'])) {
                            $rsk = 0;
                            $rskmax = count($dom[$table_el]['rowspans']);
                            while ($rsk < $rskmax) {
                                $trwsp = $dom[$table_el]['rowspans'][$rsk];
                                $rsstartx = $trwsp['startx'];
                                $rsendx = $trwsp['endx'];
                                // account for margin changes
                                if ($trwsp['startpage'] < $this->page) {
                                    if (($this->rtl) and ($this->pagedim[$this->page]['orm'] != $this->pagedim[$trwsp['startpage']]['orm'])) {
                                        $dl = ($this->pagedim[$this->page]['orm'] - $this->pagedim[$trwsp['startpage']]['orm']);
                                        $rsstartx -= $dl;
                                        $rsendx -= $dl;
                                    } elseif ((!$this->rtl) and ($this->pagedim[$this->page]['olm'] != $this->pagedim[$trwsp['startpage']]['olm'])) {
                                        $dl = ($this->pagedim[$this->page]['olm'] - $this->pagedim[$trwsp['startpage']]['olm']);
                                        $rsstartx += $dl;
                                        $rsendx += $dl;
                                    }
                                }
                                if (($trwsp['rowspan'] > 0)
                                    and ($rsstartx > ($this->x - $cellspacing['H'] - $current_cell_padding['L'] - $this->feps))
                                    and ($rsstartx < ($this->x + $cellspacing['H'] + $current_cell_padding['R'] + $this->feps))
                                    and (($trwsp['starty'] < ($this->y - $this->feps)) or ($trwsp['startpage'] < $this->page) or ($trwsp['startcolumn'] < $this->current_column))
                                ) {
                                    // set the starting X position of the current cell
                                    $this->x = $rsendx + $cellspacingx;
                                    // increment column indicator
                                    $colid += $trwsp['colspan'];
                                    if (($trwsp['rowspan'] == 1)
                                        and (isset($dom[$trid]['endy']))
                                        and (isset($dom[$trid]['endpage']))
                                        and (isset($dom[$trid]['endcolumn']))
                                        and ($trwsp['endpage'] == $dom[$trid]['endpage'])
                                        and ($trwsp['endcolumn'] == $dom[$trid]['endcolumn'])
                                    ) {
                                        // set ending Y position for row
                                        $dom[$table_el]['rowspans'][$rsk]['endy'] = max($dom[$trid]['endy'], $trwsp['endy']);
                                        $dom[$trid]['endy'] = $dom[$table_el]['rowspans'][$rsk]['endy'];
                                    }
                                    $rsk = 0;
                                } else {
                                    ++$rsk;
                                }
                            }
                        }
                        if (isset($dom[$parentid]['width'])) {
                            // user specified width
                            $cellw = $this->getHTMLUnitToUnits($dom[$parentid]['width'], $table_columns_width, 'px');
                            $tmpcw = ($cellw / $colspan);
                            for ($i = 0; $i < $colspan; ++$i) {
                                $table_colwidths[($colid + $i)] = $tmpcw;
                            }
                        } else {
                            // inherit column width
                            $cellw = 0;
                            for ($i = 0; $i < $colspan; ++$i) {
                                $cellw += $table_colwidths[($colid + $i)];
                            }
                        }
                        $cellw += (($colspan - 1) * $cellspacing['H']);
                        // increment column indicator
                        $colid += $colspan;
                        // add rowspan information to table element
                        if ($rowspan > 1) {
                            $trsid = array_push($dom[$table_el]['rowspans'], array('trid' => $trid, 'rowspan' => $rowspan, 'mrowspan' => $rowspan, 'colspan' => $colspan, 'startpage' => $this->page, 'startcolumn' => $this->current_column, 'startx' => $this->x, 'starty' => $this->y));
                        }
                        $cellid = array_push($dom[$trid]['cellpos'], array('startx' => $this->x));
                        if ($rowspan > 1) {
                            $dom[$trid]['cellpos'][($cellid - 1)]['rowspanid'] = ($trsid - 1);
                        }
                        // push background colors
                        if (isset($dom[$parentid]['bgcolor']) and ($dom[$parentid]['bgcolor'] !== false)) {
                            $dom[$trid]['cellpos'][($cellid - 1)]['bgcolor'] = $dom[$parentid]['bgcolor'];
                        }
                        // store border info
                        if (isset($tdborder) and !empty($tdborder)) {
                            $dom[$trid]['cellpos'][($cellid - 1)]['border'] = $tdborder;
                        }
                        $prevLastH = $this->lasth;
                        // store some info for multicolumn mode
                        if ($this->rtl) {
                            $this->colxshift['x'] = $this->w - $this->x - $this->rMargin;
                        } else {
                            $this->colxshift['x'] = $this->x - $this->lMargin;
                        }
                        $this->colxshift['s'] = $cellspacing;
                        $this->colxshift['p'] = $current_cell_padding;
                        // ****** write the cell content ******
                        $this->MultiCell($cellw, $cellh, $cell_content, false, $lalign, false, 2, '', '', true, 0, true, true, 0, 'T', false);
                        // restore some values
                        $this->colxshift = array('x' => 0, 's' => array('H' => 0, 'V' => 0), 'p' => array('L' => 0, 'T' => 0, 'R' => 0, 'B' => 0));
                        $this->lasth = $prevLastH;
                        $this->cell_padding = $old_cell_padding;
                        $dom[$trid]['cellpos'][($cellid - 1)]['endx'] = $this->x;
                        // update the end of row position
                        if ($rowspan <= 1) {
                            if (isset($dom[$trid]['endy'])) {
                                if (($this->page == $dom[$trid]['endpage']) and ($this->current_column == $dom[$trid]['endcolumn'])) {
                                    $dom[$trid]['endy'] = max($this->y, $dom[$trid]['endy']);
                                } elseif (($this->page > $dom[$trid]['endpage']) or ($this->current_column > $dom[$trid]['endcolumn'])) {
                                    $dom[$trid]['endy'] = $this->y;
                                }
                            } else {
                                $dom[$trid]['endy'] = $this->y;
                            }
                            if (isset($dom[$trid]['endpage'])) {
                                $dom[$trid]['endpage'] = max($this->page, $dom[$trid]['endpage']);
                            } else {
                                $dom[$trid]['endpage'] = $this->page;
                            }
                            if (isset($dom[$trid]['endcolumn'])) {
                                $dom[$trid]['endcolumn'] = max($this->current_column, $dom[$trid]['endcolumn']);
                            } else {
                                $dom[$trid]['endcolumn'] = $this->current_column;
                            }
                        } else {
                            // account for row-spanned cells
                            $dom[$table_el]['rowspans'][($trsid - 1)]['endx'] = $this->x;
                            $dom[$table_el]['rowspans'][($trsid - 1)]['endy'] = $this->y;
                            $dom[$table_el]['rowspans'][($trsid - 1)]['endpage'] = $this->page;
                            $dom[$table_el]['rowspans'][($trsid - 1)]['endcolumn'] = $this->current_column;
                        }
                        if (isset($dom[$table_el]['rowspans'])) {
                            // update endy and endpage on rowspanned cells
                            foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) {
                                if ($trwsp['rowspan'] > 0) {
                                    if (isset($dom[$trid]['endpage'])) {
                                        if (($trwsp['endpage'] == $dom[$trid]['endpage']) and ($trwsp['endcolumn'] == $dom[$trid]['endcolumn'])) {
                                            $dom[$table_el]['rowspans'][$k]['endy'] = max($dom[$trid]['endy'], $trwsp['endy']);
                                        } elseif (($trwsp['endpage'] < $dom[$trid]['endpage']) or ($trwsp['endcolumn'] < $dom[$trid]['endcolumn'])) {
                                            $dom[$table_el]['rowspans'][$k]['endy'] = $dom[$trid]['endy'];
                                            $dom[$table_el]['rowspans'][$k]['endpage'] = $dom[$trid]['endpage'];
                                            $dom[$table_el]['rowspans'][$k]['endcolumn'] = $dom[$trid]['endcolumn'];
                                        } else {
                                            $dom[$trid]['endy'] = $this->pagedim[$dom[$trid]['endpage']]['hk'] - $this->pagedim[$dom[$trid]['endpage']]['bm'];
                                        }
                                    }
                                }
                            }
                        }
                        $this->x += ($cellspacingx / 2);
                    } else {
                        // opening tag (or self-closing tag)
                        if (!isset($opentagpos)) {
                            if ($this->inxobj) {
                                // we are inside an XObject template
                                $opentagpos = strlen($this->xobjects[$this->xobjid]['outdata']);
                            } elseif (!$this->InFooter) {
                                if (isset($this->footerlen[$this->page])) {
                                    $this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page];
                                } else {
                                    $this->footerpos[$this->page] = $this->pagelen[$this->page];
                                }
                                $opentagpos = $this->footerpos[$this->page];
                            }
                        }
                        $dom = $this->openHTMLTagHandler($dom, $key, $cell);
                    }
                } else { // closing tag
                    $prev_numpages = $this->numpages;
                    $old_bordermrk = $this->bordermrk[$this->page];
                    $dom = $this->closeHTMLTagHandler($dom, $key, $cell, $maxbottomliney);
                    if ($this->bordermrk[$this->page] > $old_bordermrk) {
                        $startlinepos += ($this->bordermrk[$this->page] - $old_bordermrk);
                    }
                    if ($prev_numpages > $this->numpages) {
                        $startlinepage = $this->page;
                    }
                }
            } elseif (strlen($dom[$key]['value']) > 0) {
                // print list-item
                if (!TCPDF_STATIC::empty_string($this->lispacer) and ($this->lispacer != '^')) {
                    $this->SetFont($pfontname, $pfontstyle, $pfontsize);
                    $this->resetLastH();
                    $minstartliney = $this->y;
                    $maxbottomliney = ($startliney + $this->getCellHeight($this->FontSize));
                    if (is_numeric($pfontsize) and ($pfontsize > 0)) {
                        $this->putHtmlListBullet($this->listnum, $this->lispacer, $pfontsize);
                    }
                    $this->SetFont($curfontname, $curfontstyle, $curfontsize);
                    $this->resetLastH();
                    if (is_numeric($pfontsize) and ($pfontsize > 0) and is_numeric($curfontsize) and ($curfontsize > 0) and ($pfontsize != $curfontsize)) {
                        $pfontascent = $this->getFontAscent($pfontname, $pfontstyle, $pfontsize);
                        $pfontdescent = $this->getFontDescent($pfontname, $pfontstyle, $pfontsize);
                        $this->y += ($this->getCellHeight(($pfontsize - $curfontsize) / $this->k) + $pfontascent - $curfontascent - $pfontdescent + $curfontdescent) / 2;
                        $minstartliney = min($this->y, $minstartliney);
                        $maxbottomliney = max(($this->y + $this->getCellHeight($pfontsize / $this->k)), $maxbottomliney);
                    }
                }
                // text
                $this->htmlvspace = 0;
                if ((!$this->premode) and $this->isRTLTextDir()) {
                    // reverse spaces order
                    $lsp = ''; // left spaces
                    $rsp = ''; // right spaces
                    if (preg_match('/^(' . $this->re_space['p'] . '+)/' . $this->re_space['m'], $dom[$key]['value'], $matches)) {
                        $lsp = $matches[1];
                    }
                    if (preg_match('/(' . $this->re_space['p'] . '+)$/' . $this->re_space['m'], $dom[$key]['value'], $matches)) {
                        $rsp = $matches[1];
                    }
                    $dom[$key]['value'] = $rsp . $this->stringTrim($dom[$key]['value']) . $lsp;
                }
                if ($newline) {
                    if (!$this->premode) {
                        $prelen = strlen($dom[$key]['value']);
                        if ($this->isRTLTextDir()) {
                            // right trim except non-breaking space
                            $dom[$key]['value'] = $this->stringRightTrim($dom[$key]['value']);
                        } else {
                            // left trim except non-breaking space
                            $dom[$key]['value'] = $this->stringLeftTrim($dom[$key]['value']);
                        }
                        $postlen = strlen($dom[$key]['value']);
                        if (($postlen == 0) and ($prelen > 0)) {
                            $dom[$key]['trimmed_space'] = true;
                        }
                    }
                    $newline = false;
                    $firstblock = true;
                } else {
                    $firstblock = false;
                    // replace empty multiple spaces string with a single space
                    $dom[$key]['value'] = preg_replace('/^' . $this->re_space['p'] . '+$/' . $this->re_space['m'], chr(32), $dom[$key]['value']);
                }
                $strrest = '';
                if ($this->rtl) {
                    $this->x -= $this->textindent;
                } else {
                    $this->x += $this->textindent;
                }
                if (!isset($dom[$key]['trimmed_space']) or !$dom[$key]['trimmed_space']) {
                    $strlinelen = $this->GetStringWidth($dom[$key]['value']);
                    if (!empty($this->HREF) and (isset($this->HREF['url']))) {
                        // HTML <a> Link
                        $hrefcolor = '';
                        if (isset($dom[($dom[$key]['parent'])]['fgcolor']) and ($dom[($dom[$key]['parent'])]['fgcolor'] !== false)) {
                            $hrefcolor = $dom[($dom[$key]['parent'])]['fgcolor'];
                        }
                        $hrefstyle = -1;
                        if (isset($dom[($dom[$key]['parent'])]['fontstyle']) and ($dom[($dom[$key]['parent'])]['fontstyle'] !== false)) {
                            $hrefstyle = $dom[($dom[$key]['parent'])]['fontstyle'];
                        }
                        $strrest = $this->addHtmlLink($this->HREF['url'], $dom[$key]['value'], $wfill, true, $hrefcolor, $hrefstyle, true);
                    } else {
                        $wadj = 0; // space to leave for block continuity
                        if ($this->rtl) {
                            $cwa = ($this->x - $this->lMargin);
                        } else {
                            $cwa = ($this->w - $this->rMargin - $this->x);
                        }
                        if (($strlinelen < $cwa) and (isset($dom[($key + 1)])) and ($dom[($key + 1)]['tag']) and (!$dom[($key + 1)]['block'])) {
                            // check the next text blocks for continuity
                            $nkey = ($key + 1);
                            $write_block = true;
                            $same_textdir = true;
                            $tmp_fontname = $this->FontFamily;
                            $tmp_fontstyle = $this->FontStyle;
                            $tmp_fontsize = $this->FontSizePt;
                            while ($write_block and isset($dom[$nkey])) {
                                if ($dom[$nkey]['tag']) {
                                    if ($dom[$nkey]['block']) {
                                        // end of block
                                        $write_block = false;
                                    }
                                    $tmp_fontname = isset($dom[$nkey]['fontname']) ? $dom[$nkey]['fontname'] : $this->FontFamily;
                                    $tmp_fontstyle = isset($dom[$nkey]['fontstyle']) ? $dom[$nkey]['fontstyle'] : $this->FontStyle;
                                    $tmp_fontsize = isset($dom[$nkey]['fontsize']) ? $dom[$nkey]['fontsize'] : $this->FontSizePt;
                                    $same_textdir = ($dom[$nkey]['dir'] == $dom[$key]['dir']);
                                } else {
                                    $nextstr = TCPDF_STATIC::pregSplit('/' . $this->re_space['p'] . '+/', $this->re_space['m'], $dom[$nkey]['value']);
                                    if (isset($nextstr[0]) and $same_textdir) {
                                        $wadj += $this->GetStringWidth($nextstr[0], $tmp_fontname, $tmp_fontstyle, $tmp_fontsize);
                                        if (isset($nextstr[1])) {
                                            $write_block = false;
                                        }
                                    }
                                }
                                ++$nkey;
                            }
                        }
                        if (($wadj > 0) and (($strlinelen + $wadj) >= $cwa)) {
                            $wadj = 0;
                            $nextstr = TCPDF_STATIC::pregSplit('/' . $this->re_space['p'] . '/', $this->re_space['m'], $dom[$key]['value']);
                            $numblks = count($nextstr);
                            if ($numblks > 1) {
                                // try to split on blank spaces
                                $wadj = ($cwa - $strlinelen + $this->GetStringWidth($nextstr[($numblks - 1)]));
                            } else {
                                // set the entire block on new line
                                $wadj = $this->GetStringWidth($nextstr[0]);
                            }
                        }
                        // check for reversed text direction
                        if (($wadj > 0) and (($this->rtl and ($this->tmprtl === 'L')) or (!$this->rtl and ($this->tmprtl === 'R')))) {
                            // LTR text on RTL direction or RTL text on LTR direction
                            $reverse_dir = true;
                            $this->rtl = !$this->rtl;
                            $revshift = ($strlinelen + $wadj + 0.000001); // add little quantity for rounding problems
                            if ($this->rtl) {
                                $this->x += $revshift;
                            } else {
                                $this->x -= $revshift;
                            }
                            $xws = $this->x;
                        }
                        // ****** write only until the end of the line and get the rest ******
                        $strrest = $this->Write($this->lasth, $dom[$key]['value'], '', $wfill, '', false, 0, true, $firstblock, 0, $wadj);
                        // restore default direction
                        if ($reverse_dir and ($wadj == 0)) {
                            $this->x = $xws;
                            $this->rtl = !$this->rtl;
                            $reverse_dir = false;
                        }
                    }
                }
                $this->textindent = 0;
                if (strlen($strrest) > 0) {
                    // store the remaining string on the previous $key position
                    $this->newline = true;
                    if ($strrest == $dom[$key]['value']) {
                        // used to avoid infinite loop
                        ++$loop;
                    } else {
                        $loop = 0;
                    }
                    $dom[$key]['value'] = $strrest;
                    if ($cell) {
                        if ($this->rtl) {
                            $this->x -= $this->cell_padding['R'];
                        } else {
                            $this->x += $this->cell_padding['L'];
                        }
                    }
                    if ($loop < 3) {
                        --$key;
                    }
                } else {
                    $loop = 0;
                    // add the positive font spacing of the last character (if any)
                    if ($this->font_spacing > 0) {
                        if ($this->rtl) {
                            $this->x -= $this->font_spacing;
                        } else {
                            $this->x += $this->font_spacing;
                        }
                    }
                }
            }
            ++$key;
            if (isset($dom[$key]['tag']) and $dom[$key]['tag'] and (!isset($dom[$key]['opening']) or !$dom[$key]['opening']) and isset($dom[($dom[$key]['parent'])]['attribute']['nobr']) and ($dom[($dom[$key]['parent'])]['attribute']['nobr'] == 'true')) {
                // check if we are on a new page or on a new column
                if ((!$undo) and (($this->y < $this->start_transaction_y) or (($dom[$key]['value'] == 'tr') and ($dom[($dom[$key]['parent'])]['endy'] < $this->start_transaction_y)))) {
                    // we are on a new page or on a new column and the total object height is less than the available vertical space.
                    // restore previous object
                    $this->rollbackTransaction(true);
                    // restore previous values
                    foreach ($this_method_vars as $vkey => $vval) {
                        $$vkey = $vval;
                    }
                    // add a page (or trig AcceptPageBreak() for multicolumn mode)
                    $pre_y = $this->y;
                    if ((!$this->checkPageBreak($this->PageBreakTrigger + 1)) and ($this->y < $pre_y)) {
                        $startliney = $this->y;
                    }
                    $undo = true; // avoid infinite loop
                } else {
                    $undo = false;
                }
            }
        } // end for each $key
        // align the last line
        if (isset($startlinex)) {
            $yshift = ($minstartliney - $startliney);
            if (($yshift > 0) or ($this->page > $startlinepage)) {
                $yshift = 0;
            }
            $t_x = 0;
            // the last line must be shifted to be aligned as requested
            $linew = abs($this->endlinex - $startlinex);
            if ($this->inxobj) {
                // we are inside an XObject template
                $pstart = substr($this->xobjects[$this->xobjid]['outdata'], 0, $startlinepos);
                if (isset($opentagpos)) {
                    $midpos = $opentagpos;
                } else {
                    $midpos = 0;
                }
                if ($midpos > 0) {
                    $pmid = substr($this->xobjects[$this->xobjid]['outdata'], $startlinepos, ($midpos - $startlinepos));
                    $pend = substr($this->xobjects[$this->xobjid]['outdata'], $midpos);
                } else {
                    $pmid = substr($this->xobjects[$this->xobjid]['outdata'], $startlinepos);
                    $pend = '';
                }
            } else {
                $pstart = substr($this->getPageBuffer($startlinepage), 0, $startlinepos);
                if (isset($opentagpos) and isset($this->footerlen[$startlinepage]) and (!$this->InFooter)) {
                    $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
                    $midpos = min($opentagpos, $this->footerpos[$startlinepage]);
                } elseif (isset($opentagpos)) {
                    $midpos = $opentagpos;
                } elseif (isset($this->footerlen[$startlinepage]) and (!$this->InFooter)) {
                    $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
                    $midpos = $this->footerpos[$startlinepage];
                } else {
                    $midpos = 0;
                }
                if ($midpos > 0) {
                    $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos, ($midpos - $startlinepos));
                    $pend = substr($this->getPageBuffer($startlinepage), $midpos);
                } else {
                    $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos);
                    $pend = '';
                }
            }
            if ((isset($plalign) and ((($plalign == 'C') or (($plalign == 'R') and (!$this->rtl)) or (($plalign == 'L') and ($this->rtl)))))) {
                // calculate shifting amount
                $tw = $w;
                if ($this->lMargin != $prevlMargin) {
                    $tw += ($prevlMargin - $this->lMargin);
                }
                if ($this->rMargin != $prevrMargin) {
                    $tw += ($prevrMargin - $this->rMargin);
                }
                $one_space_width = $this->GetStringWidth(chr(32));
                $no = 0; // number of spaces on a line contained on a single block
                if ($this->isRTLTextDir()) { // RTL
                    // remove left space if exist
                    $pos1 = TCPDF_STATIC::revstrpos($pmid, '[(');
                    if ($pos1 > 0) {
                        $pos1 = intval($pos1);
                        if ($this->isUnicodeFont()) {
                            $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, '[(' . chr(0) . chr(32)));
                            $spacelen = 2;
                        } else {
                            $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, '[(' . chr(32)));
                            $spacelen = 1;
                        }
                        if ($pos1 == $pos2) {
                            $pmid = substr($pmid, 0, ($pos1 + 2)) . substr($pmid, ($pos1 + 2 + $spacelen));
                            if (substr($pmid, $pos1, 4) == '[()]') {
                                $linew -= $one_space_width;
                            } elseif ($pos1 == strpos($pmid, '[(')) {
                                $no = 1;
                            }
                        }
                    }
                } else { // LTR
                    // remove right space if exist
                    $pos1 = TCPDF_STATIC::revstrpos($pmid, ')]');
                    if ($pos1 > 0) {
                        $pos1 = intval($pos1);
                        if ($this->isUnicodeFont()) {
                            $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, chr(0) . chr(32) . ')]')) + 2;
                            $spacelen = 2;
                        } else {
                            $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, chr(32) . ')]')) + 1;
                            $spacelen = 1;
                        }
                        if ($pos1 == $pos2) {
                            $pmid = substr($pmid, 0, ($pos1 - $spacelen)) . substr($pmid, $pos1);
                            $linew -= $one_space_width;
                        }
                    }
                }
                $mdiff = ($tw - $linew);
                if ($plalign == 'C') {
                    if ($this->rtl) {
                        $t_x = - ($mdiff / 2);
                    } else {
                        $t_x = ($mdiff / 2);
                    }
                } elseif ($plalign == 'R') {
                    // right alignment on LTR document
                    $t_x = $mdiff;
                } elseif ($plalign == 'L') {
                    // left alignment on RTL document
                    $t_x = -$mdiff;
                }
            } // end if startlinex
            if (($t_x != 0) or ($yshift < 0)) {
                // shift the line
                $trx = sprintf('1 0 0 1 %F %F cm', ($t_x * $this->k), ($yshift * $this->k));
                $pstart .= "\nq\n" . $trx . "\n" . $pmid . "\nQ\n";
                $endlinepos = strlen($pstart);
                if ($this->inxobj) {
                    // we are inside an XObject template
                    $this->xobjects[$this->xobjid]['outdata'] = $pstart . $pend;
                    foreach ($this->xobjects[$this->xobjid]['annotations'] as $pak => $pac) {
                        if ($pak >= $pask) {
                            $this->xobjects[$this->xobjid]['annotations'][$pak]['x'] += $t_x;
                            $this->xobjects[$this->xobjid]['annotations'][$pak]['y'] -= $yshift;
                        }
                    }
                } else {
                    $this->setPageBuffer($startlinepage, $pstart . $pend);
                    // shift the annotations and links
                    if (isset($this->PageAnnots[$this->page])) {
                        foreach ($this->PageAnnots[$this->page] as $pak => $pac) {
                            if ($pak >= $pask) {
                                $this->PageAnnots[$this->page][$pak]['x'] += $t_x;
                                $this->PageAnnots[$this->page][$pak]['y'] -= $yshift;
                            }
                        }
                    }
                }
                $this->y -= $yshift;
                $yshift = 0;
            }
        }
        // restore previous values
        $this->setGraphicVars($gvars);
        if ($this->num_columns > 1) {
            $this->selectColumn();
        } elseif ($this->page > $prevPage) {
            $this->lMargin = $this->pagedim[$this->page]['olm'];
            $this->rMargin = $this->pagedim[$this->page]['orm'];
        }
        // restore previous list state
        $this->cell_height_ratio = $prev_cell_height_ratio;
        $this->listnum = $prev_listnum;
        $this->listordered = $prev_listordered;
        $this->listcount = $prev_listcount;
        $this->lispacer = $prev_lispacer;
        if ($ln and (!($cell and ($dom[$key - 1]['value'] == 'table')))) {
            $this->Ln($this->lasth);
            if ($this->y < $maxbottomliney) {
                $this->y = $maxbottomliney;
            }
        }
        unset($dom);
    }

    function Code39($x, $y, $code, $ext = true, $cks = false, $w = 0.29, $h = 16, $wide = true)
    {

        //Display code
        $this->SetFont('Arial', '', 10);
        $this->Text($x, $y + $h + 4, $code);

        if ($ext) {
            //Extended encoding
            $code = $this->encode_code39_ext($code);
        } else {
            //Convert to upper case
            $code = strtoupper($code);
            //Check validity
            if (!preg_match('|^[0-9A-Z. $/+%-]*$|', $code))
                $this->Error('Invalid barcode value: ' . $code);
        }

        //Compute checksum
        if ($cks)
            $code .= $this->checksum_code39($code);

        //Add start and stop characters
        $code = '*' . $code . '*';

        //Conversion tables
        $narrow_encoding = array(
            '0' => '101001101101', '1' => '110100101011', '2' => '101100101011',
            '3' => '110110010101', '4' => '101001101011', '5' => '110100110101',
            '6' => '101100110101', '7' => '101001011011', '8' => '110100101101',
            '9' => '101100101101', 'A' => '110101001011', 'B' => '101101001011',
            'C' => '110110100101', 'D' => '101011001011', 'E' => '110101100101',
            'F' => '101101100101', 'G' => '101010011011', 'H' => '110101001101',
            'I' => '101101001101', 'J' => '101011001101', 'K' => '110101010011',
            'L' => '101101010011', 'M' => '110110101001', 'N' => '101011010011',
            'O' => '110101101001', 'P' => '101101101001', 'Q' => '101010110011',
            'R' => '110101011001', 'S' => '101101011001', 'T' => '101011011001',
            'U' => '110010101011', 'V' => '100110101011', 'W' => '110011010101',
            'X' => '100101101011', 'Y' => '110010110101', 'Z' => '100110110101',
            '-' => '100101011011', '.' => '110010101101', ' ' => '100110101101',
            '*' => '100101101101', '$' => '100100100101', '/' => '100100101001',
            '+' => '100101001001', '%' => '101001001001'
        );

        $wide_encoding = array(
            '0' => '101000111011101', '1' => '111010001010111', '2' => '101110001010111',
            '3' => '111011100010101', '4' => '101000111010111', '5' => '111010001110101',
            '6' => '101110001110101', '7' => '101000101110111', '8' => '111010001011101',
            '9' => '101110001011101', 'A' => '111010100010111', 'B' => '101110100010111',
            'C' => '111011101000101', 'D' => '101011100010111', 'E' => '111010111000101',
            'F' => '101110111000101', 'G' => '101010001110111', 'H' => '111010100011101',
            'I' => '101110100011101', 'J' => '101011100011101', 'K' => '111010101000111',
            'L' => '101110101000111', 'M' => '111011101010001', 'N' => '101011101000111',
            'O' => '111010111010001', 'P' => '101110111010001', 'Q' => '101010111000111',
            'R' => '111010101110001', 'S' => '101110101110001', 'T' => '101011101110001',
            'U' => '111000101010111', 'V' => '100011101010111', 'W' => '111000111010101',
            'X' => '100010111010111', 'Y' => '111000101110101', 'Z' => '100011101110101',
            '-' => '100010101110111', '.' => '111000101011101', ' ' => '100011101011101',
            '*' => '100010111011101', '$' => '100010001000101', '/' => '100010001010001',
            '+' => '100010100010001', '%' => '101000100010001'
        );

        $encoding = $wide ? $wide_encoding : $narrow_encoding;

        //Inter-character spacing
        $gap = ($w > 0.29) ? '00' : '0';

        //Convert to bars
        $encode = '';
        for ($i = 0; $i < strlen($code); $i++)
            $encode .= $encoding[$code[$i]] . $gap;

        //Draw bars
        $this->draw_code39($encode, $x, $y, $w, $h);
    }

    function checksum_code39($code)
    {

        //Compute the modulo 43 checksum

        $chars = array(
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
            'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
            'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%'
        );
        $sum = 0;
        for ($i = 0; $i < strlen($code); $i++) {
            $a = array_keys($chars, $code[$i]);
            $sum += $a[0];
        }
        $r = $sum % 43;
        return $chars[$r];
    }

    function encode_code39_ext($code)
    {

        //Encode characters in extended mode

        $encode = array(
            chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C',
            chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G',
            chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K',
            chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O',
            chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S',
            chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W',
            chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A',
            chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E',
            chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C',
            chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G',
            chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K',
            chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O',
            chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
            chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
            chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F',
            chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J',
            chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
            chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
            chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
            chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
            chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
            chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
            chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K',
            chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O',
            chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C',
            chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G',
            chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K',
            chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O',
            chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S',
            chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W',
            chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P',
            chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T'
        );

        $code_ext = '';
        for ($i = 0; $i < strlen($code); $i++) {
            if (ord($code[$i]) > 127)
                $this->Error('Invalid character: ' . $code[$i]);
            $code_ext .= $encode[$code[$i]];
        }
        return $code_ext;
    }

    function draw_code39($code, $x, $y, $w, $h)
    {

        //Draw bars

        for ($i = 0; $i < strlen($code); $i++) {
            if ($code[$i] == '1')
                $this->Rect($x + $i * $w, $y, $w, $h, 'F');
        }
    }

    //End of class
}

//Handle special IE contype request
if (isset($_SERVER['HTTP_USER_AGENT']) && $_SERVER['HTTP_USER_AGENT'] == 'contype') {
    header('Content-Type: application/pdf');
    exit;
}