Flowing block

This script allows writing text in a block in much the same way the Write function works

Informations

Author: Damon Kohler
License: GPL

Description

This script allows writing text in a block in much the same way the Write function works. The block is defined in a manner similar to MultiCell (width, line height, border, alignment and filling color). It is possible to add content with WriteFlowingBlock and change font attributes (SetFont and SetFontSize) between two calls.
Changes in text color are not supported; however, such a change could be easily added.

This was written as part of the phpFOP project.

Source

<?php require('fpdf.php'); class PDF_FlowingBlock extends FPDF { var $flowingBlockAttr; function saveFont() { $saved = array(); $saved[ 'family' ] = $this->FontFamily; $saved[ 'style' ] = $this->FontStyle; $saved[ 'sizePt' ] = $this->FontSizePt; $saved[ 'size' ] = $this->FontSize; $saved[ 'curr' ] =& $this->CurrentFont; return $saved; } function restoreFont( $saved ) { $this->FontFamily = $saved[ 'family' ]; $this->FontStyle = $saved[ 'style' ]; $this->FontSizePt = $saved[ 'sizePt' ]; $this->FontSize = $saved[ 'size' ]; $this->CurrentFont =& $saved[ 'curr' ]; if( $this->page > 0) $this->_out( sprintf( 'BT /F%d %.2F Tf ET', $this->CurrentFont[ 'i' ], $this->FontSizePt ) ); } function newFlowingBlock( $w, $h, $b = 0, $a = 'J', $f = 0 ) { // cell width in points $this->flowingBlockAttr[ 'width' ] = $w * $this->k; // line height in user units $this->flowingBlockAttr[ 'height' ] = $h; $this->flowingBlockAttr[ 'lineCount' ] = 0; $this->flowingBlockAttr[ 'border' ] = $b; $this->flowingBlockAttr[ 'align' ] = $a; $this->flowingBlockAttr[ 'fill' ] = $f; $this->flowingBlockAttr[ 'font' ] = array(); $this->flowingBlockAttr[ 'content' ] = array(); $this->flowingBlockAttr[ 'contentWidth' ] = 0; } function finishFlowingBlock() { $maxWidth =& $this->flowingBlockAttr[ 'width' ]; $lineHeight =& $this->flowingBlockAttr[ 'height' ]; $border =& $this->flowingBlockAttr[ 'border' ]; $align =& $this->flowingBlockAttr[ 'align' ]; $fill =& $this->flowingBlockAttr[ 'fill' ]; $content =& $this->flowingBlockAttr[ 'content' ]; $font =& $this->flowingBlockAttr[ 'font' ]; // set normal spacing $this->_out( sprintf( '%.3F Tw', 0 ) ); // print out each chunk // the amount of space taken up so far in user units $usedWidth = 0; foreach ( $content as $k => $chunk ) { $b = ''; if ( is_int( strpos( $border, 'B' ) ) ) $b .= 'B'; if ( $k == 0 && is_int( strpos( $border, 'L' ) ) ) $b .= 'L'; if ( $k == count( $content ) - 1 && is_int( strpos( $border, 'R' ) ) ) $b .= 'R'; $this->restoreFont( $font[ $k ] ); // if it's the last chunk of this line, move to the next line after if ( $k == count( $content ) - 1 ) $this->Cell( ( $maxWidth / $this->k ) - $usedWidth + 2 * $this->cMargin, $lineHeight, $chunk, $b, 1, $align, $fill ); else $this->Cell( $this->GetStringWidth( $chunk ), $lineHeight, $chunk, $b, 0, $align, $fill ); $usedWidth += $this->GetStringWidth( $chunk ); } } function WriteFlowingBlock( $s ) { // width of all the content so far in points $contentWidth =& $this->flowingBlockAttr[ 'contentWidth' ]; // cell width in points $maxWidth =& $this->flowingBlockAttr[ 'width' ]; $lineCount =& $this->flowingBlockAttr[ 'lineCount' ]; // line height in user units $lineHeight =& $this->flowingBlockAttr[ 'height' ]; $border =& $this->flowingBlockAttr[ 'border' ]; $align =& $this->flowingBlockAttr[ 'align' ]; $fill =& $this->flowingBlockAttr[ 'fill' ]; $content =& $this->flowingBlockAttr[ 'content' ]; $font =& $this->flowingBlockAttr[ 'font' ]; $font[] = $this->saveFont(); $content[] = ''; $currContent =& $content[ count( $content ) - 1 ]; // where the line should be cutoff if it is to be justified $cutoffWidth = $contentWidth; // for every character in the string for ( $i = 0; $i < strlen( $s ); $i++ ) { // extract the current character $c = $s[ $i ]; // get the width of the character in points $cw = $this->CurrentFont[ 'cw' ][ $c ] * ( $this->FontSizePt / 1000 ); if ( $c == ' ' ) { $currContent .= ' '; $cutoffWidth = $contentWidth; $contentWidth += $cw; continue; } // try adding another char if ( $contentWidth + $cw > $maxWidth ) { // won't fit, output what we have $lineCount++; // contains any content that didn't make it into this print $savedContent = ''; $savedFont = array(); // first, cut off and save any partial words at the end of the string $words = explode( ' ', $currContent ); // if it looks like we didn't finish any words for this chunk if ( count( $words ) == 1 ) { // save and crop off the content currently on the stack $savedContent = array_pop( $content ); $savedFont = array_pop( $font ); // trim any trailing spaces off the last bit of content $currContent =& $content[ count( $content ) - 1 ]; $currContent = rtrim( $currContent ); } // otherwise, we need to find which bit to cut off else { $lastContent = ''; for ( $w = 0; $w < count( $words ) - 1; $w++) $lastContent .= "{$words[ $w ]} "; $savedContent = $words[ count( $words ) - 1 ]; $savedFont = $this->saveFont(); // replace the current content with the cropped version $currContent = rtrim( $lastContent ); } // update $contentWidth and $cutoffWidth since they changed with cropping $contentWidth = 0; foreach ( $content as $k => $chunk ) { $this->restoreFont( $font[ $k ] ); $contentWidth += $this->GetStringWidth( $chunk ) * $this->k; } $cutoffWidth = $contentWidth; // if it's justified, we need to find the char spacing if( $align == 'J' ) { // count how many spaces there are in the entire content string $numSpaces = 0; foreach ( $content as $chunk ) $numSpaces += substr_count( $chunk, ' ' ); // if there's more than one space, find word spacing in points if ( $numSpaces > 0 ) $this->ws = ( $maxWidth - $cutoffWidth ) / $numSpaces; else $this->ws = 0; $this->_out( sprintf( '%.3F Tw', $this->ws ) ); } // otherwise, we want normal spacing else $this->_out( sprintf( '%.3F Tw', 0 ) ); // print out each chunk $usedWidth = 0; foreach ( $content as $k => $chunk ) { $this->restoreFont( $font[ $k ] ); $stringWidth = $this->GetStringWidth( $chunk ) + ( $this->ws * substr_count( $chunk, ' ' ) / $this->k ); // determine which borders should be used $b = ''; if ( $lineCount == 1 && is_int( strpos( $border, 'T' ) ) ) $b .= 'T'; if ( $k == 0 && is_int( strpos( $border, 'L' ) ) ) $b .= 'L'; if ( $k == count( $content ) - 1 && is_int( strpos( $border, 'R' ) ) ) $b .= 'R'; // if it's the last chunk of this line, move to the next line after if ( $k == count( $content ) - 1 ) $this->Cell( ( $maxWidth / $this->k ) - $usedWidth + 2 * $this->cMargin, $lineHeight, $chunk, $b, 1, $align, $fill ); else { $this->Cell( $stringWidth + 2 * $this->cMargin, $lineHeight, $chunk, $b, 0, $align, $fill ); $this->x -= 2 * $this->cMargin; } $usedWidth += $stringWidth; } // move on to the next line, reset variables, tack on saved content and current char $this->restoreFont( $savedFont ); $font = array( $savedFont ); $content = array( $savedContent . $s[ $i ] ); $currContent =& $content[ 0 ]; $contentWidth = $this->GetStringWidth( $currContent ) * $this->k; $cutoffWidth = $contentWidth; } // another character will fit, so add it on else { $contentWidth += $cw; $currContent .= $s[ $i ]; } } } } ?>

Example

This example outputs the same text with the four possible alignments (justified, left-aligned, right-aligned and centered).
<?php require('flowing_block.php'); $pdf = new PDF_FlowingBlock(); $pdf->AddPage(); $pdf->newFlowingBlock( 40, 6, 'TBLR', 'J' ); $pdf->SetFont( 'Arial', 'B', 16 ); $pdf->WriteFlowingBlock( 'Hello ' ); $pdf->SetFont( 'Arial', 'I', 8 ); $pdf->WriteFlowingBlock( 'World! ' ); $pdf->SetFont( 'Times', '', 10 ); $pdf->WriteFlowingBlock( 'This is a test of the flowing block script.' ); $pdf->SetFont( 'Arial', 'B', 12 ); $pdf->WriteFlowingBlock( ' All' ); $pdf->SetFont( 'Times', '', 10 ); $pdf->WriteFlowingBlock( ' of this should be justified correctly.' . str_repeat( ' This is a test of the flowing block script.', 3 ) ); $pdf->finishFlowingBlock(); $pdf->AddPage(); $pdf->newFlowingBlock( 40, 6, 'TBLR', 'L' ); $pdf->SetFont( 'Arial', 'B', 16 ); $pdf->WriteFlowingBlock( 'Hello ' ); $pdf->SetFont( 'Arial', 'I', 8 ); $pdf->WriteFlowingBlock( 'World! ' ); $pdf->SetFont( 'Times', '', 10 ); $pdf->WriteFlowingBlock( 'This is a test of the flowing block script.' ); $pdf->SetFont( 'Arial', 'B', 12 ); $pdf->WriteFlowingBlock( ' All' ); $pdf->SetFont( 'Times', '', 10 ); $pdf->WriteFlowingBlock( ' of this should be justified correctly.' . str_repeat( ' This is a test of the flowing block script.', 3 ) ); $pdf->finishFlowingBlock(); $pdf->AddPage(); $pdf->newFlowingBlock( 40, 6, 'TBLR', 'R' ); $pdf->SetFont( 'Arial', 'B', 16 ); $pdf->WriteFlowingBlock( 'Hello ' ); $pdf->SetFont( 'Arial', 'I', 8 ); $pdf->WriteFlowingBlock( 'World! ' ); $pdf->SetFont( 'Times', '', 10 ); $pdf->WriteFlowingBlock( 'This is a test of the flowing block script.' ); $pdf->SetFont( 'Arial', 'B', 12 ); $pdf->WriteFlowingBlock( ' All' ); $pdf->SetFont( 'Times', '', 10 ); $pdf->WriteFlowingBlock( ' of this should be justified correctly.' . str_repeat( ' This is a test of the flowing block script.', 3 ) ); $pdf->finishFlowingBlock(); $pdf->AddPage(); $pdf->newFlowingBlock( 40, 6, 'TBLR', 'C' ); $pdf->SetFont( 'Arial', 'B', 16 ); $pdf->WriteFlowingBlock( 'Hello ' ); $pdf->SetFont( 'Arial', 'I', 8 ); $pdf->WriteFlowingBlock( 'World! ' ); $pdf->SetFont( 'Times', '', 10 ); $pdf->WriteFlowingBlock( 'This is a test of the flowing block script.' ); $pdf->SetFont( 'Arial', 'B', 12 ); $pdf->WriteFlowingBlock( ' All' ); $pdf->SetFont( 'Times', '', 10 ); $pdf->WriteFlowingBlock( ' of this should be justified correctly.' . str_repeat( ' This is a test of the flowing block script.', 3 ) ); $pdf->finishFlowingBlock(); $pdf->Output(); ?>
View the result here.

Download

ZIP | TGZ

Quelle

http://www.fpdf.org/en/script/script65.php, zuletzt abgerufen 30.03.2016 02:54