2009-08-16 11 views
12

Est-ce que quelqu'un a un moyen facile de calculer combien de points sur une page un texte va consommer dans une police et une taille particulière? (facile = lignes minimales de code + informatiquement bon marché). Zend_Pdf ne semble pas avoir une fonction qui fait cela, à part quelques appels très coûteux pour que chaque caractère obtienneGlyphForCharacter(), getUnitsPerEm() et getWidthsForGlyph().Zend_Pdf calculer la longueur de la chaîne de caractères dans la police courante pour l'enroulement de ligne

Je génère un PDF multi-pages avec plusieurs tableaux sur chaque page, et j'ai besoin d'envelopper le texte dans les colonnes. Cela prend déjà quelques secondes pour le créer, et je ne veux pas qu'il prenne trop de temps ou je vais devoir commencer à jouer avec des tâches de fond ou des barres de progression, etc.

La seule solution que j'ai trouvée pré-calcule la largeur (en points) de chaque caractère dans chaque taille de police utilisée, puis les additionne sur chaque chaîne. Encore assez cher.

Ai-je raté quelque chose? Ou avez-vous quelque chose de plus simple?

merci!

Répondre

27

Il existe un moyen de calculer des largeurs exactement, plutôt que d'utiliser Gorilla3D's worst case algorithm.

Essayez ce code de http://devzone.zend.com/article/2525-Zend_Pdf-tutorial#comments-2535

Je l'ai utilisé dans mon application pour le calcul des compensations pour le texte aligné à droite et il fonctionne

/** 
* 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; 
} 

En ce qui concerne les performances, je ne l'ai pas utilisé cette intensivement dans un script mais je peux imaginer que c'est lent. Je suggère d'écrire les fichiers PDF sur disque, si possible, de sorte que les vues répétées soient très rapides, et que les données de mise en cache/codage dur soient si possible disponibles.

+0

Je l'ai aussi utilisé. Fonctionne comme annoncé. – jason

+0

qui a l'air bien. J'ai un vocabulaire fixe d'environ 200 phrases, donc pourrait utiliser le code ci-dessus (légèrement adapté) pour précalculer et mettre en cache les chaînes de mots enveloppés. Le pdf est généré une seule fois (à la première visualisation) et ensuite mis en cache. Cela devrait se traduire par presque aucune pénalité de performance et un formatage beaucoup plus agréable. Merci de votre aide! – Steve

0

Penser à cela un peu plus. Prenez les plus larges glyphes de la police que vous utilisez et en fonction de la largeur de chaque caractère. Ce ne sera pas précis mais cela empêchera de pousser le texte au-delà de la marque.

$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); 
Questions connexes