2009-08-16 22 views
12

Qualcuno ha un modo semplice per calcolare quanti punti su una pagina consumano un pezzo di testo in un particolare tipo di carattere e dimensione? (facile = linee minime di codice + computazionalmente convenienti). Zend_Pdf non sembra avere una funzione che lo fa, ad eccezione di alcune chiamate molto costose per ogni personaggio a getGlyphForCharacter(), getUnitsPerEm() e getWidthsForGlyph().Zend_Pdf calcolo della lunghezza della stringa di testo nel carattere corrente per il ritorno a capo

Sto generando un PDF multipagina con più tabelle su ogni pagina e necessario avvolgere il testo all'interno delle colonne. Ci vogliono già alcuni secondi per crearlo e non voglio che duri troppo a lungo o dovrò iniziare a fare scherzi con le attività in background o le barre di avanzamento ecc.

L'unica soluzione che ho trovato è pre-calcolare la larghezza (in punti) di ciascun carattere in ogni dimensione di carattere utilizzata, quindi aggiungendoli sopra ogni stringa. Ancora piuttosto costoso.

mi sto perdendo qualcosa? O hai qualcosa di più semplice?

grazie!

risposta

27

C'è un modo per calcolare esattamente larghezze, piuttosto che utilizzare Gorilla3D's worst case algorithm.

Prova questo codice da http://devzone.zend.com/article/2525-Zend_Pdf-tutorial#comments-2535

ho usato nella mia applicazione per calcolare gli offset per il testo allineato a destra e funziona

/** 
* Returns the total width in points of the string using the specified font and 
* size. 
* 
* This is not the most efficient way to perform this calculation. I'm 
* concentrating optimization efforts on the upcoming layout manager class. 
* Similar calculations exist inside the layout manager class, but widths are 
* generally calculated only after determining line fragments. 
* 
* @link http://devzone.zend.com/article/2525-Zend_Pdf-tutorial#comments-2535 
* @param string $string 
* @param Zend_Pdf_Resource_Font $font 
* @param float $fontSize Font size in points 
* @return float 
*/ 
function widthForStringUsingFontSize($string, $font, $fontSize) 
{ 
    $drawingString = iconv('UTF-8', 'UTF-16BE//IGNORE', $string); 
    $characters = array(); 
    for ($i = 0; $i < strlen($drawingString); $i++) { 
     $characters[] = (ord($drawingString[$i++]) << 8) | ord($drawingString[$i]); 
    } 
    $glyphs = $font->glyphNumbersForCharacters($characters); 
    $widths = $font->widthsForGlyphs($glyphs); 
    $stringWidth = (array_sum($widths)/$font->getUnitsPerEm()) * $fontSize; 
    return $stringWidth; 
} 

Per quanto riguarda le prestazioni, non ho usato questo intensivamente in una sceneggiatura ma posso immaginare che sia lento. Suggerirei di scrivere i PDF su disco, se possibile, in modo che le visualizzazioni ripetute siano molto veloci e, ove possibile, i dati di memorizzazione nella cache/hard coding.

+0

Ho usato anche questo. Funziona come pubblicizzato. – jason

+0

sembra buono. Ho un vocabolario fisso di circa 200 frasi, quindi potrei usare il codice sopra (leggermente adattato) per precalcolare e mettere in cache le stringhe di parole avvolte. Il pdf viene generato solo una volta (alla prima visualizzazione) e poi anche nella cache. Ciò dovrebbe comportare quasi nessuna penalizzazione delle prestazioni e alcune formattazioni molto più belle. Grazie per l'aiuto! – Steve

0

Pensarci un po 'di più. Prendi i glifi più larghi del carattere che usi e lo basano come larghezza per ogni personaggio. Non sarà accurato ma impedirà di spingere il testo oltre il segno.

$pdf = new Zend_Pdf(); 
$font  = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_COURIER); 
$font_size = $pdf->getFontSize(); 


$letters = array(); 
foreach(range(0, 127) as $idx) 
{ 
    array_push($letters, chr($idx)); 
} 
$max_width = max($font->widthsForGlyphs($letters)); 

// Text wrapping settings 
$text_font_size = $max_width; // widest possible glyph 
$text_max_width = 238;  // 238px 

// Text wrapping calcs 
$posible_character_limit = round($text_max_width/$text_font_size); 
$text = wordwrap($text, $posible_character_limit, "@[email protected]"); 
$text = explode('@[email protected]', $text);