text2image: чего не хватает в стандартной imageTtfText?
Всё выросло из банальной задачи: показ на сайте большого количества надписей, набранных нестандартными шрифтами. Для решения этой задачи существуют множества различных подходов, например, популярны CSS и Flash решения. После некоторого перебора, мной был выбран подход text2image. На php в библиотеке GD уже есть отличное решение: imagefttext. Но у него есть один критичный для меня недостаток: нельзя задать выравнивание для многострочного текста. Поэтому функция imagefttext была расширена. И стало возможным получать такие картинки:
Реализация своего text2image
В качестве базиса взят стандартный функционал imagettftext, в свой метод были добавлены 3 дополнительных параметра: выравнивание текста и высота/ширина итоговой картинки. Ниже приведен код метода.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // 8 первых параметров совпадают с параметрами функции imagettftext function myimagettftext(&$image, $size, $angle, $left, $top, $color, $font, $text, $align, $width, $height) { // Текст разбивается на строки $text_lines = explode("\n", $text); // С левым выравниванием и однострочными текстами отлично справляется imagettftext if ($align == ALIGN_LEFT || count($text_lines) <= 1) { imagettftext($image, $size, $angle, $left, $top, $color, $font, $text); } else { $lines = array(); $line_widths = array(); $line_heights = array(); $line_ys = array(); $sum_height = 0; // Для каждой строки считаем её размеры foreach ($text_lines as $index => $block) { $dimensions = imagettfbbox($size, $angle, $font, $block); // Ширина строки $line_width = abs($dimensions[0]) + abs($dimensions[2]); // Высота строки $line_height = abs($dimensions[5]) + abs($dimensions[1]); // отступ по вертикали $line_y = abs($dimensions[5]); $lines[$index] = $block; $line_widths[$index] = $line_width; $line_heights[$index] = $line_height; $line_ys[$index] = $line_y; $sum_height += $line_height; } // Рассчитываем максимальную ширину строки $max_width = max($line_widths); $max_width = $max_width + floor(($width - $max_width) / 2); // Рассчитываем расстояние между строками $delta_h = floor(($height - $sum_height) / (count($lines) - 1)); $top_offset = 0; $left_offset = 0; foreach ($lines as $index => $line) { // В зависимости от выравнивания рассчитываем левый отступ if ($align == ALIGN_CENTER) { $left_offset = ($max_width - $line_widths[$index]) / 2; } elseif ($align == ALIGN_RIGHT) { $left_offset = ($max_width - $line_widths[$index]); } // Рисуем каждую строку отдельно imagettftext($image, $size, $angle, $left_offset - $left, $line_ys[$index] + $top_offset, $color, $font, $line); // Запоминаем отступ сверху для новой строки. $top_offset += (isset($line_heights[$index]) ? $line_heights[$index] : 0) + $delta_h; } } } |
Осталось используя эту функцию генерировать картинки на php. Скрипт на вход будет получать текст, шрифт, размер, выравнивание, а на выходе будет отдавать картинку (В общем text2image).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // Вычисляем размер картинки $bbox = imagettfbbox($inFontSize, 0, $inFontFile, $inText); $width = abs($bbox[0]) + abs($bbox[2]); $height = abs($bbox[5]) + abs($bbox[1]); $x = abs($bbox[0]); $y = abs($bbox[5]); // Создаем изображение header('Content-type: image/png'); $img = imagecreatetruecolor($width, $height); // Создаем цвет для текста $text_colour = imagecolorallocate($img, $redColor, $greenColor, $blueColor); $background = ImageColorAllocateAlpha($img, ($redColor == 255 ? 254 : $redColor + 1), ($greenColor == 255 ? 254 : $greenColor + 1), ($blueColor == 255 ? 254 : $blueColor + 1), 127); // задаем текст и прозрачный фон для картинки imagefill($img, 0, 0, $background); imagecolortransparent($img, $background); // Используя нашу функцию генерим картинку myimagettftext($img, $inFontSize, 0, $x, $y, $text_colour, $inFontFile, $inText, $inAlign, $width, $height); imageAlphaBlending($img, false); imageSaveAlpha($img, true); imagepng($img); // освобождаем ресурсы imagecolordeallocate($img, $text_colour); imagecolordeallocate($img, $background); imagedestroy($img); |
З.Ы.
Исходники примера лежат на ГитХабе. Очень жду комментариев. Для примера использовал шрифт BillMoney от Джефа Шрайбера.