Search code examples
phptextcolorsimagick

How can I change the color of a specific word using Imagick in PHP?


I'm currently using annotateImage to add some text to an image.

/* Black text */
$draw->setFillColor('black');

/* Font properties */
$draw->setFont('Bookman-DemiItalic');
$draw->setFontSize( 30 );

$image->annotateImage($draw, 10, 45, 0, 'The fox jumped over the lazy dog');

This currently displays all the text in black. I'm looking for a way to change the color of the word fox to red, but I'm out of ideas.

How can I achieve this?


Solution

  • As suggested by Danack's comment, here's my solution if anyone needs it. The parseText function looks for <span> tags with the attributes, color, font, size and returns an array.

    The <span color="red">fox</span> jumped over the lazy <span color="green">dog</span>.
    

    In the above text, the word fox will have a color=red attribute, and dog will have color=green.

    Using the array, we can draw the regular text, track the positioning and draw the stylized texts as well.

    function parseText($txt) {
      if ( strstr($txt, '<span') ) {
        $txt = preg_split('@(<span(?:\\\?.)*?>(?:\\\?.)*?</span>)@', $txt, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
        $arr = array();
        foreach ( $txt as $t ) {
          if ( strstr($t, '<span') ) {
            $tag = array();
            preg_match('@<span\s*((?:\\\?.)*?)\s*>((?:\\\?.)*?)</span>@', $t, $m);
            $attrs = $m[1];
            $inner = $m[2];
            if ( $attrs ) {
              $attrs = preg_split('@((?:\\\?.)*?=["\'](?:\\\?.)*?["\'])\s*@', $attrs, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
              foreach ( $attrs as $a ) {
                $a = explode('=', $a);
                $tag[ $a[0] ] = trim($a[1], '"\'');
              }
            }
            $tag['text'] = $inner;
            $arr[] = $tag;
          } else {
            $arr[] = array( 'text' => $t );
          }
          $txt = $arr;
        }
      }
      return $txt;
    }
    
    function newStyle($image, $draw, $t, &$width) {
      if ( $t['color'] )  $draw->setFillColor($t['color']);
      if ( $t['size']  )  $draw->setFontSize($t['size']);
      if ( $t['font']  )  $draw->setFont($t['font']);
      $metrics = $image->queryFontMetrics($draw, $t['text'], FALSE);
      $width = $metrics['textWidth'];
    }
    
    // To use it
    
    function defaultStyle($draw) {
      $draw->setFillColor('black');
      $draw->setFont('Bookman-DemiItalic');
      $draw->setFontSize(20);
    }
    
    defaultStyle($draw);
    
    $txt = 'The <span color="red">fox</span> jumped over the lazy <span color="green">dog</span>.';
    $x = 45;
    $y = 45;
    $txt = parseText($txt);
    if ( is_array($txt) ) {
      foreach ( $txt as $t ) {
        defaultStyle($draw);
        newStyle($image, $draw, $t, $width);
        $image->annotateImage($draw, $x, $y, 0, $t['text']);
        $x += $width;
      }
    } else {
      $image->annotateImage($draw, $x, $y, 0, $txt);
    }