2009-08-16 11 views
12

Czy ktoś ma łatwy sposób na obliczenie, ile punktów na stronie tekst zużyje w określonej czcionce i rozmiarze? (easy = minimalne linie kodu + obliczeniowo tanie). Zend_Pdf nie ma funkcji, która to robi, z wyjątkiem kilku bardzo kosztownych wywołań dla każdego znaku, aby uzyskaćGlyphForCharacter(), getUnitsPerEm() i getWidthsForGlyph().Zend_Pdf obliczanie długości ciągu tekstowego w aktualnej czcionce do zawijania linii

Generuję wielostronicowy plik PDF z kilkoma tabelami na każdej stronie i muszę zawinąć tekst w kolumnach. Utworzenie go zajmuje już kilka sekund i nie chcę, aby trwało to dłużej, bo inaczej zacznę się bawić z zadaniami tła lub pasków postępu itp.

Jedyne rozwiązanie, które wymyśliłem to wstępne obliczanie szerokości (w punktach) każdego znaku w każdej używanej wielkości czcionki, a następnie dodawanie ich do każdego ciągu. Nadal dość kosztowne.

Czy brakuje mi czegoś? Czy masz coś prostszego?

dziękuję!

Odpowiedz

27

Istnieje sposób, aby obliczyć szerokość dokładnie, zamiast Gorilla3D's worst case algorithm.

Spróbuj kod z http://devzone.zend.com/article/2525-Zend_Pdf-tutorial#comments-2535

Używałem go w mojej aplikacji do obliczenia przesunięcia na tekst wyrównany do prawej i działa

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

w odniesieniu do wydajności, nie użyłem tego intensywnie w scenariuszu, ale mogę sobie wyobrazić, że jest powolny. Sugerowałbym napisanie plików PDF na dysk, jeśli to możliwe, aby powtórzyć poglądy są bardzo szybkie, a buforowanie/trudne kodowanie danych tam, gdzie to możliwe.

+0

Użyłem tego również. Działa jak w reklamie. – jason

+0

który wygląda dobrze. Mam stały słownik zawierający około 200 fraz, więc mógłbym użyć powyższego kodu (nieco zaadaptowanego) do wstępnego skompresowania i buforowania zawijanych napisów. Plik PDF jest generowany tylko raz (przy pierwszym przeglądaniu), a następnie zapisywany w pamięci podręcznej. Powinno to spowodować prawie zerową obniżkę wydajności i znacznie ładniejsze formatowanie. Dzięki za pomoc! – Steve

0

Myślenie o tym trochę więcej. Pobierz najszersze glify czcionki, z których korzystasz, i określ je jako szerokość dla każdej postaci. Nie będzie to dokładne, ale zapobiegnie przesunięciu tekstu poza znak.

$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); 
Powiązane problemy