views:

315

answers:

2

Hi,

I am generating a PDF with fPDF.

I need to strikethrough a long text inside a MultiCell. The text is justified to left and right, which probably is the source of the problem.

Here is my code:

//get the starting x and y of the cell to strikeout
$strikeout_y_start = $pdf->GetY();
$strikeout_x = $pdf->getX();
$strikeText = "Some text with no New Lines (\n), which is wrapped automaticly, cause it is  very very very very very very very very very very long long long long long long long long long long long long long long long long long long"
//draw the text
$pdf->MultiCell(180, 4, $strikeText);
//get the y end of cell
$strikeout_y_end = $pdf->GetY();
$strikeout_y = $strikeout_y_start+2;
$strikeCount = 0;
for ($strikeout_y; $strikeout_y < $strikeout_y_end - 4; $strikeout_y+=4) {
    $strikeCount++;
    //strike out the full width of all lines but last one - works OK
    $pdf->Line($strikeout_x, $strikeout_y, $strikeout_x + 180, $strikeout_y);
}

//this works, but gives incorrect results
$width = $pdf->GetStringWidth($strikeText);
$width = $width - $strikeCount*180;
//the line below will strike out some text, but not all the letters of last line
$pdf->line($strikeout_x, $strikeout_y, $strikeout_x+$width, $strikeout_y);

The problem is that as the text in multicell is justified (and have to be), the spacec in previous lines are wider than the GetStringWidth assumes, so GetStringWidth underestimates the full width of this text.

As a result, the last line is stroked out in, say, 70%, and some letters on the end of it are not stroked out.

Any ideas how to calculate the width of last line in multicell?

A: 

Hi,

I found the solution myself. Sorry for asking unnecessary questions.

Here is what I had done:

class VeraPDF extends FPDF {

    /**
     * Returns width of the last line in a multicell
     * useful for strike out / strike through 
     * 
     *
     * @param string $s - the string measured
     * @param int $lineWidth - with of the cell/line
     * @return int
     */
    function GetStringWidth_JustifiedLastLineWidth($s, $lineWidth)
    {
        //Get width of a string in the current font
        $s=(string)$s;
        $words = split(' ',$s);
        $cw=&$this->CurrentFont['cw'];
        $w=0;
        $spaceWidth = $this->GetStringWidth(' ');

        for($i=0, $wordsCount = count($words); $i<$wordsCount; $i++){
            // sum up all the words width, and add space withs between the words
            $w += $this->GetStringWidth($words[$i]) + $spaceWidth;
            if ($w > $lineWidth) {
                //if current width is more than the line width, then the current word
                //will be moved to next line, we need to count it again
                $i--;
            }
            if ($w >= $lineWidth) {
                //if the current width is equal or grater than the line width, 
                //we need to reset current width, and count the width of remaining text
                $w = 0;
            }
        }
        //at last, we have only the width of the text that remain on the last line!
        return $w;
    }    
}

Hope this helped someone :)

SWilk
sorry for answering myself. I had an idea how to solve it just after I had posted a question here
SWilk
A: 

the spacec in previous lines are wider than the GetStringWidth assumes, so GetStringWidth underestimates the full width of this text.

Have you tried to count the spaces and add the missing width yourself. Say every space is supposed to be 5px wide, but fpdf etimates it to be 4px, maybe you could add 1px per space to the total width in the end.

Sebastian
Thanks for the answer. Actually fpdf counts space width as it is defined in the current font. But when text is wrapped and justified, the spaces "grows" to take the space fried by the word which was moved to the next line when line was filled to its end. I had just posted a solution to this, and it is based on the rule that you need to count wrapped words twice, and totally ignore the fully filled lines.
SWilk