Search code examples
textannotationsboundsboundarypdftron

PDFTron: How to figure out if text is overflowing its bouding box


I have made a PDF-document with multiline text fields. I'd like to know how I could check if the text is overflowing its bounds.

TextWidget::GetVisibleContentBox()

and

TextWidget::GetRect()

both seem to get the same Rect

Ok. Here's my slightly modified function for figuring out if a text field if overflowing. Took part of the logic from TCPDF:

function isTextWidgetOverflowing (PDFTron\TextWidget $annot, float $leading = 9.6) {
    $text = $annot->GetText();

    /** @var PDFTron\Font */
    $font = $annot->GetFont();

    /** @var PDFTron\Rect */
    $rect = $annot->GetRect();

    $length = strlen($text);

    $rectW = $rect->Width();

    $lastSeparator = -1;
    $lines = 1;
    $sum = 0;

    for ($index = 0; $index < $length; $index++) {
        $character = $text[$index];
        $charCode = mb_ord($character);

        if (!($chW = $font->GetWidth($charCode))) {
            $chW = $font->GetMissingWidth();
        }

        $chW /= 1000.0;

        if (($charCode !== 160)
                && (($charCode === 173)
                || preg_match('/[^\S\xa0]/', $character)
                || (($charCode === 45)
                    && ($index > 0) && ($index < ($length - 1))
                    && @preg_match('/[\p{L}]/', $text[$index - 1])
                    && @preg_match('/[\p{L}]/', $text[$index + 1])
                )
            )
        ) {
            $lastSeparator = $index;
        }

        if ((($sum + $chW) > $rectW) || ($charCode === 10)) {
            ++$lines;

            if ($charCode === 10) {
                $lastSeparator = -1;
                $sum = 0;
            } else if ($lastSeparator !== -1) {
                $index = $lastSeparator;
                $lastSeparator = -1;
                $sum = 0;
            } else {
                $sum = $chW;
            }
        } else {
            $sum += $chW;
        }
    }

    if (mb_ord($text[$length - 1]) === 10) {
        --$lines;
    }

    return ($lines * $leading) > $rect->Height();
}

The $chW is most likely a bit wrong. Maybe I'd need to take into account the line spacing and font stretching. Where could these be found?

Also instead of hard-coding the $leading would be nice if I could somehow grab it of the PDF-document.


Solution

  • Here's a working solution to determining if a Text Widget has overflowing text. The only thing I'd like to change is not relying on a parameter for the leading.

    function isTextWidgetOverflowing(PDFTron\TextWidget $annot, float $leading = 9.6) {
        $text = $annot->GetText();
    
        /** @var PDFTron\Font */
        $font = $annot->GetFont();
    
        $fontSize = $annot->GetFontSize();
    
        /** @var PDFTron\Rect */
        $rect = $annot->GetRect();
    
        $length = strlen($text);
    
        $rectW = $rect->Width();
    
        $lastSeparator = -1;
        $lines = 1;
        $sum = 0;
    
        for ($index = 0; $index < $length; $index++) {
            $char = $text[$index];
            $charCode = mb_ord($char);
    
            if (!($chW = $font->GetWidth($charCode))) {
                $chW = $font->GetMissingWidth();
            }
    
            $chW /= (1000.0 / $fontSize);
    
            if (($charCode !== 160)
                && (($charCode === 173)
                    || preg_match('/[^\S\xa0]/', $char)
                    || (($charCode === 45)
                        && ($index > 0) && ($index < ($length - 1))
                        && preg_match('/[\p{L}]/', $text[$index - 1])
                        && preg_match('/[\p{L}]/', $text[$index + 1])))
            ) {
                $lastSeparator = $index;
            }
    
            if ((($sum + $chW) > $rectW) || ($charCode === 10)) {
                ++$lines;
    
                if ($charCode === 10) {
                    $lastSeparator = -1;
                    $sum = 0;
                } else if ($lastSeparator !== -1) {
                    $index = $lastSeparator;
                    $lastSeparator = -1;
                    $sum = 0;
                } else {
                    $sum = $chW;
                }
            } else {
                $sum += $chW;
            }
        }
    
        if (mb_ord($text[$length - 1]) === 10) {
            --$lines;
        }
    
        return ($lines * $leading) > $rect->Height();
    }