Experimental functionality, do not use!.

@param Image $otherImage
@param mixed $minAngle
@param mixed $maxAngle
@param mixed $backgroundColor
@param mixed $minDimension
779369
private function tiltAndCompare(Image $otherImage, $minAngle = -20, $maxAngle = 20, $backgroundColor = 0xffffff, &$minDimension) {
		if($minAngle > $maxAngle) {
			$tmp = $maxAngle;
			$maxAngle = $minAngle;
			$minAngle = $tmp;
		}

		$quantization = new Quantizator();
		$vector = $otherImage->getVector(new Point(0, 0), $otherImage->getDimensions(), false, 0);
		//$vector->normalize();
		$quantization->addGlyph($vector, 1);
		$otherImageDimensions = $otherImage->getDimensions();

		$foundObject = $this;
		$minDimension = 1000000000000;

		for($angle = $minAngle; $angle <= $maxAngle; $angle += 1) {
			$copy = $this->getCopy();
			$copy->rotate($angle, $backgroundColor);
			// find object in object - this is a smart autocropping of binary images.
			//$objects = $copy->findObjects();
			$objects[0] = $copy;
			// we want only the first detected object (only one should be detected anyway!;)
			list($width, $height) = $objects[0]->getSize();
			// object must be resized before quantization in order to match the other image dimensions.
			$objects[0]->resize($otherImageDimensions, null, false)->toBinary();
			$vector = $objects[0]->getVector(new Point(0, 0), $otherImageDimensions, false, 0);
			//$vector->normalize();
			$result = $quantization->findNearestEuklid($vector);
			if($result[1] < $minDimension) {
				$minDimension = $result[1];
				$foundObject = $objects[0];
			}
		}
		return $foundObject;
	}
151018
public static function rotateImage($file, $rotate, $desFile = '', $backgroundColor = 0xFFFFFF)
    {
        try {
            if (is_file($file)) {
                if (!$desFile) {
                    $desFile = $file;
                }
                Image::open($file)->rotate($rotate, $backgroundColor)->save($desFile);
                return true;
            }
        } catch (Exception $e) {
        }
        return false;
    }
1246061
public function addRectangle($x1, $y1, $x2, $y2, $colors = [0, 0, 0])
    {
        $color = imagecolorallocate($this->image(), $colors[0],  $colors[1],  $colors[2]);
        imagerectangle ( $this->image() , $x1 , $y1 , $x2 , $y2 ,  $color );
    }
995929
public static void boundImage( GrayU16 img , int min , int max ) {
		ImplPixelMath.boundImage(img,min,max);
	}
196332
public static void boundImage( GrayS64 img , long min , long max ) {
		ImplPixelMath.boundImage(img,min,max);
	}
995475
protected function mergeProperty(Result $otherResult, string $getterName, string $adderName)
    {
        foreach ($otherResult->$getterName() as $messageInOtherResult) {
            $this->$adderName($messageInOtherResult);
        }
    }
182786
public function notEq($other, array $options = []): Image
    {
        return $this->callEnum($other, 'relational', OperationRelational::NOTEQ, $options);
    }
891607
public static function image($mixSize = '400x350', $background = '000', $foregroundColor = 'fff', $text = null, $format = 'jpg')
    {
        return "//dummyimage.com/$mixSize/$background/$foregroundColor" . (!$text ? : '&text=' . urlencode($text));
    }
1362647
public static void boundImage( GrayS8 img , int min , int max ) {
		ImplPixelMath.boundImage(img,min,max);
	}
565107
public function roundCorners($radius = 5, $bgColor = 'transparent')
		# Author:     Jarrod Oberto
		# Date:       19-05-2011
		# Purpose:    Create rounded corners on your image
		# Param in:   (int) radius = the amount of curvature
		#       (mixed) $bgColor = the corner background color
		# Param out:  n/a
		# Reference:
		# Notes:
		#
	{

		// *** Check if the user wants transparency
		$isTransparent = false;
		if ( ! is_array($bgColor))
		{
			if (fix_strtolower($bgColor) == 'transparent')
			{
				$isTransparent = true;
			}
		}


		// *** If we use transparency, we need to color our curved mask with a unique color
		if ($isTransparent)
		{
			$bgColor = $this->findUnusedGreen();
		}

		// *** Convert color
		$rgbArray = $this->formatColor($bgColor);
		$r = $rgbArray['r'];
		$g = $rgbArray['g'];
		$b = $rgbArray['b'];
		if (isset($rgbArray['a']))
		{
			$a = $rgbArray['a'];
		}


		// *** Create top-left corner mask (square)
		$cornerImg = imagecreatetruecolor($radius, $radius);
		//$cornerImg = imagecreate($radius, $radius);

		//imagealphablending($cornerImg, true);
		//imagesavealpha($cornerImg, true);

		//imagealphablending($this->imageResized, false);
		//imagesavealpha($this->imageResized, true);

		// *** Give it a color
		$maskColor = imagecolorallocate($cornerImg, 0, 0, 0);


		// *** Replace the mask color (black) to transparent
		imagecolortransparent($cornerImg, $maskColor);


		// *** Create the image background color
		$imagebgColor = imagecolorallocate($cornerImg, $r, $g, $b);


		// *** Fill the corner area to the user defined color
		imagefill($cornerImg, 0, 0, $imagebgColor);


		imagefilledellipse($cornerImg, $radius, $radius, $radius * 2, $radius * 2, $maskColor);


		// *** Map to top left corner
		imagecopymerge($this->imageResized, $cornerImg, 0, 0, 0, 0, $radius, $radius, 100); #tl

		// *** Map rounded corner to other corners by rotating and applying the mask
		$cornerImg = imagerotate($cornerImg, 90, 0);
		imagecopymerge($this->imageResized, $cornerImg, 0, $this->height - $radius, 0, 0, $radius, $radius, 100); #bl

		$cornerImg = imagerotate($cornerImg, 90, 0);
		imagecopymerge($this->imageResized, $cornerImg, $this->width - $radius, $this->height - $radius, 0, 0, $radius, $radius, 100); #br

		$cornerImg = imagerotate($cornerImg, 90, 0);
		imagecopymerge($this->imageResized, $cornerImg, $this->width - $radius, 0, 0, 0, $radius, $radius, 100); #tr


		// *** If corners are to be transparent, we fill our chromakey color as transparent.
		if ($isTransparent)
		{
			//imagecolortransparent($this->imageResized, $imagebgColor);
			$this->imageResized = $this->transparentImage($this->imageResized);
			imagesavealpha($this->imageResized, true);
		}

	}
788662
public function rshift($other, array $options = []): Image
    {
        return $this->callEnum($other, 'boolean', OperationBoolean::RSHIFT, $options);
    }
885174
public static void boundImage( GrayU8 img , int min , int max ) {
		ImplPixelMath.boundImage(img,min,max);
	}
976767
public function setImagineImage(ImagineImageInterface $imagineImage, $mimeType = null)
    {
        if (!$mimeType) {
            $mimeType = $this->getMimeType();
        }
        if ($this->imagineImage !== $imagineImage || $mimeType != $this->getMimeType()) {
            // imagine image was changed OR MIME type was changed
            //  -> we flag binary content to be regerated from imagine image
            if ($this->imagineImage !== $imagineImage) {
                $this->imagineImage = $imagineImage;
            }
            if ($this->mimeType !== $mimeType) {
                $this->mimeType = $mimeType;
            }
            $this->binaryContentDirty = true;
        }
    }
917497
function setBackground()
  {
    $dat = @getimagesize($this->bgimg);
    if($dat == false) { return; }

    switch($dat[2]) {
      case 1:  $newim = @imagecreatefromgif($this->bgimg); break;
      case 2:  $newim = @imagecreatefromjpeg($this->bgimg); break;
      case 3:  $newim = @imagecreatefrompng($this->bgimg); break;
      case 15: $newim = @imagecreatefromwbmp($this->bgimg); break;
      case 16: $newim = @imagecreatefromxbm($this->bgimg); break;
      default: return;
    }

    if(!$newim) return;

    imagecopy($this->im, $newim, 0, 0, 0, 0, $this->image_width, $this->image_height);
  }
918211
public function less($other, array $options = []): Image
    {
        return $this->callEnum($other, 'relational', OperationRelational::LESS, $options);
    }
242097
protected function sizeBetween($lengthValue, $min, $max, $not = true)
    {
        if (!($lengthValue <= $max && $lengthValue >= $min) && $not) {
            $this->addReturn('image_dimensions_width', 'width', [
                ':min' => $min,
                ':max' => $max
            ]);
        } elseif ($lengthValue <= $max && $lengthValue >= $min && !$not) {
            $this->addReturn('image_dimensions_width', 'not_width', [
                ':min' => $min,
                ':max' => $max
            ]);
        }
    }
430664
public function addShadow($shadowAngle = 45, $blur = 15, $bgColor = 'transparent')
		#
		# Author:   Jarrod Oberto (Adapted from Pascal Naidon)
		# Ref:    http://www.les-stooges.org/pascal/webdesign/vignettes/index.php?la=en
		# Purpose:  Add a drop shadow to your image
		# Params in:  (int) $angle: the angle of the shadow
		#       (int) $blur: the blur distance
		#       (mixed) $bgColor: the color of the background
		# Params out:
		# Notes:
		#
	{
		// *** A higher number results in a smoother shadow
		define('STEPS', $blur * 2);

		// *** Set the shadow distance
		$shadowDistance = $blur * 0.25;

		// *** Set blur width and height
		$blurWidth = $blurHeight = $blur;


		if ($shadowAngle == 0)
		{
			$distWidth = 0;
			$distHeight = 0;
		}
		else
		{
			$distWidth = $shadowDistance * cos(deg2rad($shadowAngle));
			$distHeight = $shadowDistance * sin(deg2rad($shadowAngle));
		}


		// *** Convert color
		if (fix_strtolower($bgColor) != 'transparent')
		{
			$rgbArray = $this->formatColor($bgColor);
			$r0 = $rgbArray['r'];
			$g0 = $rgbArray['g'];
			$b0 = $rgbArray['b'];
		}


		$image = $this->imageResized;
		$width = $this->width;
		$height = $this->height;


		$newImage = imagecreatetruecolor($width, $height);
		imagecopyresampled($newImage, $image, 0, 0, 0, 0, $width, $height, $width, $height);


		// *** RGB
		$rgb = imagecreatetruecolor($width + $blurWidth, $height + $blurHeight);
		$colour = imagecolorallocate($rgb, 0, 0, 0);
		imagefilledrectangle($rgb, 0, 0, $width + $blurWidth, $height + $blurHeight, $colour);
		$colour = imagecolorallocate($rgb, 255, 255, 255);
		//imagefilledrectangle($rgb, $blurWidth*0.5-$distWidth, $blurHeight*0.5-$distHeight, $width+$blurWidth*0.5-$distWidth, $height+$blurWidth*0.5-$distHeight, $colour);
		imagefilledrectangle($rgb, $blurWidth * 0.5 - $distWidth, $blurHeight * 0.5 - $distHeight, $width + $blurWidth * 0.5 - $distWidth, $height + $blurWidth * 0.5 - $distHeight, $colour);
		//imagecopymerge($rgb, $newImage, 1+$blurWidth*0.5-$distWidth, 1+$blurHeight*0.5-$distHeight, 0,0, $width, $height, 100);
		imagecopymerge($rgb, $newImage, $blurWidth * 0.5 - $distWidth, $blurHeight * 0.5 - $distHeight, 0, 0, $width + $blurWidth, $height + $blurHeight, 100);


		// *** Shadow (alpha)
		$shadow = imagecreatetruecolor($width + $blurWidth, $height + $blurHeight);
		imagealphablending($shadow, false);
		$colour = imagecolorallocate($shadow, 0, 0, 0);
		imagefilledrectangle($shadow, 0, 0, $width + $blurWidth, $height + $blurHeight, $colour);


		for ($i = 0; $i <= STEPS; $i++)
		{

			$t = ((1.0 * $i) / STEPS);
			$intensity = 255 * $t * $t;

			$colour = imagecolorallocate($shadow, $intensity, $intensity, $intensity);
			$points = array(
				$blurWidth * $t, $blurHeight,     // Point 1 (x, y)
				$blurWidth, $blurHeight * $t,  // Point 2 (x, y)
				$width, $blurHeight * $t,  // Point 3 (x, y)
				$width + $blurWidth * (1 - $t), $blurHeight,     // Point 4 (x, y)
				$width + $blurWidth * (1 - $t), $height,     // Point 5 (x, y)
				$width, $height + $blurHeight * (1 - $t),  // Point 6 (x, y)
				$blurWidth, $height + $blurHeight * (1 - $t),  // Point 7 (x, y)
				$blurWidth * $t, $height      // Point 8 (x, y)
			);
			imagepolygon($shadow, $points, 8, $colour);
		}

		for ($i = 0; $i <= STEPS; $i++)
		{

			$t = ((1.0 * $i) / STEPS);
			$intensity = 255 * $t * $t;

			$colour = imagecolorallocate($shadow, $intensity, $intensity, $intensity);
			imagefilledarc($shadow, $blurWidth - 1, $blurHeight - 1, 2 * (1 - $t) * $blurWidth, 2 * (1 - $t) * $blurHeight, 180, 268, $colour, IMG_ARC_PIE);
			imagefilledarc($shadow, $width, $blurHeight - 1, 2 * (1 - $t) * $blurWidth, 2 * (1 - $t) * $blurHeight, 270, 358, $colour, IMG_ARC_PIE);
			imagefilledarc($shadow, $width, $height, 2 * (1 - $t) * $blurWidth, 2 * (1 - $t) * $blurHeight, 0, 90, $colour, IMG_ARC_PIE);
			imagefilledarc($shadow, $blurWidth - 1, $height, 2 * (1 - $t) * $blurWidth, 2 * (1 - $t) * $blurHeight, 90, 180, $colour, IMG_ARC_PIE);
		}


		$colour = imagecolorallocate($shadow, 255, 255, 255);
		imagefilledrectangle($shadow, $blurWidth, $blurHeight, $width, $height, $colour);
		imagefilledrectangle($shadow, $blurWidth * 0.5 - $distWidth, $blurHeight * 0.5 - $distHeight, $width + $blurWidth * 0.5 - 1 - $distWidth, $height + $blurHeight * 0.5 - 1 - $distHeight, $colour);


		// *** The magic
		imagealphablending($rgb, false);

		for ($theX = 0; $theX < imagesx($rgb); $theX++)
		{
			for ($theY = 0; $theY < imagesy($rgb); $theY++)
			{

				// *** Get the RGB values for every pixel of the RGB image
				$colArray = imagecolorat($rgb, $theX, $theY);
				$r = ($colArray >> 16) & 0xFF;
				$g = ($colArray >> 8) & 0xFF;
				$b = $colArray & 0xFF;

				// *** Get the alpha value for every pixel of the shadow image
				$colArray = imagecolorat($shadow, $theX, $theY);
				$a = $colArray & 0xFF;
				$a = 127 - floor($a / 2);
				$t = $a / 128.0;

				// *** Create color
				if (fix_strtolower($bgColor) == 'transparent')
				{
					$myColour = imagecolorallocatealpha($rgb, $r, $g, $b, $a);
				}
				else
				{
					$myColour = imagecolorallocate($rgb, $r * (1.0 - $t) + $r0 * $t, $g * (1.0 - $t) + $g0 * $t, $b * (1.0 - $t) + $b0 * $t);
				}

				// *** Add color to new rgb image
				imagesetpixel($rgb, $theX, $theY, $myColour);
			}
		}

		imagealphablending($rgb, true);
		imagesavealpha($rgb, true);

		$this->imageResized = $rgb;

		imagedestroy($image);
		imagedestroy($newImage);
		imagedestroy($shadow);
	}