Pull to refresh

Пишем на картинках

PHP *
В течение последнего времени что-то часто стали мелькать статьи про обработку изображений на php. Скругленные края уже были, тени были, мокрый пол был, еще куча всего было.

А вот надписей вроде еще не было. Значит будут. :-)

Представляю вашему вниманию не большой, но в тоже время достаточно богатый возможностями класс (на основе GD) написания текста на картинках TrueType-шрифтами.

Код класса:


<?php

class ttfTextOnImage
{  
  // Качество jpg по-умолчанияю
  public   $jpegQuality = 100;      
  
  // Каталог шрифтов
  public   $ttfFontDir   = 'ttf';  
  
  private $ttfFont    = false;
  private $ttfFontSize  = false;
    
  private $hImage      = false;
  private $hColor      = false;

  public function __construct($imagePath)
  {
    if (!is_file($imagePath) || !list(,,$type) = @getimagesize($imagePath)) return false;
        
    switch ($type)
    {      
      case 1:  $this->hImage = @imagecreatefromgif($imagePath);  break;
      case 2:  $this->hImage = @imagecreatefromjpeg($imagePath);  break;
      case 3:  $this->hImage = @imagecreatefrompng($imagePath);  break;        
      default: $this->hImage = false;
    }
  }
  
  public function __destruct()
  {
    if ($this->hImage) imagedestroy($this->hImage);
  }
  
  /**
   * Устанавливает шрифт
   *
   */  
  public function setFont($font, $size = 14, $color = false, $alpha = false)
  {
    if (!is_file($font) && !is_file($font = $this->ttfFontDir.'/'.$font))
    return false;
    
    $this->ttfFont     = $font;
    $this->ttfFontSize   = $size;
    
    if ($color) $this->setColor($color, $alpha);
  }
  
  /**
   * Пишет текст
   *
   */    
  public function writeText ($x, $y, $text, $angle = 0)
  {
    if (!$this->ttfFont || !$this->hImage || !$this->hColor) return false;
    
    imagettftext(
      $this->hImage,
      $this->ttfFontSize, $angle, $x, $y + $this->ttfFontSize,
      $this->hColor, $this->ttfFont, $text);  
  }
  
  /**
   * Форматирует текст (согласно текущему установленному шрифту),
   * что бы он не вылезал за рамки ($bWidth, $bHeight)
   * Убирает слишком длинные слова
   */
  public function textFormat($bWidth, $bHeight, $text)
  {
    // Если в строке есть длинные слова, разбиваем их на более короткие
    // Разбиваем текст по строкам
    
    $strings   = explode("\n",
      preg_replace('!([^\s]{24})[^\s]!su', '\\1 ',
        str_replace(array("\r", "\t"),array("\n", ' '), $text)));        
        
    $textOut   = array(0 => '');
    $i = 0;
          
    foreach ($strings as $str)
    {
      // Уничтожаем совокупности пробелов, разбиваем по словам
      $words = array_filter(explode(' ', $str));
      
      foreach ($words as $word)
      {
        // Какие параметры у текста в строке?
        $sizes = imagettfbbox($this->ttfFontSize, 0, $this->ttfFont, $textOut[$i].$word.' ');  
        
        // Если размер линии превышает заданный, принудительно
        // перескакиваем на следующую строку
        // Иначе пишем на этой же строке
        if ($sizes[2] > $bWidth) $textOut[++$i] = $word.' '; else $textOut[$i].= $word.' ';
        
        // Если вышли за границы текста по вертикали, то заканчиваем
        if ($i*$this->ttfFontSize >= $bHeight) break(2);
      }
      
      // "Естественный" переход на новую строку
      $textOut[++$i] = ''; if ($i*$this->ttfFontSize >= $bHeight) break;
    }
    
    return implode ("\n", $textOut);
  }
  
  /**
   * Устанваливет цвет вида #34dc12
   *
   */
  public function setColor($color, $alpha = false)
  {
    if (!$this->hImage) return false;
    
    list($r, $g, $b) = array_map('hexdec', str_split(ltrim($color, '#'), 2));
    
    return $alpha === false ?
      $this->hColor = imagecolorallocate($this->hImage, $r+1, $g+1, $b+1) :
      $this->hColor = imagecolorallocatealpha($this->hImage, $r+1, $g+1, $b+1, $alpha);    
  }
  
  /**
   * Выводит картинку в файл. Тип вывода определяется из расширения.
   *
   */
  public function output ($target, $replace = true)
  {
    if (is_file ($target) && !$replace) return false;
      
    $ext = strtolower(substr($target, strrpos($target, ".") + 1));    

    switch ($ext)
    {
      case "gif":        
        imagegif ($this->hImage, $target);        
        break;
                
      case "jpg" :
      case "jpeg":
        imagejpeg($this->hImage, $target, $this->jpegQuality);        
        break;
        
      case "png":
        imagepng($this->hImage, $target);
        break;
        
      defaultreturn false;
    }
    return true;     
  }
}
?>


* This source code was highlighted with Source Code Highlighter.


Что он умеет, думаю разобраться не сложно, тем более что комментарии есть. Теперь пример использования:

// Берем какую-нибудь картинку
$ttfImg = new ttfTextOnImage('images/hlwn.jpg');
      
// Пишем шрифтом Scrawn размером 64 пункта бордовым цветом с 80%-ой прозрачностью
$ttfImg->setFont('files/fonts/scra.ttf', 64, "#800000", 80);      
$ttfImg->writeText(40, 570, "Happy halloween!");

// Шрифтом Constantin размером 15 пунктов оранжевым цветом с 90%-ой прозрачностью
$ttfImg->setFont('files/fonts/constan.ttf', 15, "#ff8200", 90);      

// Хотим написать много, поэтому сначала отформатируем наш текст
$message = $ttfImg->textFormat(400, 500,
"Хеллоуин (англ. Halloween) — преимущественно американский праздник, празднуется в ночь с 31 октября на 1 ноября.

Также упоминается как «канун Дня всех святых». Праздник корнями уходит к старинному кельтскому празднеству Самайн."
);

// Пишем (чуть-чуть наклоним)
$ttfImg->writeText(40, 100, $message, 5);

// и вывод в файл
$ttfImg->output('images/postcard.jpg');


* This source code was highlighted with Source Code Highlighter.


Ну собственно и результат:



Ну и на последок возможности применения:
1. Написать что-нибудь на картинке (подпись свою например)
2. Делать «гламурные заголовки» — когда некоторые тексты делаются красивыми картинками (в вордпрессе такое есть вроде)
3. CAPТCHA (просто нужно взять совершенно е**нутый шрифт)

Пользуйтесь на здоровье!

PS: Расчитано на кодировку UTF-8
Tags:
Hubs:
Total votes 104: ↑88 and ↓16 +72
Views 14K
Comments Comments 36