/**
  * Draw a line around an image
  *
  * Draw a line around an image. If $offset is 0, the line is just around the image.
  * If $offset is positive, the line is outside the image, and the gad is filled with background color.
  * If $offset is -width / 2, the line is centered on the border of the image.
  * If $offset is -$width, the line in just inside the image.
  * If $offset is negative, the line is inside the image.
  *
  * @param   int $width Line width
  * @param   mixed $color Line color
  * @param   int $offset Distance between line and image.
  *
  * @return  bool|PEAR_Error TRUE on success or PEAR_Error on failure.
  * @access  private
  * @author  Charles Brunet <*****@*****.**>
  */
 function _line($width = 2, $color = '000000', $offset = 0, $background = 'FFFFFF')
 {
     // Agrandir l'image si nécessaire
     $mag = $width + $offset;
     if ($mag > 0) {
         $w = $this->_iWidth + 2 * $mag;
         $h = $this->_iHeight + 2 * $mag;
         // Create the target image
         if (function_exists('imagecreatetruecolor')) {
             $target = imagecreatetruecolor($w, $h);
         } else {
             $target = imagecreate($w, $h);
         }
         if (!Image_Tools::isGDImageResource($target)) {
             return PEAR::raiseError('Cannot initialize new GD image stream');
         }
         $background = Image_Tools_Utils::colorToRGBA($background);
         $background = imagecolorallocate($target, $background['r'], $background['g'], $background['b']);
         imagefilledrectangle($target, 0, 0, $w - 1, $h - 1, $background);
         imagecopy($target, $this->resultImage, $mag, $mag, 0, 0, $this->_iWidth, $this->_iHeight);
         $this->_iWidth = $w;
         $this->_iHeight = $h;
         imagedestroy($this->resultImage);
         $this->resultImage = $target;
     }
     if (!Image_Tools::isGDImageResource($this->resultImage)) {
         return PEAR::raiseError('Invalid image resource Image_Tools_Mask::$_resultImage');
     }
     $color = Image_Tools_Utils::colorToRGBA($color);
     $color = imagecolorallocate($this->resultImage, $color['r'], $color['g'], $color['b']);
     $a = $mag < 0 ? 0 - $mag : 0;
     for ($i = $a; $i < $a + $width; ++$i) {
         imagerectangle($this->resultImage, $i, $i, $this->_iWidth - $i - 1, $this->_iHeight - $i - 1, $color);
     }
     return true;
 }
 /**
  * Apply the blend mode.
  *
  * @return true|PEAR_Error
  * @access protected
  */
 function render()
 {
     $method = array($this, "_{$this->options['mode']}");
     if (!is_callable($method)) {
         return PEAR::raiseError('Invalid mode or not supported');
     }
     $width1 = imagesx($this->_image1);
     $height1 = imagesy($this->_image1);
     $width = imagesx($this->_image2);
     $height = imagesy($this->_image2);
     // sets out of bound flags
     $x_outbound = $y_outbound = false;
     // walking through pixels
     for ($x2 = 0, $x1 = $this->options['x']; $x2 < $width; $x2++, $x1++) {
         // x and y already out of bound, nothing to process
         if ($x_outbound && $y_outbound) {
             break;
         }
         $x_outbound = $y_outbound = false;
         // x is out bound
         if ($x1 >= $width1) {
             $x_outbound = true;
             continue;
         }
         for ($y2 = 0, $y1 = $this->options['y']; $y2 < $height; $y2++, $y1++) {
             // y is out bound
             if ($y1 >= $height1) {
                 $y_outbound = true;
                 continue;
             }
             $color1 = Image_Tools_Utils::colorToRGBA(imagecolorat($this->_image1, $x1, $y1));
             $color2 = Image_Tools_Utils::colorToRGBA(imagecolorat($this->_image2, $x2, $y2));
             // ignore transparencies
             if ($color2['a'] == 127) {
                 continue;
             }
             $params = array_merge(array($color1['r'], $color2['r']), $this->options['params']);
             $red = call_user_func_array($method, $params);
             $params = array_merge(array($color1['g'], $color2['g']), $this->options['params']);
             $green = call_user_func_array($method, $params);
             $params = array_merge(array($color1['b'], $color2['b']), $this->options['params']);
             $blue = call_user_func_array($method, $params);
             $color = imagecolorallocatealpha($this->_image1, $red, $green, $blue, $color2['a']);
             imagesetpixel($this->_image1, $x1, $y1, $color);
         }
     }
     $this->resultImage = $this->_image1;
     // frees up memory
     imagedestroy($this->_image2);
     return true;
 }