Add IImageAdapter::drawTextRelative()
authorMatthias Schmidt <gravatronics@live.com>
Tue, 23 Dec 2014 08:29:31 +0000 (09:29 +0100)
committerMatthias Schmidt <gravatronics@live.com>
Tue, 23 Dec 2014 08:29:31 +0000 (09:29 +0100)
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 f4420e30d193f1bfa9e7a0174aeb948b4da3bf53..5acc24b38c6df9b3b8cd060b09af5506e1fea013 100644 (file)
@@ -20,6 +20,12 @@ class GDImageAdapter implements IImageAdapter {
         */
        protected $color = null;
        
+       /**
+        * red, green, blue data of the active color
+        * @var array
+        */
+       protected $colorData = array();
+       
        /**
         * image height
         * @var integer
@@ -44,6 +50,12 @@ 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()
         */
@@ -179,15 +191,81 @@ class GDImageAdapter implements IImageAdapter {
        /**
         * @see \wcf\system\image\adapter\IImageAdapter::drawText()
         */
-       public function drawText($string, $x, $y) {
+       public function drawText($string, $x, $y, $opacity) {
                if (!StringUtil::isUTF8($string)) {
-                       throw new SystemException("Only UTF-8 encoded text can be written onto images"); // GD is buggy with UTF-8
+                       // 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;
-               $string = mb_encode_numericentity($string, array(0x0, 0xFFFF, 0, 0xFFF), 'UTF-8');
+               // todo: $string = mb_encode_numericentity($string, array(0x0, 0xFFFF, 0, 0xFFF), 'UTF-8');
+               
+               // set opacity
+               $color = imagecolorallocatealpha($this->image, $this->colorData['red'], $this->colorData['green'], $this->colorData['blue'], (1 - $opacity) * 127);
                
-               imageString($this->image, 3, $x, $y, $string, $this->color);
+               imageString($this->image, self::FONT, $x, $y, $string, $color);
+       }
+       
+       /**
+        * @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));
+               
+               $characterWidth = imagefontwidth(self::FONT);
+               $lineHeight = imagefontheight(self::FONT);
+               $textHeight = $lineHeight * count($lines);
+               
+               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;
+                               break;
+                               
+                               case 'topCenter':
+                               case 'middleCenter':
+                               case 'bottomCenter':
+                                       $x = floor(($this->getWidth() - $lineWidth) / 2);
+                               break;
+                               
+                               case 'topRight':
+                               case 'middleRight':
+                               case 'bottomRight':
+                                       $x = $this->getWidth() - $lineWidth - $margin;
+                               break;
+                       }
+                       
+                       // calculate y coordinate
+                       $y = 0;
+                       switch ($position) {
+                               case 'topLeft':
+                               case 'topCenter':
+                               case 'topRight':
+                                       $y = $margin + $key * $lineHeight;
+                               break;
+                               
+                               case 'middleLeft':
+                               case 'middleCenter':
+                               case 'middleRight':
+                                       $y = floor(($this->getHeight() - $textHeight) / 2) + $key * $lineHeight;
+                               break;
+                               
+                               case 'bottomLeft':
+                               case 'bottomCenter':
+                               case 'bottomRight':
+                                       $y = $this->getHeight() - $textHeight + $key * $lineHeight - $margin;
+                               break;
+                       }
+                       
+                       $this->drawText($line, $x, $y, $opacity);
+               }
        }
        
        /**
@@ -195,6 +273,13 @@ class GDImageAdapter implements IImageAdapter {
         */
        public function setColor($red, $green, $blue) {
                $this->color = imageColorAllocate($this->image, $red, $green, $blue);
+               
+               // save data of the color
+               $this->colorData = array(
+                       'red' => $red,
+                       'green' => $green,
+                       'blue' => $blue
+               );
        }
        
        /**
index aaa0670dcca1fa77170967f43d62f9825a2a80f9..a5b19a6d0a05184b8afd8b5dc429d57f73de9b3d 100644 (file)
@@ -87,10 +87,23 @@ interface IImageAdapter {
         * @param       string          $string
         * @param       integer         $x
         * @param       integer         $y
+        * @param       float           $opacity
+        * 
         * @see         \wcf\system\image\adapter\IImageAdapter::getImage()
         * @see         \wcf\system\image\adapter\IImageAdapter::setColor()
         */
-       public function drawText($string, $x, $y);
+       public function drawText($string, $x, $y, $opacity);
+       
+       /**
+        * Draws (multiple lines of) text on the image at the given relative position
+        * with a certain margin to the image border.
+        * 
+        * @param       string          $text
+        * @param       string          $position
+        * @param       integer         $margin         in pixels
+        * @param       float           $opacity
+        */
+       public function drawTextRelative($text, $position, $margin, $opacity);
        
        /**
         * Sets active color.
index 0433dac0e203dfb6fc8185f42bd900a0ec45f4b1..3d8248cb955327081a792c7f81c4a52a1cdd181d 100644 (file)
@@ -128,12 +128,43 @@ class ImageAdapter implements IImageAdapter {
        /**
         * @see \wcf\system\image\adapter\IImageAdapter::drawText()
         */
-       public function drawText($string, $x, $y) {
+       public function drawText($string, $x, $y, $opacity) {
                if (!$this->adapter->hasColor()) {
                        throw new SystemException("Cannot draw text unless a color has been specified with setColor().");
                }
                
-               $this->adapter->drawText($string, $x, $y);
+               // validate opacity
+               if ($opacity < 0 || $opacity > 1) {
+                       throw new SystemException("Invalid opacity value given.");
+               }
+               
+               $this->adapter->drawText($string, $x, $y, $opacity);
+       }
+       
+       /**
+        * @see \wcf\system\image\adapter\IImageAdapter::drawTextRelative()
+        */
+       public function drawTextRelative($text, $position, $margin, $opacity) {
+               if (!$this->adapter->hasColor()) {
+                       throw new SystemException("Cannot draw text unless a color has been specified with setColor().");
+               }
+               
+               // validate position
+               if (!in_array($position, $this->relativePositions)) {
+                       throw new SystemException("Unknown relative position '".$position."'.");
+               }
+               
+               // validate margin
+               if ($margin < 0 || $margin >= $this->getHeight() / 2 || $margin >= $this->getWidth() / 2) {
+                       throw new SystemException("Margin has to be positive and respect image dimensions.");
+               }
+               
+               // validate opacity
+               if ($opacity < 0 || $opacity > 1) {
+                       throw new SystemException("Invalid opacity value given.");
+               }
+               
+               $this->adapter->drawTextRelative($text, $position, $margin, $opacity);
        }
        
        /**
@@ -217,6 +248,11 @@ class ImageAdapter implements IImageAdapter {
                        throw new SystemException("Image '".$file."' does not exist.");
                }
                
+               // validate opacity
+               if ($opacity < 0 || $opacity > 1) {
+                       throw new SystemException("Invalid opacity value given.");
+               }
+               
                $this->adapter->overlayImage($file, $x, $y, $opacity);
        }
        
@@ -239,6 +275,11 @@ class ImageAdapter implements IImageAdapter {
                        throw new SystemException("Margin has to be positive and respect image dimensions.");
                }
                
+               // validate opacity
+               if ($opacity < 0 || $opacity > 1) {
+                       throw new SystemException("Invalid opacity value given.");
+               }
+               
                $adapterClassName = get_class($this->adapter);
                $overlayImage = new $adapterClassName();
                $overlayImage->loadFile($file);
index 42b3eaacb8bd627916af72d3e4cde09580141c74..5fa9005ad46b3f516471f9ab8ce93700f2a1e2ad 100644 (file)
@@ -187,8 +187,9 @@ class ImagickImageAdapter implements IImageAdapter {
        /**
         * @see \wcf\system\image\adapter\IImageAdapter::drawText()
         */
-       public function drawText($string, $x, $y) {
+       public function drawText($string, $x, $y, $opacity) {
                $draw = new \ImagickDraw();
+               $draw->setStrokeOpacity($opacity);
                $draw->setFillColor($this->color);
                $draw->setTextAntialias(true);
                
@@ -197,6 +198,62 @@ class ImagickImageAdapter implements IImageAdapter {
                $this->imagick->drawImage($draw);
        }
        
+       /**
+        * @see \wcf\system\image\adapter\IImageAdapter::drawTextRelative()
+        */
+       public function drawTextRelative($text, $position, $margin, $opacity) {
+               $draw = new \ImagickDraw();
+               $draw->setStrokeOpacity($opacity);
+               $metrics = $this->imagick->queryFontMetrics($draw, $string);
+               
+               // 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() - $metrics['textWidth']) / 2);
+                       break;
+                       
+                       case 'topRight':
+                       case 'middleRight':
+                       case 'bottomRight':
+                               $x = $this->getWidth() - $metrics['textWidth'] - $margin;
+                       break;
+               }
+               
+               // calculate y coordinate
+               $y = 0;
+               switch ($position) {
+                       case 'topLeft':
+                       case 'topCenter':
+                       case 'topRight':
+                               $y = $margin;
+                       break;
+                       
+                       case 'middleLeft':
+                       case 'middleCenter':
+                       case 'middleRight':
+                               $y = floor(($this->getHeight() - $metrics['textHeight']) / 2);
+                       break;
+                       
+                       case 'bottomLeft':
+                       case 'bottomCenter':
+                       case 'bottomRight':
+                               $y = $this->getHeight() - $metrics['textHeight'] - $margin;
+                       break;
+               }
+               
+               // draw text
+               $this->drawText($string, $x, $y);
+       }
+       
        /**
         * @see \wcf\system\image\adapter\IImageAdapter::setColor()
         */