2009-08-16 3 views
12

Есть ли у кого-нибудь простой способ рассчитать, сколько точек на странице кусочек текста будет потребляться в определенном шрифте и размере? (легко = минимальные строки кода + вычислительно дешево). Zend_Pdf не имеет функции, которая делает это, за исключением некоторых очень дорогих вызовов для каждого символа getGlyphForCharacter(), getUnitsPerEm() и getWidthsForGlyph().Zend_Pdf вычисление длины текстовой строки в текущем шрифте для обертки строк

Я создаю многостраничный PDF-файл с несколькими таблицами на каждой странице и должен обернуть текст внутри столбцов. Для его создания уже несколько секунд, и я не хочу, чтобы он занимал слишком много времени, или мне придется начинать возиться с фоновыми задачами или полосами прогресса и т. Д.

Единственное решение, с которым я столкнулся, предварительно вычисляет ширину (в точках) каждого символа в каждом используемом размере шрифта, а затем добавляет их поверх каждой строки. Все еще довольно дорого.

Я что-то не хватает? Или у вас есть что-то более простое?

спасибо!

ответ

27

Существует способ расчета ширины точно, вместо использования Gorilla3D's worst case algorithm.

Попробуйте этот код из http://devzone.zend.com/article/2525-Zend_Pdf-tutorial#comments-2535

Я использовал его в моем приложении для вычисления смещения для правого выровнен текста и работает

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

Что касается производительности, я не использовал этот интенсивно в сценарии, но я могу представить, что это медленно. Я бы предложил написать PDF-файлы на диск, если это возможно, так что повторение представлений происходит очень быстро и, где это возможно, кеширование/жесткое кодирование.

+0

Я тоже использовал это. Работает как рекламируется. – jason

+0

это хорошо выглядит. У меня есть фиксированный словарный запас около 200 фраз, поэтому можно использовать приведенный выше код (слегка адаптированный) для прекомпопуляции и кэширования слов, завернутых в строки. PDF создается только один раз (при первом просмотре), а затем кэшируется. Это должно привести к почти не ухудшению производительности и некоторому более приятному форматированию. Спасибо за вашу помощь! – Steve

0

Мышление над этим немного больше. Возьмите самые широкие шрифты шрифта, который вы используете, и основываетесь на этом как ширина для каждого символа. Он не будет точным, но это предотвратит нажатие текста за меткой.

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