ImageAdapter::drawText() overhaul
authorMarcel Werk <burntime@woltlab.com>
Sat, 10 Jan 2015 22:50:04 +0000 (23:50 +0100)
committerMarcel Werk <burntime@woltlab.com>
Sat, 10 Jan 2015 22:50:04 +0000 (23:50 +0100)
Closes #1856
Closes #1857

wcfsetup/install/files/lib/system/image/adapter/GDImageAdapter.class.php
wcfsetup/install/files/lib/system/image/adapter/IImageAdapter.class.php
wcfsetup/install/files/lib/system/image/adapter/ImageAdapter.class.php
wcfsetup/install/files/lib/system/image/adapter/ImagickImageAdapter.class.php

index 5acc24b38c6df9b3b8cd060b09af5506e1fea013..54104bf544430cc0bd4eff0cfb291a09b68817fb 100644 (file)
@@ -50,12 +50,6 @@ class GDImageAdapter implements IImageAdapter {
         */
        protected $width = 0;
        
-       /**
-        * value of the font parameter of gd functions
-        * @var integer
-        */
-       const FONT = 3;
-       
        /**
         * @see \wcf\system\image\adapter\IImageAdapter::load()
         */
@@ -191,81 +185,73 @@ class GDImageAdapter implements IImageAdapter {
        /**
         * @see \wcf\system\image\adapter\IImageAdapter::drawText()
         */
-       public function drawText($string, $x, $y, $opacity) {
-               if (!StringUtil::isUTF8($string)) {
-                       // GD is buggy with UTF-8
-                       throw new SystemException("Only UTF-8 encoded text can be written onto images");
-               }
-               
-               // convert UTF-8 characters > 127 to their numeric representation, e.g. A -> &#65;
-               // todo: $string = mb_encode_numericentity($string, array(0x0, 0xFFFF, 0, 0xFFF), 'UTF-8');
-               
+       public function drawText($text, $x, $y, $font, $size, $opacity = 1) {
                // set opacity
                $color = imagecolorallocatealpha($this->image, $this->colorData['red'], $this->colorData['green'], $this->colorData['blue'], (1 - $opacity) * 127);
                
-               imageString($this->image, self::FONT, $x, $y, $string, $color);
+               // draw text
+               imagettftext($this->image, $size, 0, $x, $y, $color, $font, $text);
        }
        
        /**
         * @see \wcf\system\image\adapter\IImageAdapter::drawTextRelative()
         */
-       public function drawTextRelative($text, $position, $margin, $opacity) {
-               // split text into multiple lines to add each line separately
-               $lines = explode('\n', StringUtil::unifyNewlines($text));
+       public function drawTextRelative($text, $position, $margin, $offsetX, $offsetY, $font, $size, $opacity = 1) {
+               // split text into multiple lines
+               $lines = explode("\n", StringUtil::unifyNewlines($text));
                
-               $characterWidth = imagefontwidth(self::FONT);
-               $lineHeight = imagefontheight(self::FONT);
-               $textHeight = $lineHeight * count($lines);
+               // calc text width, height and first line height
+               $box = imagettfbbox($size, 0, $font, $text);
+               $firstLineBox = imagettfbbox($size, 0, $font, $lines[0]);
+               $textWidth = abs($box[0] - $box[2]);
+               $textHeight = abs($box[7] - $box[1]);
+               $firstLineHeight = abs($firstLineBox[7] - $firstLineBox[1]);
                
-               foreach ($lines as $key => $line) {
-                       $lineWidth = mb_strlen($line) * $characterWidth;
-                       
-                       // calculate x coordinate
-                       $x = 0;
-                       switch ($position) {
-                               case 'topLeft':
-                               case 'middleLeft':
-                               case 'bottomLeft':
-                                       $x = $margin;
+               // calculate x coordinate
+               $x = 0;
+               switch ($position) {
+                       case 'topLeft':
+                       case 'middleLeft':
+                       case 'bottomLeft':
+                               $x = $margin;
                                break;
-                               
-                               case 'topCenter':
-                               case 'middleCenter':
-                               case 'bottomCenter':
-                                       $x = floor(($this->getWidth() - $lineWidth) / 2);
+               
+                       case 'topCenter':
+                       case 'middleCenter':
+                       case 'bottomCenter':
+                               $x = floor(($this->getWidth() - $textWidth) / 2);
                                break;
-                               
-                               case 'topRight':
-                               case 'middleRight':
-                               case 'bottomRight':
-                                       $x = $this->getWidth() - $lineWidth - $margin;
+               
+                       case 'topRight':
+                       case 'middleRight':
+                       case 'bottomRight':
+                               $x = $this->getWidth() - $textWidth - $margin;
                                break;
-                       }
+               }
                        
-                       // calculate y coordinate
-                       $y = 0;
-                       switch ($position) {
-                               case 'topLeft':
-                               case 'topCenter':
-                               case 'topRight':
-                                       $y = $margin + $key * $lineHeight;
+               // calculate y coordinate
+               $y = 0;
+               switch ($position) {
+                       case 'topLeft':
+                       case 'topCenter':
+                       case 'topRight':
+                               $y = $margin + $firstLineHeight;
                                break;
-                               
-                               case 'middleLeft':
-                               case 'middleCenter':
-                               case 'middleRight':
-                                       $y = floor(($this->getHeight() - $textHeight) / 2) + $key * $lineHeight;
+               
+                       case 'middleLeft':
+                       case 'middleCenter':
+                       case 'middleRight':
+                               $y = floor(($this->getHeight() - $textHeight) / 2) + $firstLineHeight;
                                break;
-                               
-                               case 'bottomLeft':
-                               case 'bottomCenter':
-                               case 'bottomRight':
-                                       $y = $this->getHeight() - $textHeight + $key * $lineHeight - $margin;
+               
+                       case 'bottomLeft':
+                       case 'bottomCenter':
+                       case 'bottomRight':
+                               $y = $this->getHeight() - $textHeight + $firstLineHeight - $margin;
                                break;
-                       }
-                       
-                       $this->drawText($line, $x, $y, $opacity);
                }
+               
+               $this->drawText($text, $x + $offsetX, $y + $offsetY, $font, $size, $opacity);
        }
        
        /**
index a5b19a6d0a05184b8afd8b5dc429d57f73de9b3d..7686fd28543ac3429b8193451dc21bf288ede5c7 100644 (file)
@@ -84,15 +84,16 @@ interface IImageAdapter {
        /**
         * Draws a line of text, overwrites image resource within instance.
         * 
-        * @param       string          $string
+        * @param       string          $text
         * @param       integer         $x
         * @param       integer         $y
+        * @param       string          $font           path to TrueType font file
+        * @param       integer         $size           font size
         * @param       float           $opacity
-        * 
         * @see         \wcf\system\image\adapter\IImageAdapter::getImage()
         * @see         \wcf\system\image\adapter\IImageAdapter::setColor()
         */
-       public function drawText($string, $x, $y, $opacity);
+       public function drawText($text, $x, $y, $font, $size, $opacity = 1);
        
        /**
         * Draws (multiple lines of) text on the image at the given relative position
@@ -101,9 +102,13 @@ interface IImageAdapter {
         * @param       string          $text
         * @param       string          $position
         * @param       integer         $margin         in pixels
+        * @param       integer         $offsetX
+        * @param       integer         $offsetY
+        * @param       string          $font           path to TrueType font file
+        * @param       integer         $size           font size
         * @param       float           $opacity
         */
-       public function drawTextRelative($text, $position, $margin, $opacity);
+       public function drawTextRelative($text, $position, $margin, $offsetX, $offsetY, $font, $size, $opacity = 1);
        
        /**
         * Sets active color.
index 3d8248cb955327081a792c7f81c4a52a1cdd181d..80477bda472487834ea363787c74647679522715 100644 (file)
@@ -128,7 +128,7 @@ class ImageAdapter implements IImageAdapter {
        /**
         * @see \wcf\system\image\adapter\IImageAdapter::drawText()
         */
-       public function drawText($string, $x, $y, $opacity) {
+       public function drawText($text, $x, $y, $font, $size, $opacity = 1) {
                if (!$this->adapter->hasColor()) {
                        throw new SystemException("Cannot draw text unless a color has been specified with setColor().");
                }
@@ -138,13 +138,13 @@ class ImageAdapter implements IImageAdapter {
                        throw new SystemException("Invalid opacity value given.");
                }
                
-               $this->adapter->drawText($string, $x, $y, $opacity);
+               $this->adapter->drawText($text, $x, $y, $font, $size, $opacity);
        }
        
        /**
         * @see \wcf\system\image\adapter\IImageAdapter::drawTextRelative()
         */
-       public function drawTextRelative($text, $position, $margin, $opacity) {
+       public function drawTextRelative($text, $position, $margin, $offsetX, $offsetY, $font, $size, $opacity = 1) {
                if (!$this->adapter->hasColor()) {
                        throw new SystemException("Cannot draw text unless a color has been specified with setColor().");
                }
@@ -164,7 +164,7 @@ class ImageAdapter implements IImageAdapter {
                        throw new SystemException("Invalid opacity value given.");
                }
                
-               $this->adapter->drawTextRelative($text, $position, $margin, $opacity);
+               $this->adapter->drawTextRelative($text, $position, $margin, $offsetX, $offsetY, $font, $size, $opacity);
        }
        
        /**
index 5fa9005ad46b3f516471f9ab8ce93700f2a1e2ad..4f0be1bfe206cd369827e4b226c541132eb2a581 100644 (file)
@@ -187,24 +187,27 @@ class ImagickImageAdapter implements IImageAdapter {
        /**
         * @see \wcf\system\image\adapter\IImageAdapter::drawText()
         */
-       public function drawText($string, $x, $y, $opacity) {
+       public function drawText($text, $x, $y, $font, $size, $opacity = 1) {
                $draw = new \ImagickDraw();
                $draw->setStrokeOpacity($opacity);
                $draw->setFillColor($this->color);
                $draw->setTextAntialias(true);
+               $draw->setFont($font);
+               $draw->setFontSize($size);
                
                // draw text
-               $draw->annotation($x, $y, $string);
+               $draw->annotation($x, $y, $text);
                $this->imagick->drawImage($draw);
        }
        
        /**
         * @see \wcf\system\image\adapter\IImageAdapter::drawTextRelative()
         */
-       public function drawTextRelative($text, $position, $margin, $opacity) {
+       public function drawTextRelative($text, $position, $margin, $offsetX, $offsetY, $font, $size, $opacity = 1) {
                $draw = new \ImagickDraw();
-               $draw->setStrokeOpacity($opacity);
-               $metrics = $this->imagick->queryFontMetrics($draw, $string);
+               $draw->setFont($font);
+               $draw->setFontSize($size);
+               $metrics = $this->imagick->queryFontMetrics($draw, $text);
                
                // calculate x coordinate
                $x = 0;
@@ -251,7 +254,7 @@ class ImagickImageAdapter implements IImageAdapter {
                }
                
                // draw text
-               $this->drawText($string, $x, $y);
+               $this->drawText($text, $x + $offsetX, $y + $offsetY, $font, $size, $opacity);
        }
        
        /**