mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-25 10:09:20 +03:00
Added: Incorrect image orientation
This commit is contained in:
parent
217207883f
commit
e3b62d24d8
87 changed files with 10461 additions and 21 deletions
|
|
@ -22,7 +22,7 @@ if (!\defined('RAINLOOP_APP_LIBRARIES_PATH'))
|
|||
function rainLoopSplAutoloadNamespaces()
|
||||
{
|
||||
return RAINLOOP_INCLUDE_AS_API_DEF ? array('RainLoop') :
|
||||
array('RainLoop', 'Facebook', 'GuzzleHttp', 'PHPThumb', 'SabreForRainLoop');
|
||||
array('RainLoop', 'Facebook', 'GuzzleHttp', 'PHPThumb', 'SabreForRainLoop', 'Imagine');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
149
rainloop/v/0.0.0/app/libraries/Imagine/Draw/DrawerInterface.php
Normal file
149
rainloop/v/0.0.0/app/libraries/Imagine/Draw/DrawerInterface.php
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Draw;
|
||||
|
||||
use Imagine\Image\AbstractFont;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\PointInterface;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Interface for the drawer
|
||||
*/
|
||||
interface DrawerInterface
|
||||
{
|
||||
/**
|
||||
* Draws an arc on a starting at a given x, y coordinates under a given
|
||||
* start and end angles
|
||||
*
|
||||
* @param PointInterface $center
|
||||
* @param BoxInterface $size
|
||||
* @param integer $start
|
||||
* @param integer $end
|
||||
* @param ColorInterface $color
|
||||
* @param integer $thickness
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return DrawerInterface
|
||||
*/
|
||||
public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1);
|
||||
|
||||
/**
|
||||
* Same as arc, but also connects end points with a straight line
|
||||
*
|
||||
* @param PointInterface $center
|
||||
* @param BoxInterface $size
|
||||
* @param integer $start
|
||||
* @param integer $end
|
||||
* @param ColorInterface $color
|
||||
* @param Boolean $fill
|
||||
* @param integer $thickness
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return DrawerInterface
|
||||
*/
|
||||
public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1);
|
||||
|
||||
/**
|
||||
* Draws and ellipse with center at the given x, y coordinates, and given
|
||||
* width and height
|
||||
*
|
||||
* @param PointInterface $center
|
||||
* @param BoxInterface $size
|
||||
* @param ColorInterface $color
|
||||
* @param Boolean $fill
|
||||
* @param integer $thickness
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return DrawerInterface
|
||||
*/
|
||||
public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1);
|
||||
|
||||
/**
|
||||
* Draws a line from start(x, y) to end(x, y) coordinates
|
||||
*
|
||||
* @param PointInterface $start
|
||||
* @param PointInterface $end
|
||||
* @param ColorInterface $outline
|
||||
* @param integer $thickness
|
||||
*
|
||||
* @return DrawerInterface
|
||||
*/
|
||||
public function line(PointInterface $start, PointInterface $end, ColorInterface $outline, $thickness = 1);
|
||||
|
||||
/**
|
||||
* Same as arc, but connects end points and the center
|
||||
*
|
||||
* @param PointInterface $center
|
||||
* @param BoxInterface $size
|
||||
* @param integer $start
|
||||
* @param integer $end
|
||||
* @param ColorInterface $color
|
||||
* @param Boolean $fill
|
||||
* @param integer $thickness
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return DrawerInterface
|
||||
*/
|
||||
public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1);
|
||||
|
||||
/**
|
||||
* Places a one pixel point at specific coordinates and fills it with
|
||||
* specified color
|
||||
*
|
||||
* @param PointInterface $position
|
||||
* @param ColorInterface $color
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return DrawerInterface
|
||||
*/
|
||||
public function dot(PointInterface $position, ColorInterface $color);
|
||||
|
||||
/**
|
||||
* Draws a polygon using array of x, y coordinates. Must contain at least
|
||||
* three coordinates
|
||||
*
|
||||
* @param array $coordinates
|
||||
* @param ColorInterface $color
|
||||
* @param Boolean $fill
|
||||
* @param integer $thickness
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return DrawerInterface
|
||||
*/
|
||||
public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1);
|
||||
|
||||
/**
|
||||
* Annotates image with specified text at a given position starting on the
|
||||
* top left of the final text box
|
||||
*
|
||||
* The rotation is done CW
|
||||
*
|
||||
* @param string $string
|
||||
* @param AbstractFont $font
|
||||
* @param PointInterface $position
|
||||
* @param integer $angle
|
||||
* @param integer $width
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return DrawerInterface
|
||||
*/
|
||||
public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null);
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Effects;
|
||||
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
|
||||
/**
|
||||
* Interface for the effects
|
||||
*/
|
||||
interface EffectsInterface
|
||||
{
|
||||
/**
|
||||
* Apply gamma correction
|
||||
*
|
||||
* @param float $correction
|
||||
* @return EffectsInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function gamma($correction);
|
||||
|
||||
/**
|
||||
* Invert the colors of the image
|
||||
*
|
||||
* @return EffectsInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function negative();
|
||||
|
||||
/**
|
||||
* Grayscale the image
|
||||
*
|
||||
* @return EffectsInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function grayscale();
|
||||
|
||||
/**
|
||||
* Colorize the image
|
||||
*
|
||||
* @param ColorInterface $color
|
||||
*
|
||||
* @return EffectsInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function colorize(ColorInterface $color);
|
||||
|
||||
/**
|
||||
* Sharpens the image
|
||||
*
|
||||
* @return EffectsInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function sharpen();
|
||||
|
||||
/**
|
||||
* Blur the image
|
||||
*
|
||||
* @param float|int $sigma
|
||||
*
|
||||
* @return EffectsInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function blur($sigma);
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Exception;
|
||||
|
||||
/**
|
||||
* Imagine-specific exception
|
||||
*/
|
||||
interface Exception
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Exception;
|
||||
|
||||
/**
|
||||
* Imagine-specific invalid argument exception
|
||||
*/
|
||||
class InvalidArgumentException extends \InvalidArgumentException implements Exception
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Exception;
|
||||
|
||||
/**
|
||||
* Should be used when a driver does not support an operation.
|
||||
*/
|
||||
class NotSupportedException extends RuntimeException implements Exception
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Exception;
|
||||
|
||||
/**
|
||||
* Imagine-specific out of bounds exception
|
||||
*/
|
||||
class OutOfBoundsException extends \OutOfBoundsException implements Exception
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Exception;
|
||||
|
||||
/**
|
||||
* Imagine-specific runtime exception
|
||||
*/
|
||||
class RuntimeException extends \RuntimeException implements Exception
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Advanced;
|
||||
|
||||
use Imagine\Filter\FilterInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Point;
|
||||
|
||||
/**
|
||||
* A border filter
|
||||
*/
|
||||
class Border implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @var ColorInterface
|
||||
*/
|
||||
private $color;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $width;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $height;
|
||||
|
||||
/**
|
||||
* Constructs Border filter with given color, width and height
|
||||
*
|
||||
* @param ColorInterface $color
|
||||
* @param integer $width Width of the border on the left and right sides of the image
|
||||
* @param integer $height Height of the border on the top and bottom sides of the image
|
||||
*/
|
||||
public function __construct(ColorInterface $color, $width = 1, $height = 1)
|
||||
{
|
||||
$this->color = $color;
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
$size = $image->getSize();
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
$draw = $image->draw();
|
||||
|
||||
// Draw top and bottom lines
|
||||
$draw
|
||||
->line(
|
||||
new Point(0, 0),
|
||||
new Point($width - 1, 0),
|
||||
$this->color,
|
||||
$this->height
|
||||
)
|
||||
->line(
|
||||
new Point($width - 1, $height - 1),
|
||||
new Point(0, $height - 1),
|
||||
$this->color,
|
||||
$this->height
|
||||
)
|
||||
;
|
||||
|
||||
// Draw sides
|
||||
$draw
|
||||
->line(
|
||||
new Point(0, 0),
|
||||
new Point(0, $height - 1),
|
||||
$this->color,
|
||||
$this->width
|
||||
)
|
||||
->line(
|
||||
new Point($width - 1, 0),
|
||||
new Point($width - 1, $height - 1),
|
||||
$this->color,
|
||||
$this->width
|
||||
)
|
||||
;
|
||||
|
||||
return $image;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Advanced;
|
||||
|
||||
use Imagine\Filter\FilterInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Point;
|
||||
use Imagine\Image\PointInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\ImagineInterface;
|
||||
|
||||
/**
|
||||
* A canvas filter
|
||||
*/
|
||||
class Canvas implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @var BoxInterface
|
||||
*/
|
||||
private $size;
|
||||
|
||||
/**
|
||||
* @var PointInterface
|
||||
*/
|
||||
private $placement;
|
||||
|
||||
/**
|
||||
* @var ColorInterface
|
||||
*/
|
||||
private $background;
|
||||
|
||||
/**
|
||||
* @var ImagineInterface
|
||||
*/
|
||||
private $imagine;
|
||||
|
||||
/**
|
||||
* Constructs Canvas filter with given width and height and the placement of the current image
|
||||
* inside the new canvas
|
||||
*
|
||||
* @param ImagineInterface $imagine
|
||||
* @param BoxInterface $size
|
||||
* @param PointInterface $placement
|
||||
* @param ColorInterface $background
|
||||
*/
|
||||
public function __construct(ImagineInterface $imagine, BoxInterface $size, PointInterface $placement = null, ColorInterface $background = null)
|
||||
{
|
||||
$this->imagine = $imagine;
|
||||
$this->size = $size;
|
||||
$this->placement = $placement ?: new Point(0, 0);
|
||||
$this->background = $background;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
$canvas = $this->imagine->create($this->size, $this->background);
|
||||
$canvas->paste($image, $this->placement);
|
||||
|
||||
return $canvas;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Advanced;
|
||||
|
||||
use Imagine\Filter\FilterInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\Point;
|
||||
|
||||
/**
|
||||
* The Grayscale filter calculates the gray-value based on RGB.
|
||||
*/
|
||||
class Grayscale extends OnPixelBased implements FilterInterface
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(function (ImageInterface $image, Point $point) {
|
||||
$color = $image->getColorAt($point);
|
||||
$image->draw()->dot($point, $color->grayscale());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Advanced;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\Point;
|
||||
|
||||
/**
|
||||
* The OnPixelBased takes a callable, and for each pixel, this callable is called with the
|
||||
* image (\Imagine\Image\ImageInterface) and the current point (\Imagine\Image\Point)
|
||||
*/
|
||||
class OnPixelBased implements FilterInterface
|
||||
{
|
||||
protected $callback;
|
||||
|
||||
public function __construct($callback)
|
||||
{
|
||||
if (!is_callable($callback)) {
|
||||
throw new InvalidArgumentException('$callback has to be callable');
|
||||
}
|
||||
|
||||
$this->callback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies scheduled transformation to ImageInterface instance
|
||||
* Returns processed ImageInterface instance
|
||||
*
|
||||
* @param ImageInterface $image
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
$w = $image->getSize()->getWidth();
|
||||
$h = $image->getSize()->getHeight();
|
||||
|
||||
for ($x = 0; $x < $w; $x++) {
|
||||
for ($y = 0; $y < $h; $y++) {
|
||||
call_user_func($this->callback, $image, new Point($x, $y));
|
||||
}
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Advanced;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
|
||||
/**
|
||||
* The RelativeResize filter allows images to be resized relative to their
|
||||
* existing dimensions.
|
||||
*/
|
||||
class RelativeResize implements FilterInterface
|
||||
{
|
||||
private $method;
|
||||
private $parameter;
|
||||
|
||||
/**
|
||||
* Constructs a RelativeResize filter with the given method and argument.
|
||||
*
|
||||
* @param string $method BoxInterface method
|
||||
* @param mixed $parameter Parameter for BoxInterface method
|
||||
*/
|
||||
public function __construct($method, $parameter)
|
||||
{
|
||||
if (!in_array($method, array('heighten', 'increase', 'scale', 'widen'))) {
|
||||
throw new InvalidArgumentException(sprintf('Unsupported method: ', $method));
|
||||
}
|
||||
|
||||
$this->method = $method;
|
||||
$this->parameter = $parameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->resize(call_user_func(array($image->getSize(), $this->method), $this->parameter));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Filter\FilterInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
|
||||
/**
|
||||
* An apply mask filter
|
||||
*/
|
||||
class ApplyMask implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @var ImageInterface
|
||||
*/
|
||||
private $mask;
|
||||
|
||||
/**
|
||||
* @param ImageInterface $mask
|
||||
*/
|
||||
public function __construct(ImageInterface $mask)
|
||||
{
|
||||
$this->mask = $mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->applyMask($this->mask);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Filter\FilterInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
|
||||
/**
|
||||
* Rotates an image automatically based on exif information.
|
||||
*
|
||||
* Your attention please: This filter requires the use of the
|
||||
* ExifMetadataReader to work.
|
||||
*
|
||||
* @see https://imagine.readthedocs.org/en/latest/usage/metadata.html
|
||||
*/
|
||||
class Autorotate implements FilterInterface
|
||||
{
|
||||
private $color;
|
||||
|
||||
/**
|
||||
* @param string|array|ColorInterface $color A color
|
||||
*/
|
||||
public function __construct($color = '000000')
|
||||
{
|
||||
$this->color = $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
$metadata = $image->metadata();
|
||||
|
||||
switch (isset($metadata['ifd0.Orientation']) ? $metadata['ifd0.Orientation'] : null) {
|
||||
case 1: // top-left
|
||||
break;
|
||||
case 2: // top-right
|
||||
$image->flipHorizontally();
|
||||
break;
|
||||
case 3: // bottom-right
|
||||
$image->rotate(180, $this->getColor($image));
|
||||
break;
|
||||
case 4: // bottom-left
|
||||
$image->flipHorizontally();
|
||||
$image->rotate(180, $this->getColor($image));
|
||||
break;
|
||||
case 5: // left-top
|
||||
$image->flipHorizontally();
|
||||
$image->rotate(-90, $this->getColor($image));
|
||||
break;
|
||||
case 6: // right-top
|
||||
$image->rotate(90, $this->getColor($image));
|
||||
break;
|
||||
case 7: // right-bottom
|
||||
$image->flipHorizontally();
|
||||
$image->rotate(90, $this->getColor($image));
|
||||
break;
|
||||
case 8: // left-bottom
|
||||
$image->rotate(-90, $this->getColor($image));
|
||||
break;
|
||||
default: // Invalid orientation
|
||||
break;
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
private function getColor(ImageInterface $image)
|
||||
{
|
||||
if ($this->color instanceof ColorInterface) {
|
||||
return $this->color;
|
||||
}
|
||||
|
||||
return $image->palette()->color($this->color);
|
||||
}
|
||||
}
|
||||
29
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Basic/Copy.php
Normal file
29
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Basic/Copy.php
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Filter\FilterInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
|
||||
/**
|
||||
* A copy filter
|
||||
*/
|
||||
class Copy implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->copy();
|
||||
}
|
||||
}
|
||||
54
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Basic/Crop.php
Normal file
54
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Basic/Crop.php
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\PointInterface;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A crop filter
|
||||
*/
|
||||
class Crop implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @var PointInterface
|
||||
*/
|
||||
private $start;
|
||||
|
||||
/**
|
||||
* @var BoxInterface
|
||||
*/
|
||||
private $size;
|
||||
|
||||
/**
|
||||
* Constructs a Crop filter with given x, y, coordinates and crop width and
|
||||
* height values
|
||||
*
|
||||
* @param PointInterface $start
|
||||
* @param BoxInterface $size
|
||||
*/
|
||||
public function __construct(PointInterface $start, BoxInterface $size)
|
||||
{
|
||||
$this->start = $start;
|
||||
$this->size = $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->crop($this->start, $this->size);
|
||||
}
|
||||
}
|
||||
43
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Basic/Fill.php
Normal file
43
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Basic/Fill.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Filter\FilterInterface;
|
||||
use Imagine\Image\Fill\FillInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
|
||||
/**
|
||||
* A fill filter
|
||||
*/
|
||||
class Fill implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @var FillInterface
|
||||
*/
|
||||
private $fill;
|
||||
|
||||
/**
|
||||
* @param FillInterface $fill
|
||||
*/
|
||||
public function __construct(FillInterface $fill)
|
||||
{
|
||||
$this->fill = $fill;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->fill($this->fill);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A "flip horizontally" filter
|
||||
*/
|
||||
class FlipHorizontally implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->flipHorizontally();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A "flip vertically" filter
|
||||
*/
|
||||
class FlipVertically implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->flipVertically();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\PointInterface;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A paste filter
|
||||
*/
|
||||
class Paste implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @var ImageInterface
|
||||
*/
|
||||
private $image;
|
||||
|
||||
/**
|
||||
* @var PointInterface
|
||||
*/
|
||||
private $start;
|
||||
|
||||
/**
|
||||
* Constructs a Paste filter with given ImageInterface to paste and x, y
|
||||
* coordinates of target position
|
||||
*
|
||||
* @param ImageInterface $image
|
||||
* @param PointInterface $start
|
||||
*/
|
||||
public function __construct(ImageInterface $image, PointInterface $start)
|
||||
{
|
||||
$this->image = $image;
|
||||
$this->start = $start;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->paste($this->image, $this->start);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Filter\FilterInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\BoxInterface;
|
||||
|
||||
/**
|
||||
* A resize filter
|
||||
*/
|
||||
class Resize implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @var BoxInterface
|
||||
*/
|
||||
private $size;
|
||||
private $filter;
|
||||
|
||||
/**
|
||||
* Constructs Resize filter with given width and height
|
||||
*
|
||||
* @param BoxInterface $size
|
||||
* @param string $filter
|
||||
*/
|
||||
public function __construct(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED)
|
||||
{
|
||||
$this->size = $size;
|
||||
$this->filter = $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->resize($this->size, $this->filter);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A rotate filter
|
||||
*/
|
||||
class Rotate implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $angle;
|
||||
|
||||
/**
|
||||
* @var ColorInterface
|
||||
*/
|
||||
private $background;
|
||||
|
||||
/**
|
||||
* Constructs Rotate filter with given angle and background color
|
||||
*
|
||||
* @param integer $angle
|
||||
* @param ColorInterface $background
|
||||
*/
|
||||
public function __construct($angle, ColorInterface $background = null)
|
||||
{
|
||||
$this->angle = $angle;
|
||||
$this->background = $background;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->rotate($this->angle, $this->background);
|
||||
}
|
||||
}
|
||||
51
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Basic/Save.php
Normal file
51
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Basic/Save.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A save filter
|
||||
*/
|
||||
class Save implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $path;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs Save filter with given path and options
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct($path = null, array $options = array())
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->save($this->path, $this->options);
|
||||
}
|
||||
}
|
||||
51
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Basic/Show.php
Normal file
51
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Basic/Show.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A show filter
|
||||
*/
|
||||
class Show implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $format;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* Constructs the Show filter with given format and options
|
||||
*
|
||||
* @param string $format
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct($format, array $options = array())
|
||||
{
|
||||
$this->format = $format;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->show($this->format, $this->options);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A strip filter
|
||||
*/
|
||||
class Strip implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->strip();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A thumbnail filter
|
||||
*/
|
||||
class Thumbnail implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* @var BoxInterface
|
||||
*/
|
||||
private $size;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $mode;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $filter;
|
||||
|
||||
/**
|
||||
* Constructs the Thumbnail filter with given width, height and mode
|
||||
*
|
||||
* @param BoxInterface $size
|
||||
* @param string $mode
|
||||
* @param string $filter
|
||||
*/
|
||||
public function __construct(BoxInterface $size, $mode = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED)
|
||||
{
|
||||
$this->size = $size;
|
||||
$this->mode = $mode;
|
||||
$this->filter = $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return $image->thumbnail($this->size, $this->mode, $this->filter);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter\Basic;
|
||||
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\Palette\RGB;
|
||||
use Imagine\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A filter to render web-optimized images
|
||||
*/
|
||||
class WebOptimization implements FilterInterface
|
||||
{
|
||||
private $palette;
|
||||
private $path;
|
||||
private $options;
|
||||
|
||||
public function __construct($path = null, array $options = array())
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->options = array_replace(array(
|
||||
'resolution-units' => ImageInterface::RESOLUTION_PIXELSPERINCH,
|
||||
'resolution-y' => 72,
|
||||
'resolution-x' => 72,
|
||||
), $options);
|
||||
$this->palette = new RGB();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
$image
|
||||
->usePalette($this->palette)
|
||||
->strip();
|
||||
|
||||
if (is_callable($this->path)) {
|
||||
$path = call_user_func($this->path, $image);
|
||||
} elseif (null !== $this->path) {
|
||||
$path = $this->path;
|
||||
} else {
|
||||
return $image;
|
||||
}
|
||||
|
||||
return $image->save($path, $this->options);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter;
|
||||
|
||||
use Imagine\Image\ImageInterface;
|
||||
|
||||
/**
|
||||
* Interface for imagine filters
|
||||
*/
|
||||
interface FilterInterface
|
||||
{
|
||||
/**
|
||||
* Applies scheduled transformation to ImageInterface instance
|
||||
* Returns processed ImageInterface instance
|
||||
*
|
||||
* @param ImageInterface $image
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function apply(ImageInterface $image);
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Image\ImagineInterface;
|
||||
|
||||
/**
|
||||
* ImagineAware base class
|
||||
*/
|
||||
abstract class ImagineAware implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* An ImagineInterface instance.
|
||||
*
|
||||
* @var ImagineInterface
|
||||
*/
|
||||
private $imagine;
|
||||
|
||||
/**
|
||||
* Set ImagineInterface instance.
|
||||
*
|
||||
* @param ImagineInterface $imagine An ImagineInterface instance
|
||||
*/
|
||||
public function setImagine(ImagineInterface $imagine)
|
||||
{
|
||||
$this->imagine = $imagine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ImagineInterface instance.
|
||||
*
|
||||
* @return ImagineInterface
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function getImagine()
|
||||
{
|
||||
if (!$this->imagine instanceof ImagineInterface) {
|
||||
throw new InvalidArgumentException(sprintf('In order to use %s pass an Imagine\Image\ImagineInterface instance to filter constructor', get_class($this)));
|
||||
}
|
||||
|
||||
return $this->imagine;
|
||||
}
|
||||
}
|
||||
240
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Transformation.php
Normal file
240
rainloop/v/0.0.0/app/libraries/Imagine/Filter/Transformation.php
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Filter;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Filter\Basic\ApplyMask;
|
||||
use Imagine\Filter\Basic\Copy;
|
||||
use Imagine\Filter\Basic\Crop;
|
||||
use Imagine\Filter\Basic\Fill;
|
||||
use Imagine\Filter\Basic\FlipVertically;
|
||||
use Imagine\Filter\Basic\FlipHorizontally;
|
||||
use Imagine\Filter\Basic\Paste;
|
||||
use Imagine\Filter\Basic\Resize;
|
||||
use Imagine\Filter\Basic\Rotate;
|
||||
use Imagine\Filter\Basic\Save;
|
||||
use Imagine\Filter\Basic\Show;
|
||||
use Imagine\Filter\Basic\Strip;
|
||||
use Imagine\Filter\Basic\Thumbnail;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\ImagineInterface;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Fill\FillInterface;
|
||||
use Imagine\Image\ManipulatorInterface;
|
||||
use Imagine\Image\PointInterface;
|
||||
|
||||
/**
|
||||
* A transformation filter
|
||||
*/
|
||||
final class Transformation implements FilterInterface, ManipulatorInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $filters = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $sorted;
|
||||
|
||||
/**
|
||||
* An ImagineInterface instance.
|
||||
*
|
||||
* @var ImagineInterface
|
||||
*/
|
||||
private $imagine;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param ImagineInterface $imagine An ImagineInterface instance
|
||||
*/
|
||||
public function __construct(ImagineInterface $imagine = null)
|
||||
{
|
||||
$this->imagine = $imagine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a given FilterInterface onto given ImageInterface and returns
|
||||
* modified ImageInterface
|
||||
*
|
||||
* @param ImageInterface $image
|
||||
* @param FilterInterface $filter
|
||||
*
|
||||
* @return ImageInterface
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function applyFilter(ImageInterface $image, FilterInterface $filter)
|
||||
{
|
||||
if ($filter instanceof ImagineAware) {
|
||||
if ($this->imagine === null) {
|
||||
throw new InvalidArgumentException(sprintf('In order to use %s pass an Imagine\Image\ImagineInterface instance to Transformation constructor', get_class($filter)));
|
||||
}
|
||||
$filter->setImagine($this->imagine);
|
||||
}
|
||||
|
||||
return $filter->apply($image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of filters sorted by their priority. Filters with same priority will be returned in the order they were added.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
if (null === $this->sorted) {
|
||||
if (!empty($this->filters)) {
|
||||
ksort($this->filters);
|
||||
$this->sorted = call_user_func_array('array_merge', $this->filters);
|
||||
} else {
|
||||
$this->sorted = array();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->sorted;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(ImageInterface $image)
|
||||
{
|
||||
return array_reduce(
|
||||
$this->getFilters(),
|
||||
array($this, 'applyFilter'),
|
||||
$image
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function copy()
|
||||
{
|
||||
return $this->add(new Copy());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function crop(PointInterface $start, BoxInterface $size)
|
||||
{
|
||||
return $this->add(new Crop($start, $size));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function flipHorizontally()
|
||||
{
|
||||
return $this->add(new FlipHorizontally());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function flipVertically()
|
||||
{
|
||||
return $this->add(new FlipVertically());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function strip()
|
||||
{
|
||||
return $this->add(new Strip());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function paste(ImageInterface $image, PointInterface $start)
|
||||
{
|
||||
return $this->add(new Paste($image, $start));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyMask(ImageInterface $mask)
|
||||
{
|
||||
return $this->add(new ApplyMask($mask));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fill(FillInterface $fill)
|
||||
{
|
||||
return $this->add(new Fill($fill));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED)
|
||||
{
|
||||
return $this->add(new Resize($size, $filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rotate($angle, ColorInterface $background = null)
|
||||
{
|
||||
return $this->add(new Rotate($angle, $background));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save($path = null, array $options = array())
|
||||
{
|
||||
return $this->add(new Save($path, $options));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function show($format, array $options = array())
|
||||
{
|
||||
return $this->add(new Show($format, $options));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function thumbnail(BoxInterface $size, $mode = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED)
|
||||
{
|
||||
return $this->add(new Thumbnail($size, $mode, $filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a given FilterInterface in an internal array of filters for
|
||||
* later application to an instance of ImageInterface
|
||||
*
|
||||
* @param FilterInterface $filter
|
||||
* @param int $priority
|
||||
* @return Transformation
|
||||
*/
|
||||
public function add(FilterInterface $filter, $priority = 0)
|
||||
{
|
||||
$this->filters[$priority][] = $filter;
|
||||
$this->sorted = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
333
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Drawer.php
Normal file
333
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Drawer.php
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gd;
|
||||
|
||||
use Imagine\Draw\DrawerInterface;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\AbstractFont;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Palette\Color\RGB as RGBColor;
|
||||
use Imagine\Image\PointInterface;
|
||||
|
||||
/**
|
||||
* Drawer implementation using the GD library
|
||||
*/
|
||||
final class Drawer implements DrawerInterface
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $resource;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $info;
|
||||
|
||||
/**
|
||||
* Constructs Drawer with a given gd image resource
|
||||
*
|
||||
* @param resource $resource
|
||||
*/
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->loadGdInfo();
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1)
|
||||
{
|
||||
imagesetthickness($this->resource, max(1, (int) $thickness));
|
||||
|
||||
if (false === imagealphablending($this->resource, true)) {
|
||||
throw new RuntimeException('Draw arc operation failed');
|
||||
}
|
||||
|
||||
if (false === imagearc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color))) {
|
||||
imagealphablending($this->resource, false);
|
||||
throw new RuntimeException('Draw arc operation failed');
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, false)) {
|
||||
throw new RuntimeException('Draw arc operation failed');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function does not work properly because of a bug in GD
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
imagesetthickness($this->resource, max(1, (int) $thickness));
|
||||
|
||||
if ($fill) {
|
||||
$style = IMG_ARC_CHORD;
|
||||
} else {
|
||||
$style = IMG_ARC_CHORD | IMG_ARC_NOFILL;
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, true)) {
|
||||
throw new RuntimeException('Draw chord operation failed');
|
||||
}
|
||||
|
||||
if (false === imagefilledarc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color), $style)) {
|
||||
imagealphablending($this->resource, false);
|
||||
throw new RuntimeException('Draw chord operation failed');
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, false)) {
|
||||
throw new RuntimeException('Draw chord operation failed');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
imagesetthickness($this->resource, max(1, (int) $thickness));
|
||||
|
||||
if ($fill) {
|
||||
$callback = 'imagefilledellipse';
|
||||
} else {
|
||||
$callback = 'imageellipse';
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, true)) {
|
||||
throw new RuntimeException('Draw ellipse operation failed');
|
||||
}
|
||||
|
||||
if (false === $callback($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $this->getColor($color))) {
|
||||
imagealphablending($this->resource, false);
|
||||
throw new RuntimeException('Draw ellipse operation failed');
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, false)) {
|
||||
throw new RuntimeException('Draw ellipse operation failed');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1)
|
||||
{
|
||||
imagesetthickness($this->resource, max(1, (int) $thickness));
|
||||
|
||||
if (false === imagealphablending($this->resource, true)) {
|
||||
throw new RuntimeException('Draw line operation failed');
|
||||
}
|
||||
|
||||
if (false === imageline($this->resource, $start->getX(), $start->getY(), $end->getX(), $end->getY(), $this->getColor($color))) {
|
||||
imagealphablending($this->resource, false);
|
||||
throw new RuntimeException('Draw line operation failed');
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, false)) {
|
||||
throw new RuntimeException('Draw line operation failed');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
imagesetthickness($this->resource, max(1, (int) $thickness));
|
||||
|
||||
if ($fill) {
|
||||
$style = IMG_ARC_EDGED;
|
||||
} else {
|
||||
$style = IMG_ARC_EDGED | IMG_ARC_NOFILL;
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, true)) {
|
||||
throw new RuntimeException('Draw chord operation failed');
|
||||
}
|
||||
|
||||
if (false === imagefilledarc($this->resource, $center->getX(), $center->getY(), $size->getWidth(), $size->getHeight(), $start, $end, $this->getColor($color), $style)) {
|
||||
imagealphablending($this->resource, false);
|
||||
throw new RuntimeException('Draw chord operation failed');
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, false)) {
|
||||
throw new RuntimeException('Draw chord operation failed');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dot(PointInterface $position, ColorInterface $color)
|
||||
{
|
||||
if (false === imagealphablending($this->resource, true)) {
|
||||
throw new RuntimeException('Draw point operation failed');
|
||||
}
|
||||
|
||||
if (false === imagesetpixel($this->resource, $position->getX(), $position->getY(), $this->getColor($color))) {
|
||||
imagealphablending($this->resource, false);
|
||||
throw new RuntimeException('Draw point operation failed');
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, false)) {
|
||||
throw new RuntimeException('Draw point operation failed');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
imagesetthickness($this->resource, max(1, (int) $thickness));
|
||||
|
||||
if (count($coordinates) < 3) {
|
||||
throw new InvalidArgumentException(sprintf('A polygon must consist of at least 3 points, %d given', count($coordinates)));
|
||||
}
|
||||
|
||||
$points = call_user_func_array('array_merge', array_map(function (PointInterface $p) {
|
||||
return array($p->getX(), $p->getY());
|
||||
}, $coordinates));
|
||||
|
||||
if ($fill) {
|
||||
$callback = 'imagefilledpolygon';
|
||||
} else {
|
||||
$callback = 'imagepolygon';
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, true)) {
|
||||
throw new RuntimeException('Draw polygon operation failed');
|
||||
}
|
||||
|
||||
if (false === $callback($this->resource, $points, count($coordinates), $this->getColor($color))) {
|
||||
imagealphablending($this->resource, false);
|
||||
throw new RuntimeException('Draw polygon operation failed');
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, false)) {
|
||||
throw new RuntimeException('Draw polygon operation failed');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null)
|
||||
{
|
||||
if (!$this->info['FreeType Support']) {
|
||||
throw new RuntimeException('GD is not compiled with FreeType support');
|
||||
}
|
||||
|
||||
$angle = -1 * $angle;
|
||||
$fontsize = $font->getSize();
|
||||
$fontfile = $font->getFile();
|
||||
$x = $position->getX();
|
||||
$y = $position->getY() + $fontsize;
|
||||
|
||||
if ($width !== null) {
|
||||
$string = $this->wrapText($string, $font, $angle, $width);
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, true)) {
|
||||
throw new RuntimeException('Font mask operation failed');
|
||||
}
|
||||
|
||||
if (false === imagefttext($this->resource, $fontsize, $angle, $x, $y, $this->getColor($font->getColor()), $fontfile, $string)) {
|
||||
imagealphablending($this->resource, false);
|
||||
throw new RuntimeException('Font mask operation failed');
|
||||
}
|
||||
|
||||
if (false === imagealphablending($this->resource, false)) {
|
||||
throw new RuntimeException('Font mask operation failed');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Generates a GD color from Color instance
|
||||
*
|
||||
* @param ColorInterface $color
|
||||
*
|
||||
* @return resource
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function getColor(ColorInterface $color)
|
||||
{
|
||||
if (!$color instanceof RGBColor) {
|
||||
throw new InvalidArgumentException('GD driver only supports RGB colors');
|
||||
}
|
||||
|
||||
$gdColor = imagecolorallocatealpha($this->resource, $color->getRed(), $color->getGreen(), $color->getBlue(), (100 - $color->getAlpha()) * 127 / 100);
|
||||
if (false === $gdColor) {
|
||||
throw new RuntimeException(sprintf('Unable to allocate color "RGB(%s, %s, %s)" with transparency of %d percent', $color->getRed(), $color->getGreen(), $color->getBlue(), $color->getAlpha()));
|
||||
}
|
||||
|
||||
return $gdColor;
|
||||
}
|
||||
|
||||
private function loadGdInfo()
|
||||
{
|
||||
if (!function_exists('gd_info')) {
|
||||
throw new RuntimeException('Gd not installed');
|
||||
}
|
||||
|
||||
$this->info = gd_info();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Fits a string into box with given width
|
||||
*/
|
||||
private function wrapText($string, AbstractFont $font, $angle, $width)
|
||||
{
|
||||
$result = '';
|
||||
$words = explode(' ', $string);
|
||||
foreach ($words as $word) {
|
||||
$teststring = $result . ' ' . $word;
|
||||
$testbox = imagettfbbox($font->getSize(), $angle, $font->getFile(), $teststring);
|
||||
if ($testbox[2] > $width) {
|
||||
$result .= ($result == '' ? '' : "\n") . $word;
|
||||
} else {
|
||||
$result .= ($result == '' ? '' : ' ') . $word;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
109
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Effects.php
Normal file
109
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Effects.php
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gd;
|
||||
|
||||
use Imagine\Effects\EffectsInterface;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Palette\Color\RGB as RGBColor;
|
||||
|
||||
/**
|
||||
* Effects implementation using the GD library
|
||||
*/
|
||||
class Effects implements EffectsInterface
|
||||
{
|
||||
private $resource;
|
||||
|
||||
public function __construct($resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function gamma($correction)
|
||||
{
|
||||
if (false === imagegammacorrect($this->resource, 1.0, $correction)) {
|
||||
throw new RuntimeException('Failed to apply gamma correction to the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function negative()
|
||||
{
|
||||
if (false === imagefilter($this->resource, IMG_FILTER_NEGATE)) {
|
||||
throw new RuntimeException('Failed to negate the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function grayscale()
|
||||
{
|
||||
if (false === imagefilter($this->resource, IMG_FILTER_GRAYSCALE)) {
|
||||
throw new RuntimeException('Failed to grayscale the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function colorize(ColorInterface $color)
|
||||
{
|
||||
if (!$color instanceof RGBColor) {
|
||||
throw new RuntimeException('Colorize effects only accepts RGB color in GD context');
|
||||
}
|
||||
|
||||
if (false === imagefilter($this->resource, IMG_FILTER_COLORIZE, $color->getRed(), $color->getGreen(), $color->getBlue())) {
|
||||
throw new RuntimeException('Failed to colorize the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sharpen()
|
||||
{
|
||||
$sharpenMatrix = array(array(-1,-1,-1), array(-1,16,-1), array(-1,-1,-1));
|
||||
$divisor = array_sum(array_map('array_sum', $sharpenMatrix));
|
||||
|
||||
if (false === imageconvolution($this->resource, $sharpenMatrix, $divisor, 0)) {
|
||||
throw new RuntimeException('Failed to sharpen the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blur($sigma = 1)
|
||||
{
|
||||
if (false === imagefilter($this->resource, IMG_FILTER_GAUSSIAN_BLUR)) {
|
||||
throw new RuntimeException('Failed to blur the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
41
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Font.php
Normal file
41
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Font.php
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gd;
|
||||
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\AbstractFont;
|
||||
use Imagine\Image\Box;
|
||||
|
||||
/**
|
||||
* Font implementation using the GD library
|
||||
*/
|
||||
final class Font extends AbstractFont
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function box($string, $angle = 0)
|
||||
{
|
||||
if (!function_exists('imageftbbox')) {
|
||||
throw new RuntimeException('GD must have been compiled with `--with-freetype-dir` option to use the Font feature.');
|
||||
}
|
||||
|
||||
$angle = -1 * $angle;
|
||||
$info = imageftbbox($this->size, $angle, $this->file, $string);
|
||||
$xs = array($info[0], $info[2], $info[4], $info[6]);
|
||||
$ys = array($info[1], $info[3], $info[5], $info[7]);
|
||||
$width = abs(max($xs) - min($xs));
|
||||
$height = abs(max($ys) - min($ys));
|
||||
|
||||
return new Box($width, $height);
|
||||
}
|
||||
}
|
||||
735
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Image.php
Normal file
735
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Image.php
Normal file
|
|
@ -0,0 +1,735 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gd;
|
||||
|
||||
use Imagine\Image\AbstractImage;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\Box;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Metadata\MetadataBag;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Fill\FillInterface;
|
||||
use Imagine\Image\Point;
|
||||
use Imagine\Image\PointInterface;
|
||||
use Imagine\Image\Palette\PaletteInterface;
|
||||
use Imagine\Image\Palette\Color\RGB as RGBColor;
|
||||
use Imagine\Image\ProfileInterface;
|
||||
use Imagine\Image\Palette\RGB;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\OutOfBoundsException;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Image implementation using the GD library
|
||||
*/
|
||||
final class Image extends AbstractImage
|
||||
{
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
private $resource;
|
||||
|
||||
/**
|
||||
* @var Layers|null
|
||||
*/
|
||||
private $layers;
|
||||
|
||||
/**
|
||||
* @var PaletteInterface
|
||||
*/
|
||||
private $palette;
|
||||
|
||||
/**
|
||||
* Constructs a new Image instance
|
||||
*
|
||||
* @param resource $resource
|
||||
* @param PaletteInterface $palette
|
||||
* @param MetadataBag $metadata
|
||||
*/
|
||||
public function __construct($resource, PaletteInterface $palette, MetadataBag $metadata)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
$this->palette = $palette;
|
||||
$this->resource = $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure the current image resource is destroyed
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if (is_resource($this->resource) && 'gd' === get_resource_type($this->resource)) {
|
||||
imagedestroy($this->resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Gd resource
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
public function getGdResource()
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
final public function copy()
|
||||
{
|
||||
$size = $this->getSize();
|
||||
$copy = $this->createImage($size, 'copy');
|
||||
|
||||
if (false === imagecopy($copy, $this->resource, 0, 0, 0, 0, $size->getWidth(), $size->getHeight())) {
|
||||
throw new RuntimeException('Image copy operation failed');
|
||||
}
|
||||
|
||||
return new Image($copy, $this->palette, $this->metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
final public function crop(PointInterface $start, BoxInterface $size)
|
||||
{
|
||||
if (!$start->in($this->getSize())) {
|
||||
throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders');
|
||||
}
|
||||
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
$dest = $this->createImage($size, 'crop');
|
||||
|
||||
if (false === imagecopy($dest, $this->resource, 0, 0, $start->getX(), $start->getY(), $width, $height)) {
|
||||
throw new RuntimeException('Image crop operation failed');
|
||||
}
|
||||
|
||||
imagedestroy($this->resource);
|
||||
|
||||
$this->resource = $dest;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
final public function paste(ImageInterface $image, PointInterface $start)
|
||||
{
|
||||
if (!$image instanceof self) {
|
||||
throw new InvalidArgumentException(sprintf('Gd\Image can only paste() Gd\Image instances, %s given', get_class($image)));
|
||||
}
|
||||
|
||||
$size = $image->getSize();
|
||||
if (!$this->getSize()->contains($size, $start)) {
|
||||
throw new OutOfBoundsException('Cannot paste image of the given size at the specified position, as it moves outside of the current image\'s box');
|
||||
}
|
||||
|
||||
imagealphablending($this->resource, true);
|
||||
imagealphablending($image->resource, true);
|
||||
|
||||
if (false === imagecopy($this->resource, $image->resource, $start->getX(), $start->getY(), 0, 0, $size->getWidth(), $size->getHeight())) {
|
||||
throw new RuntimeException('Image paste operation failed');
|
||||
}
|
||||
|
||||
imagealphablending($this->resource, false);
|
||||
imagealphablending($image->resource, false);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
final public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED)
|
||||
{
|
||||
if (ImageInterface::FILTER_UNDEFINED !== $filter) {
|
||||
throw new InvalidArgumentException('Unsupported filter type, GD only supports ImageInterface::FILTER_UNDEFINED filter');
|
||||
}
|
||||
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
$dest = $this->createImage($size, 'resize');
|
||||
|
||||
imagealphablending($this->resource, true);
|
||||
imagealphablending($dest, true);
|
||||
|
||||
if (false === imagecopyresampled($dest, $this->resource, 0, 0, 0, 0, $width, $height, imagesx($this->resource), imagesy($this->resource))) {
|
||||
throw new RuntimeException('Image resize operation failed');
|
||||
}
|
||||
|
||||
imagealphablending($this->resource, false);
|
||||
imagealphablending($dest, false);
|
||||
|
||||
imagedestroy($this->resource);
|
||||
|
||||
$this->resource = $dest;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
final public function rotate($angle, ColorInterface $background = null)
|
||||
{
|
||||
$color = $background ? $background : $this->palette->color('fff');
|
||||
$resource = imagerotate($this->resource, -1 * $angle, $this->getColor($color));
|
||||
|
||||
if (false === $resource) {
|
||||
throw new RuntimeException('Image rotate operation failed');
|
||||
}
|
||||
|
||||
imagedestroy($this->resource);
|
||||
$this->resource = $resource;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
final public function save($path = null, array $options = array())
|
||||
{
|
||||
$path = null === $path ? (isset($this->metadata['filepath']) ? $this->metadata['filepath'] : $path) : $path;
|
||||
|
||||
if (null === $path) {
|
||||
throw new RuntimeException('You can omit save path only if image has been open from a file');
|
||||
}
|
||||
|
||||
if (isset($options['format'])) {
|
||||
$format = $options['format'];
|
||||
} elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) {
|
||||
$format = $extension;
|
||||
} else {
|
||||
$originalPath = isset($this->metadata['filepath']) ? $this->metadata['filepath'] : null;
|
||||
$format = pathinfo($originalPath, \PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
$this->saveOrOutput($format, $options, $path);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function show($format, array $options = array())
|
||||
{
|
||||
header('Content-type: '.$this->getMimeType($format));
|
||||
|
||||
$this->saveOrOutput($format, $options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($format, array $options = array())
|
||||
{
|
||||
ob_start();
|
||||
$this->saveOrOutput($format, $options);
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->get('png');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
final public function flipHorizontally()
|
||||
{
|
||||
$size = $this->getSize();
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
$dest = $this->createImage($size, 'flip');
|
||||
|
||||
for ($i = 0; $i < $width; $i++) {
|
||||
if (false === imagecopy($dest, $this->resource, $i, 0, ($width - 1) - $i, 0, 1, $height)) {
|
||||
throw new RuntimeException('Horizontal flip operation failed');
|
||||
}
|
||||
}
|
||||
|
||||
imagedestroy($this->resource);
|
||||
|
||||
$this->resource = $dest;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
final public function flipVertically()
|
||||
{
|
||||
$size = $this->getSize();
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
$dest = $this->createImage($size, 'flip');
|
||||
|
||||
for ($i = 0; $i < $height; $i++) {
|
||||
if (false === imagecopy($dest, $this->resource, 0, $i, 0, ($height - 1) - $i, $width, 1)) {
|
||||
throw new RuntimeException('Vertical flip operation failed');
|
||||
}
|
||||
}
|
||||
|
||||
imagedestroy($this->resource);
|
||||
|
||||
$this->resource = $dest;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
final public function strip()
|
||||
{
|
||||
// GD strips profiles and comment, so there's nothing to do here
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function draw()
|
||||
{
|
||||
return new Drawer($this->resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function effects()
|
||||
{
|
||||
return new Effects($this->resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return new Box(imagesx($this->resource), imagesy($this->resource));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function applyMask(ImageInterface $mask)
|
||||
{
|
||||
if (!$mask instanceof self) {
|
||||
throw new InvalidArgumentException('Cannot mask non-gd images');
|
||||
}
|
||||
|
||||
$size = $this->getSize();
|
||||
$maskSize = $mask->getSize();
|
||||
|
||||
if ($size != $maskSize) {
|
||||
throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, Current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size));
|
||||
}
|
||||
|
||||
for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) {
|
||||
for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) {
|
||||
$position = new Point($x, $y);
|
||||
$color = $this->getColorAt($position);
|
||||
$maskColor = $mask->getColorAt($position);
|
||||
$round = (int) round(max($color->getAlpha(), (100 - $color->getAlpha()) * $maskColor->getRed() / 255));
|
||||
|
||||
if (false === imagesetpixel($this->resource, $x, $y, $this->getColor($color->dissolve($round - $color->getAlpha())))) {
|
||||
throw new RuntimeException('Apply mask operation failed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function fill(FillInterface $fill)
|
||||
{
|
||||
$size = $this->getSize();
|
||||
|
||||
for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) {
|
||||
for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) {
|
||||
if (false === imagesetpixel($this->resource, $x, $y, $this->getColor($fill->getColor(new Point($x, $y))))) {
|
||||
throw new RuntimeException('Fill operation failed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function mask()
|
||||
{
|
||||
$mask = $this->copy();
|
||||
|
||||
if (false === imagefilter($mask->resource, IMG_FILTER_GRAYSCALE)) {
|
||||
throw new RuntimeException('Mask operation failed');
|
||||
}
|
||||
|
||||
return $mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function histogram()
|
||||
{
|
||||
$size = $this->getSize();
|
||||
$colors = array();
|
||||
|
||||
for ($x = 0, $width = $size->getWidth(); $x < $width; $x++) {
|
||||
for ($y = 0, $height = $size->getHeight(); $y < $height; $y++) {
|
||||
$colors[] = $this->getColorAt(new Point($x, $y));
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($colors);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getColorAt(PointInterface $point)
|
||||
{
|
||||
if (!$point->in($this->getSize())) {
|
||||
throw new RuntimeException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight()));
|
||||
}
|
||||
|
||||
$index = imagecolorat($this->resource, $point->getX(), $point->getY());
|
||||
$info = imagecolorsforindex($this->resource, $index);
|
||||
|
||||
return $this->palette->color(array($info['red'], $info['green'], $info['blue']), max(min(100 - (int) round($info['alpha'] / 127 * 100), 100), 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function layers()
|
||||
{
|
||||
if (null === $this->layers) {
|
||||
$this->layers = new Layers($this, $this->palette, $this->resource);
|
||||
}
|
||||
|
||||
return $this->layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
**/
|
||||
public function interlace($scheme)
|
||||
{
|
||||
static $supportedInterlaceSchemes = array(
|
||||
ImageInterface::INTERLACE_NONE => 0,
|
||||
ImageInterface::INTERLACE_LINE => 1,
|
||||
ImageInterface::INTERLACE_PLANE => 1,
|
||||
ImageInterface::INTERLACE_PARTITION => 1,
|
||||
);
|
||||
|
||||
if (!array_key_exists($scheme, $supportedInterlaceSchemes)) {
|
||||
throw new InvalidArgumentException('Unsupported interlace type');
|
||||
}
|
||||
|
||||
imageinterlace($this->resource, $supportedInterlaceSchemes[$scheme]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function palette()
|
||||
{
|
||||
return $this->palette;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function profile(ProfileInterface $profile)
|
||||
{
|
||||
throw new RuntimeException('GD driver does not support color profiles');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function usePalette(PaletteInterface $palette)
|
||||
{
|
||||
if (!$palette instanceof RGB) {
|
||||
throw new RuntimeException('GD driver only supports RGB palette');
|
||||
}
|
||||
|
||||
$this->palette = $palette;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Performs save or show operation using one of GD's image... functions
|
||||
*
|
||||
* @param string $format
|
||||
* @param array $options
|
||||
* @param string $filename
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function saveOrOutput($format, array $options, $filename = null)
|
||||
{
|
||||
$format = $this->normalizeFormat($format);
|
||||
|
||||
if (!$this->supported($format)) {
|
||||
throw new InvalidArgumentException(sprintf('Saving image in "%s" format is not supported, please use one of the following extensions: "%s"', $format, implode('", "', $this->supported())));
|
||||
}
|
||||
|
||||
$save = 'image'.$format;
|
||||
$args = array(&$this->resource, $filename);
|
||||
|
||||
// Preserve BC until version 1.0
|
||||
if (isset($options['quality']) && !isset($options['png_compression_level'])) {
|
||||
$options['png_compression_level'] = round((100 - $options['quality']) * 9 / 100);
|
||||
}
|
||||
if (isset($options['filters']) && !isset($options['png_compression_filter'])) {
|
||||
$options['png_compression_filter'] = $options['filters'];
|
||||
}
|
||||
|
||||
$options = $this->updateSaveOptions($options);
|
||||
|
||||
if ($format === 'jpeg' && isset($options['jpeg_quality'])) {
|
||||
$args[] = $options['jpeg_quality'];
|
||||
}
|
||||
|
||||
if ($format === 'png') {
|
||||
if (isset($options['png_compression_level'])) {
|
||||
if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) {
|
||||
throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9');
|
||||
}
|
||||
$args[] = $options['png_compression_level'];
|
||||
} else {
|
||||
$args[] = -1; // use default level
|
||||
}
|
||||
|
||||
if (isset($options['png_compression_filter'])) {
|
||||
if (~PNG_ALL_FILTERS & $options['png_compression_filter']) {
|
||||
throw new InvalidArgumentException('png_compression_filter option should be a combination of the PNG_FILTER_XXX constants');
|
||||
}
|
||||
$args[] = $options['png_compression_filter'];
|
||||
}
|
||||
}
|
||||
|
||||
if (($format === 'wbmp' || $format === 'xbm') && isset($options['foreground'])) {
|
||||
$args[] = $options['foreground'];
|
||||
}
|
||||
|
||||
$this->setExceptionHandler();
|
||||
|
||||
if (false === call_user_func_array($save, $args)) {
|
||||
throw new RuntimeException('Save operation failed');
|
||||
}
|
||||
|
||||
$this->resetExceptionHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Generates a GD image
|
||||
*
|
||||
* @param BoxInterface $size
|
||||
* @param string the operation initiating the creation
|
||||
*
|
||||
* @return resource
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
*/
|
||||
private function createImage(BoxInterface $size, $operation)
|
||||
{
|
||||
$resource = imagecreatetruecolor($size->getWidth(), $size->getHeight());
|
||||
|
||||
if (false === $resource) {
|
||||
throw new RuntimeException('Image '.$operation.' failed');
|
||||
}
|
||||
|
||||
if (false === imagealphablending($resource, false) || false === imagesavealpha($resource, true)) {
|
||||
throw new RuntimeException('Image '.$operation.' failed');
|
||||
}
|
||||
|
||||
if (function_exists('imageantialias')) {
|
||||
imageantialias($resource, true);
|
||||
}
|
||||
|
||||
$transparent = imagecolorallocatealpha($resource, 255, 255, 255, 127);
|
||||
imagefill($resource, 0, 0, $transparent);
|
||||
imagecolortransparent($resource, $transparent);
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Generates a GD color from Color instance
|
||||
*
|
||||
* @param ColorInterface $color
|
||||
*
|
||||
* @return integer A color identifier
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function getColor(ColorInterface $color)
|
||||
{
|
||||
if (!$color instanceof RGBColor) {
|
||||
throw new InvalidArgumentException('GD driver only supports RGB colors');
|
||||
}
|
||||
|
||||
$index = imagecolorallocatealpha($this->resource, $color->getRed(), $color->getGreen(), $color->getBlue(), round(127 * (100 - $color->getAlpha()) / 100));
|
||||
|
||||
if (false === $index) {
|
||||
throw new RuntimeException(sprintf('Unable to allocate color "RGB(%s, %s, %s)" with transparency of %d percent', $color->getRed(), $color->getGreen(), $color->getBlue(), $color->getAlpha()));
|
||||
}
|
||||
|
||||
return $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Normalizes a given format name
|
||||
*
|
||||
* @param string $format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function normalizeFormat($format)
|
||||
{
|
||||
$format = strtolower($format);
|
||||
|
||||
if ('jpg' === $format || 'pjpeg' === $format) {
|
||||
$format = 'jpeg';
|
||||
}
|
||||
|
||||
return $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Checks whether a given format is supported by GD library
|
||||
*
|
||||
* @param string $format
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
private function supported($format = null)
|
||||
{
|
||||
$formats = array('gif', 'jpeg', 'png', 'wbmp', 'xbm');
|
||||
|
||||
if (null === $format) {
|
||||
return $formats;
|
||||
}
|
||||
|
||||
return in_array($format, $formats);
|
||||
}
|
||||
|
||||
private function setExceptionHandler()
|
||||
{
|
||||
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
|
||||
if (0 === error_reporting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new RuntimeException($errstr, $errno, new \ErrorException($errstr, 0, $errno, $errfile, $errline));
|
||||
}, E_WARNING | E_NOTICE);
|
||||
}
|
||||
|
||||
private function resetExceptionHandler()
|
||||
{
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Get the mime type based on format.
|
||||
*
|
||||
* @param string $format
|
||||
*
|
||||
* @return string mime-type
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function getMimeType($format)
|
||||
{
|
||||
$format = $this->normalizeFormat($format);
|
||||
|
||||
if (!$this->supported($format)) {
|
||||
throw new RuntimeException('Invalid format');
|
||||
}
|
||||
|
||||
static $mimeTypes = array(
|
||||
'jpeg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'png' => 'image/png',
|
||||
'wbmp' => 'image/vnd.wap.wbmp',
|
||||
'xbm' => 'image/xbm',
|
||||
);
|
||||
|
||||
return $mimeTypes[$format];
|
||||
}
|
||||
}
|
||||
195
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Imagine.php
Normal file
195
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Imagine.php
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gd;
|
||||
|
||||
use Imagine\Image\AbstractImagine;
|
||||
use Imagine\Image\Metadata\MetadataBag;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Palette\RGB;
|
||||
use Imagine\Image\Palette\PaletteInterface;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Palette\Color\RGB as RGBColor;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Imagine implementation using the GD library
|
||||
*/
|
||||
final class Imagine extends AbstractImagine
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $info;
|
||||
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->loadGdInfo();
|
||||
$this->requireGdVersion('2.0.1');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function create(BoxInterface $size, ColorInterface $color = null)
|
||||
{
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
$resource = imagecreatetruecolor($width, $height);
|
||||
|
||||
if (false === $resource) {
|
||||
throw new RuntimeException('Create operation failed');
|
||||
}
|
||||
|
||||
$palette = null !== $color ? $color->getPalette() : new RGB();
|
||||
$color = $color ? $color : $palette->color('fff');
|
||||
|
||||
if (!$color instanceof RGBColor) {
|
||||
throw new InvalidArgumentException('GD driver only supports RGB colors');
|
||||
}
|
||||
|
||||
$index = imagecolorallocatealpha($resource, $color->getRed(), $color->getGreen(), $color->getBlue(), round(127 * (100 - $color->getAlpha()) / 100));
|
||||
|
||||
if (false === $index) {
|
||||
throw new RuntimeException('Unable to allocate color');
|
||||
}
|
||||
|
||||
if (false === imagefill($resource, 0, 0, $index)) {
|
||||
throw new RuntimeException('Could not set background color fill');
|
||||
}
|
||||
|
||||
if ($color->getAlpha() >= 95) {
|
||||
imagecolortransparent($resource, $index);
|
||||
}
|
||||
|
||||
return $this->wrap($resource, $palette, new MetadataBag());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function open($path)
|
||||
{
|
||||
$path = $this->checkPath($path);
|
||||
$data = @file_get_contents($path);
|
||||
|
||||
if (false === $data) {
|
||||
throw new RuntimeException(sprintf('Failed to open file %s', $path));
|
||||
}
|
||||
|
||||
$resource = @imagecreatefromstring($data);
|
||||
|
||||
if (!is_resource($resource)) {
|
||||
throw new RuntimeException(sprintf('Unable to open image %s', $path));
|
||||
}
|
||||
|
||||
return $this->wrap($resource, new RGB(), $this->getMetadataReader()->readFile($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($string)
|
||||
{
|
||||
return $this->doLoad($string, $this->getMetadataReader()->readData($string));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($resource)
|
||||
{
|
||||
if (!is_resource($resource)) {
|
||||
throw new InvalidArgumentException('Variable does not contain a stream resource');
|
||||
}
|
||||
|
||||
$content = stream_get_contents($resource);
|
||||
|
||||
if (false === $content) {
|
||||
throw new InvalidArgumentException('Cannot read resource content');
|
||||
}
|
||||
|
||||
return $this->doLoad($content, $this->getMetadataReader()->readStream($resource));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function font($file, $size, ColorInterface $color)
|
||||
{
|
||||
if (!$this->info['FreeType Support']) {
|
||||
throw new RuntimeException('GD is not compiled with FreeType support');
|
||||
}
|
||||
|
||||
return new Font($file, $size, $color);
|
||||
}
|
||||
|
||||
private function wrap($resource, PaletteInterface $palette, MetadataBag $metadata)
|
||||
{
|
||||
if (!imageistruecolor($resource)) {
|
||||
list($width, $height) = array(imagesx($resource), imagesy($resource));
|
||||
|
||||
// create transparent truecolor canvas
|
||||
$truecolor = imagecreatetruecolor($width, $height);
|
||||
$transparent = imagecolorallocatealpha($truecolor, 255, 255, 255, 127);
|
||||
|
||||
imagefill($truecolor, 0, 0, $transparent);
|
||||
imagecolortransparent($truecolor, $transparent);
|
||||
|
||||
imagecopymerge($truecolor, $resource, 0, 0, 0, 0, $width, $height, 100);
|
||||
|
||||
imagedestroy($resource);
|
||||
$resource = $truecolor;
|
||||
}
|
||||
|
||||
if (false === imagealphablending($resource, false) || false === imagesavealpha($resource, true)) {
|
||||
throw new RuntimeException('Could not set alphablending, savealpha and antialias values');
|
||||
}
|
||||
|
||||
if (function_exists('imageantialias')) {
|
||||
imageantialias($resource, true);
|
||||
}
|
||||
|
||||
return new Image($resource, $palette, $metadata);
|
||||
}
|
||||
|
||||
private function loadGdInfo()
|
||||
{
|
||||
if (!function_exists('gd_info')) {
|
||||
throw new RuntimeException('Gd not installed');
|
||||
}
|
||||
|
||||
$this->info = gd_info();
|
||||
}
|
||||
|
||||
private function requireGdVersion($version)
|
||||
{
|
||||
if (version_compare(GD_VERSION, $version, '<')) {
|
||||
throw new RuntimeException(sprintf('GD2 version %s or higher is required', $version));
|
||||
}
|
||||
}
|
||||
|
||||
private function doLoad($string, MetadataBag $metadata)
|
||||
{
|
||||
$resource = @imagecreatefromstring($string);
|
||||
|
||||
if (!is_resource($resource)) {
|
||||
throw new RuntimeException('An image could not be created from the given input');
|
||||
}
|
||||
|
||||
return $this->wrap($resource, new RGB(), $metadata);
|
||||
}
|
||||
}
|
||||
144
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Layers.php
Normal file
144
rainloop/v/0.0.0/app/libraries/Imagine/Gd/Layers.php
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gd;
|
||||
|
||||
use Imagine\Image\AbstractLayers;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\Metadata\MetadataBag;
|
||||
use Imagine\Image\Palette\PaletteInterface;
|
||||
use Imagine\Exception\NotSupportedException;
|
||||
|
||||
class Layers extends AbstractLayers
|
||||
{
|
||||
private $image;
|
||||
private $offset;
|
||||
private $resource;
|
||||
private $palette;
|
||||
|
||||
public function __construct(Image $image, PaletteInterface $palette, $resource)
|
||||
{
|
||||
if (!is_resource($resource)) {
|
||||
throw new RuntimeException('Invalid Gd resource provided');
|
||||
}
|
||||
|
||||
$this->image = $image;
|
||||
$this->resource = $resource;
|
||||
$this->offset = 0;
|
||||
$this->palette = $palette;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function merge()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function coalesce()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function animate($format, $delay, $loops)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return new Image($this->resource, $this->palette, new MetadataBag());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
++$this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->offset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->offset < 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return 0 === $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
if (0 === $offset) {
|
||||
return new Image($this->resource, $this->palette, new MetadataBag());
|
||||
}
|
||||
|
||||
throw new RuntimeException('GD only supports one layer at offset 0');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
throw new NotSupportedException('GD does not support layer set');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
throw new NotSupportedException('GD does not support layer unset');
|
||||
}
|
||||
}
|
||||
356
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Drawer.php
Normal file
356
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Drawer.php
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gmagick;
|
||||
|
||||
use Imagine\Draw\DrawerInterface;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\NotSupportedException;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\AbstractFont;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Point;
|
||||
use Imagine\Image\PointInterface;
|
||||
|
||||
/**
|
||||
* Drawer implementation using the Gmagick PHP extension
|
||||
*/
|
||||
final class Drawer implements DrawerInterface
|
||||
{
|
||||
/**
|
||||
* @var \Gmagick
|
||||
*/
|
||||
private $gmagick;
|
||||
|
||||
/**
|
||||
* @param \Gmagick $gmagick
|
||||
*/
|
||||
public function __construct(\Gmagick $gmagick)
|
||||
{
|
||||
$this->gmagick = $gmagick;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1)
|
||||
{
|
||||
$x = $center->getX();
|
||||
$y = $center->getY();
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$arc = new \GmagickDraw();
|
||||
|
||||
$arc->setstrokecolor($pixel);
|
||||
$arc->setstrokewidth(max(1, (int) $thickness));
|
||||
$arc->setfillcolor('transparent');
|
||||
$arc->arc(
|
||||
$x - $width / 2,
|
||||
$y - $height / 2,
|
||||
$x + $width / 2,
|
||||
$y + $height / 2,
|
||||
$start,
|
||||
$end
|
||||
);
|
||||
|
||||
$this->gmagick->drawImage($arc);
|
||||
|
||||
$pixel = null;
|
||||
|
||||
$arc = null;
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Draw arc operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
$x = $center->getX();
|
||||
$y = $center->getY();
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$chord = new \GmagickDraw();
|
||||
|
||||
$chord->setstrokecolor($pixel);
|
||||
$chord->setstrokewidth(max(1, (int) $thickness));
|
||||
|
||||
if ($fill) {
|
||||
$chord->setfillcolor($pixel);
|
||||
} else {
|
||||
$x1 = round($x + $width / 2 * cos(deg2rad($start)));
|
||||
$y1 = round($y + $height / 2 * sin(deg2rad($start)));
|
||||
$x2 = round($x + $width / 2 * cos(deg2rad($end)));
|
||||
$y2 = round($y + $height / 2 * sin(deg2rad($end)));
|
||||
|
||||
$this->line(new Point($x1, $y1), new Point($x2, $y2), $color);
|
||||
|
||||
$chord->setfillcolor('transparent');
|
||||
}
|
||||
|
||||
$chord->arc($x - $width / 2, $y - $height / 2, $x + $width / 2, $y + $height / 2, $start, $end);
|
||||
|
||||
$this->gmagick->drawImage($chord);
|
||||
|
||||
$pixel = null;
|
||||
|
||||
$chord = null;
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Draw chord operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$ellipse = new \GmagickDraw();
|
||||
|
||||
$ellipse->setstrokecolor($pixel);
|
||||
$ellipse->setstrokewidth(max(1, (int) $thickness));
|
||||
|
||||
if ($fill) {
|
||||
$ellipse->setfillcolor($pixel);
|
||||
} else {
|
||||
$ellipse->setfillcolor('transparent');
|
||||
}
|
||||
|
||||
$ellipse->ellipse(
|
||||
$center->getX(),
|
||||
$center->getY(),
|
||||
$width / 2,
|
||||
$height / 2,
|
||||
0, 360
|
||||
);
|
||||
|
||||
$this->gmagick->drawImage($ellipse);
|
||||
|
||||
$pixel = null;
|
||||
|
||||
$ellipse = null;
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Draw ellipse operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1)
|
||||
{
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$line = new \GmagickDraw();
|
||||
|
||||
$line->setstrokecolor($pixel);
|
||||
$line->setstrokewidth(max(1, (int) $thickness));
|
||||
$line->setfillcolor($pixel);
|
||||
$line->line(
|
||||
$start->getX(),
|
||||
$start->getY(),
|
||||
$end->getX(),
|
||||
$end->getY()
|
||||
);
|
||||
|
||||
$this->gmagick->drawImage($line);
|
||||
|
||||
$pixel = null;
|
||||
|
||||
$line = null;
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Draw line operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
$x1 = round($center->getX() + $width / 2 * cos(deg2rad($start)));
|
||||
$y1 = round($center->getY() + $height / 2 * sin(deg2rad($start)));
|
||||
$x2 = round($center->getX() + $width / 2 * cos(deg2rad($end)));
|
||||
$y2 = round($center->getY() + $height / 2 * sin(deg2rad($end)));
|
||||
|
||||
if ($fill) {
|
||||
$this->chord($center, $size, $start, $end, $color, true, $thickness);
|
||||
$this->polygon(
|
||||
array(
|
||||
$center,
|
||||
new Point($x1, $y1),
|
||||
new Point($x2, $y2),
|
||||
),
|
||||
$color,
|
||||
true,
|
||||
$thickness
|
||||
);
|
||||
} else {
|
||||
$this->arc($center, $size, $start, $end, $color, $thickness);
|
||||
$this->line($center, new Point($x1, $y1), $color, $thickness);
|
||||
$this->line($center, new Point($x2, $y2), $color, $thickness);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dot(PointInterface $position, ColorInterface $color)
|
||||
{
|
||||
$x = $position->getX();
|
||||
$y = $position->getY();
|
||||
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$point = new \GmagickDraw();
|
||||
|
||||
$point->setfillcolor($pixel);
|
||||
$point->point($x, $y);
|
||||
|
||||
$this->gmagick->drawimage($point);
|
||||
|
||||
$pixel = null;
|
||||
$point = null;
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Draw point operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
if (count($coordinates) < 3) {
|
||||
throw new InvalidArgumentException(sprintf('Polygon must consist of at least 3 coordinates, %d given', count($coordinates)));
|
||||
}
|
||||
|
||||
$points = array_map(function (PointInterface $p) {
|
||||
return array('x' => $p->getX(), 'y' => $p->getY());
|
||||
}, $coordinates);
|
||||
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$polygon = new \GmagickDraw();
|
||||
|
||||
$polygon->setstrokecolor($pixel);
|
||||
$polygon->setstrokewidth(max(1, (int) $thickness));
|
||||
|
||||
if ($fill) {
|
||||
$polygon->setfillcolor($pixel);
|
||||
} else {
|
||||
$polygon->setfillcolor('transparent');
|
||||
}
|
||||
|
||||
$polygon->polygon($points);
|
||||
|
||||
$this->gmagick->drawImage($polygon);
|
||||
|
||||
unset($pixel, $polygon);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Draw polygon operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null)
|
||||
{
|
||||
try {
|
||||
$pixel = $this->getColor($font->getColor());
|
||||
$text = new \GmagickDraw();
|
||||
|
||||
$text->setfont($font->getFile());
|
||||
/**
|
||||
* @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027
|
||||
*
|
||||
* ensure font resolution is the same as GD's hard-coded 96
|
||||
*/
|
||||
$text->setfontsize((int) ($font->getSize() * (96 / 72)));
|
||||
$text->setfillcolor($pixel);
|
||||
|
||||
$info = $this->gmagick->queryfontmetrics($text, $string);
|
||||
$rad = deg2rad($angle);
|
||||
$cos = cos($rad);
|
||||
$sin = sin($rad);
|
||||
|
||||
$x1 = round(0 * $cos - 0 * $sin);
|
||||
$x2 = round($info['textWidth'] * $cos - $info['textHeight'] * $sin);
|
||||
$y1 = round(0 * $sin + 0 * $cos);
|
||||
$y2 = round($info['textWidth'] * $sin + $info['textHeight'] * $cos);
|
||||
|
||||
$xdiff = 0 - min($x1, $x2);
|
||||
$ydiff = 0 - min($y1, $y2);
|
||||
|
||||
if ($width !== null) {
|
||||
throw new NotSupportedException('Gmagick doesn\'t support queryfontmetrics function for multiline text', 1);
|
||||
}
|
||||
|
||||
$this->gmagick->annotateimage($text, $position->getX() + $x1 + $xdiff, $position->getY() + $y2 + $ydiff, $angle, $string);
|
||||
|
||||
unset($pixel, $text);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Draw text operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets specifically formatted color string from Color instance
|
||||
*
|
||||
* @param ColorInterface $color
|
||||
*
|
||||
* @return \GmagickPixel
|
||||
*
|
||||
* @throws InvalidArgumentException In case a non-opaque color is passed
|
||||
*/
|
||||
private function getColor(ColorInterface $color)
|
||||
{
|
||||
if (!$color->isOpaque()) {
|
||||
throw new InvalidArgumentException('Gmagick doesn\'t support transparency');
|
||||
}
|
||||
|
||||
return new \GmagickPixel((string) $color);
|
||||
}
|
||||
}
|
||||
106
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Effects.php
Normal file
106
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Effects.php
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gmagick;
|
||||
|
||||
use Imagine\Effects\EffectsInterface;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Exception\NotSupportedException;
|
||||
|
||||
/**
|
||||
* Effects implementation using the Gmagick PHP extension
|
||||
*/
|
||||
class Effects implements EffectsInterface
|
||||
{
|
||||
private $gmagick;
|
||||
|
||||
public function __construct(\Gmagick $gmagick)
|
||||
{
|
||||
$this->gmagick = $gmagick;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function gamma($correction)
|
||||
{
|
||||
try {
|
||||
$this->gmagick->gammaimage($correction);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Failed to apply gamma correction to the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function negative()
|
||||
{
|
||||
if (!method_exists($this->gmagick, 'negateimage')) {
|
||||
throw new NotSupportedException('Gmagick version 1.1.0 RC3 is required for negative effect');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->gmagick->negateimage(false, \Gmagick::CHANNEL_ALL);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Failed to negate the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function grayscale()
|
||||
{
|
||||
try {
|
||||
$this->gmagick->setImageType(2);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Failed to grayscale the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function colorize(ColorInterface $color)
|
||||
{
|
||||
throw new NotSupportedException('Gmagick does not support colorize');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sharpen()
|
||||
{
|
||||
throw new NotSupportedException('Gmagick does not support sharpen yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blur($sigma = 1)
|
||||
{
|
||||
try {
|
||||
$this->gmagick->blurImage(0, $sigma);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Failed to blur the image', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
63
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Font.php
Normal file
63
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Font.php
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gmagick;
|
||||
|
||||
use Imagine\Image\AbstractFont;
|
||||
use Imagine\Image\Box;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
|
||||
/**
|
||||
* Font implementation using the Gmagick PHP extension
|
||||
*/
|
||||
final class Font extends AbstractFont
|
||||
{
|
||||
/**
|
||||
* @var \Gmagick
|
||||
*/
|
||||
private $gmagick;
|
||||
|
||||
/**
|
||||
* @param \Gmagick $gmagick
|
||||
* @param string $file
|
||||
* @param integer $size
|
||||
* @param ColorInterface $color
|
||||
*/
|
||||
public function __construct(\Gmagick $gmagick, $file, $size, ColorInterface $color)
|
||||
{
|
||||
$this->gmagick = $gmagick;
|
||||
|
||||
parent::__construct($file, $size, $color);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function box($string, $angle = 0)
|
||||
{
|
||||
$text = new \GmagickDraw();
|
||||
|
||||
$text->setfont($this->file);
|
||||
/**
|
||||
* @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027
|
||||
*
|
||||
* ensure font resolution is the same as GD's hard-coded 96
|
||||
*/
|
||||
$text->setfontsize((int) ($this->size * (96 / 72)));
|
||||
$text->setfontstyle(\Gmagick::STYLE_OBLIQUE);
|
||||
|
||||
$info = $this->gmagick->queryfontmetrics($text, $string);
|
||||
|
||||
$box = new Box($info['textWidth'], $info['textHeight']);
|
||||
|
||||
return $box;
|
||||
}
|
||||
}
|
||||
786
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Image.php
Normal file
786
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Image.php
Normal file
|
|
@ -0,0 +1,786 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gmagick;
|
||||
|
||||
use Imagine\Exception\OutOfBoundsException;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\AbstractImage;
|
||||
use Imagine\Image\Metadata\MetadataBag;
|
||||
use Imagine\Image\Palette\PaletteInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\Box;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Fill\FillInterface;
|
||||
use Imagine\Image\Point;
|
||||
use Imagine\Image\PointInterface;
|
||||
use Imagine\Image\ProfileInterface;
|
||||
|
||||
/**
|
||||
* Image implementation using the Gmagick PHP extension
|
||||
*/
|
||||
final class Image extends AbstractImage
|
||||
{
|
||||
/**
|
||||
* @var \Gmagick
|
||||
*/
|
||||
private $gmagick;
|
||||
/**
|
||||
* @var Layers
|
||||
*/
|
||||
private $layers;
|
||||
|
||||
/**
|
||||
* @var PaletteInterface
|
||||
*/
|
||||
private $palette;
|
||||
|
||||
private static $colorspaceMapping = array(
|
||||
PaletteInterface::PALETTE_CMYK => \Gmagick::COLORSPACE_CMYK,
|
||||
PaletteInterface::PALETTE_RGB => \Gmagick::COLORSPACE_RGB,
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructs a new Image instance
|
||||
*
|
||||
* @param \Gmagick $gmagick
|
||||
* @param PaletteInterface $palette
|
||||
* @param MetadataBag $metadata
|
||||
*/
|
||||
public function __construct(\Gmagick $gmagick, PaletteInterface $palette, MetadataBag $metadata)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
$this->gmagick = $gmagick;
|
||||
$this->setColorspace($palette);
|
||||
$this->layers = new Layers($this, $this->palette, $this->gmagick);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys allocated gmagick resources
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->gmagick instanceof \Gmagick) {
|
||||
$this->gmagick->clear();
|
||||
$this->gmagick->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns gmagick instance
|
||||
*
|
||||
* @return Gmagick
|
||||
*/
|
||||
public function getGmagick()
|
||||
{
|
||||
return $this->gmagick;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function copy()
|
||||
{
|
||||
return new self(clone $this->gmagick, $this->palette, clone $this->metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function crop(PointInterface $start, BoxInterface $size)
|
||||
{
|
||||
if (!$start->in($this->getSize())) {
|
||||
throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->gmagick->cropimage($size->getWidth(), $size->getHeight(), $start->getX(), $start->getY());
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Crop operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function flipHorizontally()
|
||||
{
|
||||
try {
|
||||
$this->gmagick->flopimage();
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Horizontal flip operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function flipVertically()
|
||||
{
|
||||
try {
|
||||
$this->gmagick->flipimage();
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Vertical flip operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function strip()
|
||||
{
|
||||
try {
|
||||
try {
|
||||
$this->profile($this->palette->profile());
|
||||
} catch (\Exception $e) {
|
||||
// here we discard setting the profile as the previous incorporated profile
|
||||
// is corrupted, let's now strip the image
|
||||
}
|
||||
$this->gmagick->stripimage();
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Strip operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function paste(ImageInterface $image, PointInterface $start)
|
||||
{
|
||||
if (!$image instanceof self) {
|
||||
throw new InvalidArgumentException(sprintf('Gmagick\Image can only paste() Gmagick\Image instances, %s given', get_class($image)));
|
||||
}
|
||||
|
||||
if (!$this->getSize()->contains($image->getSize(), $start)) {
|
||||
throw new OutOfBoundsException('Cannot paste image of the given size at the specified position, as it moves outside of the current image\'s box');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->gmagick->compositeimage($image->gmagick, \Gmagick::COMPOSITE_DEFAULT, $start->getX(), $start->getY());
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Paste operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED)
|
||||
{
|
||||
static $supportedFilters = array(
|
||||
ImageInterface::FILTER_UNDEFINED => \Gmagick::FILTER_UNDEFINED,
|
||||
ImageInterface::FILTER_BESSEL => \Gmagick::FILTER_BESSEL,
|
||||
ImageInterface::FILTER_BLACKMAN => \Gmagick::FILTER_BLACKMAN,
|
||||
ImageInterface::FILTER_BOX => \Gmagick::FILTER_BOX,
|
||||
ImageInterface::FILTER_CATROM => \Gmagick::FILTER_CATROM,
|
||||
ImageInterface::FILTER_CUBIC => \Gmagick::FILTER_CUBIC,
|
||||
ImageInterface::FILTER_GAUSSIAN => \Gmagick::FILTER_GAUSSIAN,
|
||||
ImageInterface::FILTER_HANNING => \Gmagick::FILTER_HANNING,
|
||||
ImageInterface::FILTER_HAMMING => \Gmagick::FILTER_HAMMING,
|
||||
ImageInterface::FILTER_HERMITE => \Gmagick::FILTER_HERMITE,
|
||||
ImageInterface::FILTER_LANCZOS => \Gmagick::FILTER_LANCZOS,
|
||||
ImageInterface::FILTER_MITCHELL => \Gmagick::FILTER_MITCHELL,
|
||||
ImageInterface::FILTER_POINT => \Gmagick::FILTER_POINT,
|
||||
ImageInterface::FILTER_QUADRATIC => \Gmagick::FILTER_QUADRATIC,
|
||||
ImageInterface::FILTER_SINC => \Gmagick::FILTER_SINC,
|
||||
ImageInterface::FILTER_TRIANGLE => \Gmagick::FILTER_TRIANGLE
|
||||
);
|
||||
|
||||
if (!array_key_exists($filter, $supportedFilters)) {
|
||||
throw new InvalidArgumentException('Unsupported filter type');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->gmagick->resizeimage($size->getWidth(), $size->getHeight(), $supportedFilters[$filter], 1);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Resize operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function rotate($angle, ColorInterface $background = null)
|
||||
{
|
||||
try {
|
||||
$background = $background ?: $this->palette->color('fff');
|
||||
$pixel = $this->getColor($background);
|
||||
|
||||
$this->gmagick->rotateimage($pixel, $angle);
|
||||
|
||||
unset($pixel);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Rotate operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Applies options before save or output
|
||||
*
|
||||
* @param \Gmagick $image
|
||||
* @param array $options
|
||||
* @param string $path
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function applyImageOptions(\Gmagick $image, array $options, $path)
|
||||
{
|
||||
if (isset($options['format'])) {
|
||||
$format = $options['format'];
|
||||
} elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) {
|
||||
$format = $extension;
|
||||
} else {
|
||||
$format = pathinfo($image->getImageFilename(), \PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
$format = strtolower($format);
|
||||
|
||||
$options = $this->updateSaveOptions($options);
|
||||
|
||||
if (isset($options['jpeg_quality']) && in_array($format, array('jpeg', 'jpg', 'pjpeg'))) {
|
||||
$image->setCompressionQuality($options['jpeg_quality']);
|
||||
}
|
||||
|
||||
if ((isset($options['png_compression_level']) || isset($options['png_compression_filter'])) && $format === 'png') {
|
||||
// first digit: compression level (default: 7)
|
||||
if (isset($options['png_compression_level'])) {
|
||||
if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) {
|
||||
throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9');
|
||||
}
|
||||
$compression = $options['png_compression_level'] * 10;
|
||||
} else {
|
||||
$compression = 70;
|
||||
}
|
||||
|
||||
// second digit: compression filter (default: 5)
|
||||
if (isset($options['png_compression_filter'])) {
|
||||
if ($options['png_compression_filter'] < 0 || $options['png_compression_filter'] > 9) {
|
||||
throw new InvalidArgumentException('png_compression_filter option should be an integer from 0 to 9');
|
||||
}
|
||||
$compression += $options['png_compression_filter'];
|
||||
} else {
|
||||
$compression += 5;
|
||||
}
|
||||
|
||||
$image->setCompressionQuality($compression);
|
||||
}
|
||||
|
||||
if (isset($options['resolution-units']) && isset($options['resolution-x']) && isset($options['resolution-y'])) {
|
||||
if ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERCENTIMETER) {
|
||||
$image->setimageunits(\Gmagick::RESOLUTION_PIXELSPERCENTIMETER);
|
||||
} elseif ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERINCH) {
|
||||
$image->setimageunits(\Gmagick::RESOLUTION_PIXELSPERINCH);
|
||||
} else {
|
||||
throw new InvalidArgumentException('Unsupported image unit format');
|
||||
}
|
||||
|
||||
$image->setimageresolution($options['resolution-x'], $options['resolution-y']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function save($path = null, array $options = array())
|
||||
{
|
||||
$path = null === $path ? $this->gmagick->getImageFilename() : $path;
|
||||
|
||||
if ('' === trim($path)) {
|
||||
throw new RuntimeException('You can omit save path only if image has been open from a file');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->prepareOutput($options, $path);
|
||||
$allFrames = !isset($options['animated']) || false === $options['animated'];
|
||||
$this->gmagick->writeimage($path, $allFrames);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Save operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function show($format, array $options = array())
|
||||
{
|
||||
header('Content-type: '.$this->getMimeType($format));
|
||||
echo $this->get($format, $options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($format, array $options = array())
|
||||
{
|
||||
try {
|
||||
$options['format'] = $format;
|
||||
$this->prepareOutput($options);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Get operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this->gmagick->getimagesblob();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
* @param string $path
|
||||
*/
|
||||
private function prepareOutput(array $options, $path = null)
|
||||
{
|
||||
if (isset($options['format'])) {
|
||||
$this->gmagick->setimageformat($options['format']);
|
||||
}
|
||||
|
||||
if (isset($options['animated']) && true === $options['animated']) {
|
||||
$format = isset($options['format']) ? $options['format'] : 'gif';
|
||||
$delay = isset($options['animated.delay']) ? $options['animated.delay'] : null;
|
||||
$loops = isset($options['animated.loops']) ? $options['animated.loops'] : 0;
|
||||
|
||||
$options['flatten'] = false;
|
||||
|
||||
$this->layers->animate($format, $delay, $loops);
|
||||
} else {
|
||||
$this->layers->merge();
|
||||
}
|
||||
$this->applyImageOptions($this->gmagick, $options, $path);
|
||||
|
||||
// flatten only if image has multiple layers
|
||||
if ((!isset($options['flatten']) || $options['flatten'] === true) && count($this->layers) > 1) {
|
||||
$this->flatten();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->get('png');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function draw()
|
||||
{
|
||||
return new Drawer($this->gmagick);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function effects()
|
||||
{
|
||||
return new Effects($this->gmagick);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
try {
|
||||
$i = $this->gmagick->getimageindex();
|
||||
$this->gmagick->setimageindex(0); //rewind
|
||||
$width = $this->gmagick->getimagewidth();
|
||||
$height = $this->gmagick->getimageheight();
|
||||
$this->gmagick->setimageindex($i);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Get size operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return new Box($width, $height);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function applyMask(ImageInterface $mask)
|
||||
{
|
||||
if (!$mask instanceof self) {
|
||||
throw new InvalidArgumentException('Can only apply instances of Imagine\Gmagick\Image as masks');
|
||||
}
|
||||
|
||||
$size = $this->getSize();
|
||||
$maskSize = $mask->getSize();
|
||||
|
||||
if ($size != $maskSize) {
|
||||
throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size));
|
||||
}
|
||||
|
||||
try {
|
||||
$mask = $mask->copy();
|
||||
$this->gmagick->compositeimage($mask->gmagick, \Gmagick::COMPOSITE_DEFAULT, 0, 0);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Apply mask operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function mask()
|
||||
{
|
||||
$mask = $this->copy();
|
||||
|
||||
try {
|
||||
$mask->gmagick->modulateimage(100, 0, 100);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Mask operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function fill(FillInterface $fill)
|
||||
{
|
||||
try {
|
||||
$draw = new \GmagickDraw();
|
||||
$size = $this->getSize();
|
||||
|
||||
$w = $size->getWidth();
|
||||
$h = $size->getHeight();
|
||||
|
||||
for ($x = 0; $x <= $w; $x++) {
|
||||
for ($y = 0; $y <= $h; $y++) {
|
||||
$pixel = $this->getColor($fill->getColor(new Point($x, $y)));
|
||||
|
||||
$draw->setfillcolor($pixel);
|
||||
$draw->point($x, $y);
|
||||
|
||||
$pixel = null;
|
||||
}
|
||||
}
|
||||
|
||||
$this->gmagick->drawimage($draw);
|
||||
|
||||
$draw = null;
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Fill operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function histogram()
|
||||
{
|
||||
try {
|
||||
$pixels = $this->gmagick->getimagehistogram();
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Error while fetching histogram', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$image = $this;
|
||||
|
||||
return array_map(function (\GmagickPixel $pixel) use ($image) {
|
||||
return $image->pixelToColor($pixel);
|
||||
}, $pixels);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getColorAt(PointInterface $point)
|
||||
{
|
||||
if (!$point->in($this->getSize())) {
|
||||
throw new InvalidArgumentException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight()));
|
||||
}
|
||||
|
||||
try {
|
||||
$cropped = clone $this->gmagick;
|
||||
$histogram = $cropped
|
||||
->cropImage(1, 1, $point->getX(), $point->getY())
|
||||
->getImageHistogram();
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Unable to get the pixel');
|
||||
}
|
||||
|
||||
$pixel = array_shift($histogram);
|
||||
|
||||
unset($histogram, $cropped);
|
||||
|
||||
return $this->pixelToColor($pixel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a color given a pixel, depending the Palette context
|
||||
*
|
||||
* Note : this method is public for PHP 5.3 compatibility
|
||||
*
|
||||
* @param \GmagickPixel $pixel
|
||||
*
|
||||
* @return ColorInterface
|
||||
*
|
||||
* @throws InvalidArgumentException In case a unknown color is requested
|
||||
*/
|
||||
public function pixelToColor(\GmagickPixel $pixel)
|
||||
{
|
||||
static $colorMapping = array(
|
||||
ColorInterface::COLOR_RED => \Gmagick::COLOR_RED,
|
||||
ColorInterface::COLOR_GREEN => \Gmagick::COLOR_GREEN,
|
||||
ColorInterface::COLOR_BLUE => \Gmagick::COLOR_BLUE,
|
||||
ColorInterface::COLOR_CYAN => \Gmagick::COLOR_CYAN,
|
||||
ColorInterface::COLOR_MAGENTA => \Gmagick::COLOR_MAGENTA,
|
||||
ColorInterface::COLOR_YELLOW => \Gmagick::COLOR_YELLOW,
|
||||
ColorInterface::COLOR_KEYLINE => \Gmagick::COLOR_BLACK,
|
||||
// There is no gray component in \Gmagick, let's use one of the RGB comp
|
||||
ColorInterface::COLOR_GRAY => \Gmagick::COLOR_RED,
|
||||
);
|
||||
|
||||
if ($this->palette->supportsAlpha()) {
|
||||
try {
|
||||
$alpha = (int) round($pixel->getcolorvalue(\Gmagick::COLOR_ALPHA) * 100);
|
||||
} catch (\GmagickPixelException $e) {
|
||||
$alpha = null;
|
||||
}
|
||||
} else {
|
||||
$alpha = null;
|
||||
}
|
||||
|
||||
$palette = $this->palette();
|
||||
|
||||
return $this->palette->color(array_map(function ($color) use ($palette, $pixel, $colorMapping) {
|
||||
if (!isset($colorMapping[$color])) {
|
||||
throw new InvalidArgumentException(sprintf('Color %s is not mapped in Gmagick', $color));
|
||||
}
|
||||
$multiplier = 255;
|
||||
if ($palette->name() === PaletteInterface::PALETTE_CMYK) {
|
||||
$multiplier = 100;
|
||||
}
|
||||
|
||||
return $pixel->getcolorvalue($colorMapping[$color]) * $multiplier;
|
||||
}, $this->palette->pixelDefinition()), $alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function layers()
|
||||
{
|
||||
return $this->layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function interlace($scheme)
|
||||
{
|
||||
static $supportedInterlaceSchemes = array(
|
||||
ImageInterface::INTERLACE_NONE => \Gmagick::INTERLACE_NO,
|
||||
ImageInterface::INTERLACE_LINE => \Gmagick::INTERLACE_LINE,
|
||||
ImageInterface::INTERLACE_PLANE => \Gmagick::INTERLACE_PLANE,
|
||||
ImageInterface::INTERLACE_PARTITION => \Gmagick::INTERLACE_PARTITION,
|
||||
);
|
||||
|
||||
if (!array_key_exists($scheme, $supportedInterlaceSchemes)) {
|
||||
throw new InvalidArgumentException('Unsupported interlace type');
|
||||
}
|
||||
|
||||
$this->gmagick->setInterlaceScheme($supportedInterlaceSchemes[$scheme]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function usePalette(PaletteInterface $palette)
|
||||
{
|
||||
if (!isset(static::$colorspaceMapping[$palette->name()])) {
|
||||
throw new InvalidArgumentException(sprintf('The palette %s is not supported by Gmagick driver',$palette->name()));
|
||||
}
|
||||
|
||||
if ($this->palette->name() === $palette->name()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
$hasICCProfile = (Boolean) $this->gmagick->getimageprofile('ICM');
|
||||
} catch (\GmagickException $e) {
|
||||
$hasICCProfile = false;
|
||||
}
|
||||
|
||||
if (!$hasICCProfile) {
|
||||
$this->profile($this->palette->profile());
|
||||
}
|
||||
|
||||
$this->profile($palette->profile());
|
||||
|
||||
$this->setColorspace($palette);
|
||||
$this->palette = $palette;
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Failed to set colorspace', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function palette()
|
||||
{
|
||||
return $this->palette;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function profile(ProfileInterface $profile)
|
||||
{
|
||||
try {
|
||||
$this->gmagick->profileimage('ICM', $profile->data());
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException(sprintf('Unable to add profile %s to image', $profile->name()), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Flatten the image.
|
||||
*/
|
||||
private function flatten()
|
||||
{
|
||||
/**
|
||||
* @see http://pecl.php.net/bugs/bug.php?id=22435
|
||||
*/
|
||||
if (method_exists($this->gmagick, 'flattenImages')) {
|
||||
try {
|
||||
$this->gmagick = $this->gmagick->flattenImages();
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Flatten operation failed', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets specifically formatted color string from Color instance
|
||||
*
|
||||
* @param ColorInterface $color
|
||||
*
|
||||
* @return \GmagickPixel
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function getColor(ColorInterface $color)
|
||||
{
|
||||
if (!$color->isOpaque()) {
|
||||
throw new InvalidArgumentException('Gmagick doesn\'t support transparency');
|
||||
}
|
||||
|
||||
return new \GmagickPixel((string) $color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Get the mime type based on format.
|
||||
*
|
||||
* @param string $format
|
||||
*
|
||||
* @return string mime-type
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function getMimeType($format)
|
||||
{
|
||||
static $mimeTypes = array(
|
||||
'jpeg' => 'image/jpeg',
|
||||
'jpg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'png' => 'image/png',
|
||||
'wbmp' => 'image/vnd.wap.wbmp',
|
||||
'xbm' => 'image/xbm',
|
||||
);
|
||||
|
||||
if (!isset($mimeTypes[$format])) {
|
||||
throw new InvalidArgumentException(sprintf('Unsupported format given. Only %s are supported, %s given', implode(", ", array_keys($mimeTypes)), $format));
|
||||
}
|
||||
|
||||
return $mimeTypes[$format];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets colorspace and image type, assigns the palette.
|
||||
*
|
||||
* @param PaletteInterface $palette
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function setColorspace(PaletteInterface $palette)
|
||||
{
|
||||
if (!isset(static::$colorspaceMapping[$palette->name()])) {
|
||||
throw new InvalidArgumentException(sprintf('The palette %s is not supported by Gmagick driver', $palette->name()));
|
||||
}
|
||||
|
||||
$this->gmagick->setimagecolorspace(static::$colorspaceMapping[$palette->name()]);
|
||||
$this->palette = $palette;
|
||||
}
|
||||
}
|
||||
167
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Imagine.php
Normal file
167
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Imagine.php
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gmagick;
|
||||
|
||||
use Imagine\Image\AbstractImagine;
|
||||
use Imagine\Exception\NotSupportedException;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Metadata\MetadataBag;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Palette\Grayscale;
|
||||
use Imagine\Image\Palette\CMYK;
|
||||
use Imagine\Image\Palette\RGB;
|
||||
use Imagine\Image\Palette\Color\CMYK as CMYKColor;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Imagine implementation using the Gmagick PHP extension
|
||||
*/
|
||||
class Imagine extends AbstractImagine
|
||||
{
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!class_exists('Gmagick')) {
|
||||
throw new RuntimeException('Gmagick not installed');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function open($path)
|
||||
{
|
||||
$path = $this->checkPath($path);
|
||||
|
||||
try {
|
||||
$gmagick = new \Gmagick($path);
|
||||
$image = new Image($gmagick, $this->createPalette($gmagick), $this->getMetadataReader()->readFile($path));
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException(sprintf('Unable to open image %s', $path), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function create(BoxInterface $size, ColorInterface $color = null)
|
||||
{
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
$palette = null !== $color ? $color->getPalette() : new RGB();
|
||||
$color = null !== $color ? $color : $palette->color('fff');
|
||||
|
||||
try {
|
||||
$gmagick = new \Gmagick();
|
||||
// Gmagick does not support creation of CMYK GmagickPixel
|
||||
// see https://bugs.php.net/bug.php?id=64466
|
||||
if ($color instanceof CMYKColor) {
|
||||
$switchPalette = $palette;
|
||||
$palette = new RGB();
|
||||
$pixel = new \GmagickPixel($palette->color((string) $color));
|
||||
} else {
|
||||
$switchPalette = null;
|
||||
$pixel = new \GmagickPixel((string) $color);
|
||||
}
|
||||
|
||||
if ($color->getPalette()->supportsAlpha() && $color->getAlpha() < 100) {
|
||||
throw new NotSupportedException('alpha transparency is not supported');
|
||||
}
|
||||
|
||||
$gmagick->newimage($width, $height, $pixel->getcolor(false));
|
||||
$gmagick->setimagecolorspace(\Gmagick::COLORSPACE_TRANSPARENT);
|
||||
$gmagick->setimagebackgroundcolor($pixel);
|
||||
|
||||
$image = new Image($gmagick, $palette, new MetadataBag());
|
||||
|
||||
if ($switchPalette) {
|
||||
$image->usePalette($switchPalette);
|
||||
}
|
||||
|
||||
return $image;
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Could not create empty image', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($string)
|
||||
{
|
||||
return $this->doLoad($string, $this->getMetadataReader()->readData($string));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($resource)
|
||||
{
|
||||
if (!is_resource($resource)) {
|
||||
throw new InvalidArgumentException('Variable does not contain a stream resource');
|
||||
}
|
||||
|
||||
$content = stream_get_contents($resource);
|
||||
|
||||
if (false === $content) {
|
||||
throw new InvalidArgumentException('Couldn\'t read given resource');
|
||||
}
|
||||
|
||||
return $this->doLoad($content, $this->getMetadataReader()->readStream($resource));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function font($file, $size, ColorInterface $color)
|
||||
{
|
||||
$gmagick = new \Gmagick();
|
||||
$gmagick->newimage(1, 1, 'transparent');
|
||||
|
||||
return new Font($gmagick, $file, $size, $color);
|
||||
}
|
||||
|
||||
private function createPalette(\Gmagick $gmagick)
|
||||
{
|
||||
switch ($gmagick->getimagecolorspace()) {
|
||||
case \Gmagick::COLORSPACE_SRGB:
|
||||
case \Gmagick::COLORSPACE_RGB:
|
||||
return new RGB();
|
||||
case \Gmagick::COLORSPACE_CMYK:
|
||||
return new CMYK();
|
||||
case \Gmagick::COLORSPACE_GRAY:
|
||||
return new Grayscale();
|
||||
default:
|
||||
throw new NotSupportedException('Only RGB and CMYK colorspace are currently supported');
|
||||
}
|
||||
}
|
||||
|
||||
private function doLoad($content, MetadataBag $metadata)
|
||||
{
|
||||
try {
|
||||
$gmagick = new \Gmagick();
|
||||
$gmagick->readimageblob($content);
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException(
|
||||
'Could not load image from string', $e->getCode(), $e
|
||||
);
|
||||
}
|
||||
|
||||
return new Image($gmagick, $this->createPalette($gmagick), $metadata);
|
||||
}
|
||||
}
|
||||
272
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Layers.php
Normal file
272
rainloop/v/0.0.0/app/libraries/Imagine/Gmagick/Layers.php
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Gmagick;
|
||||
|
||||
use Imagine\Image\AbstractLayers;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Exception\NotSupportedException;
|
||||
use Imagine\Exception\OutOfBoundsException;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Image\Metadata\MetadataBag;
|
||||
use Imagine\Image\Palette\PaletteInterface;
|
||||
|
||||
class Layers extends AbstractLayers
|
||||
{
|
||||
/**
|
||||
* @var Image
|
||||
*/
|
||||
private $image;
|
||||
|
||||
/**
|
||||
* @var \Gmagick
|
||||
*/
|
||||
private $resource;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $offset = 0;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $layers = array();
|
||||
|
||||
/**
|
||||
* @var PaletteInterface
|
||||
*/
|
||||
private $palette;
|
||||
|
||||
public function __construct(Image $image, PaletteInterface $palette, \Gmagick $resource)
|
||||
{
|
||||
$this->image = $image;
|
||||
$this->resource = $resource;
|
||||
$this->palette = $palette;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function merge()
|
||||
{
|
||||
foreach ($this->layers as $offset => $image) {
|
||||
try {
|
||||
$this->resource->setimageindex($offset);
|
||||
$this->resource->setimage($image->getGmagick());
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Failed to substitute layer', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function coalesce()
|
||||
{
|
||||
throw new NotSupportedException('Gmagick does not support coalescing');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function animate($format, $delay, $loops)
|
||||
{
|
||||
if ('gif' !== strtolower($format)) {
|
||||
throw new NotSupportedException('Animated picture is currently only supported on gif');
|
||||
}
|
||||
|
||||
if (!is_int($loops) || $loops < 0) {
|
||||
throw new InvalidArgumentException('Loops must be a positive integer.');
|
||||
}
|
||||
|
||||
if (null !== $delay && (!is_int($delay) || $delay < 0)) {
|
||||
throw new InvalidArgumentException('Delay must be either null or a positive integer.');
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($this as $offset => $layer) {
|
||||
$this->resource->setimageindex($offset);
|
||||
$this->resource->setimageformat($format);
|
||||
|
||||
if (null !== $delay) {
|
||||
$this->resource->setimagedelay($delay / 10);
|
||||
}
|
||||
|
||||
$this->resource->setimageiterations($loops);
|
||||
}
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Failed to animate layers', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->extractAt($this->offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to extract layer at given offset
|
||||
*
|
||||
* @param integer $offset
|
||||
* @return Image
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function extractAt($offset)
|
||||
{
|
||||
if (!isset($this->layers[$offset])) {
|
||||
try {
|
||||
$this->resource->setimageindex($offset);
|
||||
$this->layers[$offset] = new Image($this->resource->getimage(), $this->palette, new MetadataBag());
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException(sprintf('Failed to extract layer %d', $offset), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->layers[$offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
++$this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->offset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->offset < count($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
try {
|
||||
return $this->resource->getnumberimages();
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Failed to count the number of layers', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return is_int($offset) && $offset >= 0 && $offset < count($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->extractAt($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetSet($offset, $image)
|
||||
{
|
||||
if (!$image instanceof Image) {
|
||||
throw new InvalidArgumentException('Only a Gmagick Image can be used as layer');
|
||||
}
|
||||
|
||||
if (null === $offset) {
|
||||
$offset = count($this) - 1;
|
||||
} else {
|
||||
if (!is_int($offset)) {
|
||||
throw new InvalidArgumentException('Invalid offset for layer, it must be an integer');
|
||||
}
|
||||
|
||||
if (count($this) < $offset || 0 > $offset) {
|
||||
throw new OutOfBoundsException(sprintf('Invalid offset for layer, it must be a value between 0 and %d, %d given', count($this), $offset));
|
||||
}
|
||||
|
||||
if (isset($this[$offset])) {
|
||||
unset($this[$offset]);
|
||||
$offset = $offset - 1;
|
||||
}
|
||||
}
|
||||
|
||||
$frame = $image->getGmagick();
|
||||
|
||||
try {
|
||||
if (count($this) > 0) {
|
||||
$this->resource->setimageindex($offset);
|
||||
$this->resource->nextimage();
|
||||
}
|
||||
$this->resource->addimage($frame);
|
||||
|
||||
/**
|
||||
* ugly hack to bypass issue https://bugs.php.net/bug.php?id=64623
|
||||
*/
|
||||
if (count($this) == 2) {
|
||||
$this->resource->setimageindex($offset+1);
|
||||
$this->resource->nextimage();
|
||||
$this->resource->addimage($frame);
|
||||
unset($this[0]);
|
||||
}
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Unable to set the layer', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$this->layers = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
try {
|
||||
$this->extractAt($offset);
|
||||
} catch (RuntimeException $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->resource->setimageindex($offset);
|
||||
$this->resource->removeimage();
|
||||
} catch (\GmagickException $e) {
|
||||
throw new RuntimeException('Unable to remove layer', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
|
||||
/**
|
||||
* Abstract font base class
|
||||
*/
|
||||
abstract class AbstractFont implements FontInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
protected $size;
|
||||
|
||||
/**
|
||||
* @var ColorInterface
|
||||
*/
|
||||
protected $color;
|
||||
|
||||
/**
|
||||
* Constructs a font with specified $file, $size and $color
|
||||
*
|
||||
* The font size is to be specified in points (e.g. 10pt means 10)
|
||||
*
|
||||
* @param string $file
|
||||
* @param integer $size
|
||||
* @param ColorInterface $color
|
||||
*/
|
||||
public function __construct($file, $size, ColorInterface $color)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->size = $size;
|
||||
$this->color = $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
final public function getFile()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
final public function getSize()
|
||||
{
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
final public function getColor()
|
||||
{
|
||||
return $this->color;
|
||||
}
|
||||
}
|
||||
120
rainloop/v/0.0.0/app/libraries/Imagine/Image/AbstractImage.php
Normal file
120
rainloop/v/0.0.0/app/libraries/Imagine/Image/AbstractImage.php
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Image\Metadata\MetadataBag;
|
||||
|
||||
abstract class AbstractImage implements ImageInterface
|
||||
{
|
||||
/**
|
||||
* @var MetadataBag
|
||||
*/
|
||||
protected $metadata;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function thumbnail(BoxInterface $size, $mode = ImageInterface::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED)
|
||||
{
|
||||
if ($mode !== ImageInterface::THUMBNAIL_INSET &&
|
||||
$mode !== ImageInterface::THUMBNAIL_OUTBOUND) {
|
||||
throw new InvalidArgumentException('Invalid mode specified');
|
||||
}
|
||||
|
||||
$imageSize = $this->getSize();
|
||||
$ratios = array(
|
||||
$size->getWidth() / $imageSize->getWidth(),
|
||||
$size->getHeight() / $imageSize->getHeight()
|
||||
);
|
||||
|
||||
$thumbnail = $this->copy();
|
||||
|
||||
$thumbnail->usePalette($this->palette());
|
||||
$thumbnail->strip();
|
||||
// if target width is larger than image width
|
||||
// AND target height is longer than image height
|
||||
if ($size->contains($imageSize)) {
|
||||
return $thumbnail;
|
||||
}
|
||||
|
||||
if ($mode === ImageInterface::THUMBNAIL_INSET) {
|
||||
$ratio = min($ratios);
|
||||
} else {
|
||||
$ratio = max($ratios);
|
||||
}
|
||||
|
||||
if ($mode === ImageInterface::THUMBNAIL_OUTBOUND) {
|
||||
if (!$imageSize->contains($size)) {
|
||||
$size = new Box(
|
||||
min($imageSize->getWidth(), $size->getWidth()),
|
||||
min($imageSize->getHeight(), $size->getHeight())
|
||||
);
|
||||
} else {
|
||||
$imageSize = $thumbnail->getSize()->scale($ratio);
|
||||
$thumbnail->resize($imageSize, $filter);
|
||||
}
|
||||
$thumbnail->crop(new Point(
|
||||
max(0, round(($imageSize->getWidth() - $size->getWidth()) / 2)),
|
||||
max(0, round(($imageSize->getHeight() - $size->getHeight()) / 2))
|
||||
), $size);
|
||||
} else {
|
||||
if (!$imageSize->contains($size)) {
|
||||
$imageSize = $imageSize->scale($ratio);
|
||||
$thumbnail->resize($imageSize, $filter);
|
||||
} else {
|
||||
$imageSize = $thumbnail->getSize()->scale($ratio);
|
||||
$thumbnail->resize($imageSize, $filter);
|
||||
}
|
||||
}
|
||||
|
||||
return $thumbnail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a given array of save options for backward compatibility with legacy names
|
||||
*
|
||||
* @param array $options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function updateSaveOptions(array $options)
|
||||
{
|
||||
// Preserve BC until version 1.0
|
||||
if (isset($options['quality']) && !isset($options['jpeg_quality'])) {
|
||||
$options['jpeg_quality'] = $options['quality'];
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function metadata()
|
||||
{
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assures the metadata instance will be cloned, too
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
if ($this->metadata !== null) {
|
||||
$this->metadata = clone $this->metadata;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
use Imagine\Image\Metadata\DefaultMetadataReader;
|
||||
use Imagine\Image\Metadata\ExifMetadataReader;
|
||||
use Imagine\Image\Metadata\MetadataReaderInterface;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
|
||||
abstract class AbstractImagine implements ImagineInterface
|
||||
{
|
||||
/** @var MetadataReaderInterface */
|
||||
private $metadataReader;
|
||||
|
||||
/**
|
||||
* @param MetadataReaderInterface $metadataReader
|
||||
*
|
||||
* @return ImagineInterface
|
||||
*/
|
||||
public function setMetadataReader(MetadataReaderInterface $metadataReader)
|
||||
{
|
||||
$this->metadataReader = $metadataReader;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MetadataReaderInterface
|
||||
*/
|
||||
public function getMetadataReader()
|
||||
{
|
||||
if (null === $this->metadataReader) {
|
||||
if (ExifMetadataReader::isSupported()) {
|
||||
$this->metadataReader = new ExifMetadataReader();
|
||||
} else {
|
||||
$this->metadataReader = new DefaultMetadataReader();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->metadataReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a path that could be used with ImagineInterface::open and returns
|
||||
* a proper string.
|
||||
*
|
||||
* @param string|object $path
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws InvalidArgumentException In case the given path is invalid.
|
||||
*/
|
||||
protected function checkPath($path)
|
||||
{
|
||||
// provide compatibility with objects such as \SplFileInfo
|
||||
if (is_object($path) && method_exists($path, '__toString')) {
|
||||
$path = (string) $path;
|
||||
}
|
||||
|
||||
$handle = @fopen($path, 'r');
|
||||
|
||||
if (false === $handle) {
|
||||
throw new InvalidArgumentException(sprintf('File %s does not exist.', $path));
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
abstract class AbstractLayers implements LayersInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function add(ImageInterface $image)
|
||||
{
|
||||
$this[] = $image;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function set($offset, ImageInterface $image)
|
||||
{
|
||||
$this[$offset] = $image;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function remove($offset)
|
||||
{
|
||||
unset($this[$offset]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($offset)
|
||||
{
|
||||
return $this[$offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has($offset)
|
||||
{
|
||||
return isset($this[$offset]);
|
||||
}
|
||||
}
|
||||
122
rainloop/v/0.0.0/app/libraries/Imagine/Image/Box.php
Normal file
122
rainloop/v/0.0.0/app/libraries/Imagine/Image/Box.php
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* A box implementation
|
||||
*/
|
||||
final class Box implements BoxInterface
|
||||
{
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $width;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $height;
|
||||
|
||||
/**
|
||||
* Constructs the Size with given width and height
|
||||
*
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct($width, $height)
|
||||
{
|
||||
if ($height < 1 || $width < 1) {
|
||||
throw new InvalidArgumentException(sprintf('Length of either side cannot be 0 or negative, current size is %sx%s', $width, $height));
|
||||
}
|
||||
|
||||
$this->width = (int) $width;
|
||||
$this->height = (int) $height;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getWidth()
|
||||
{
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHeight()
|
||||
{
|
||||
return $this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function scale($ratio)
|
||||
{
|
||||
return new Box(round($ratio * $this->width), round($ratio * $this->height));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function increase($size)
|
||||
{
|
||||
return new Box((int) $size + $this->width, (int) $size + $this->height);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function contains(BoxInterface $box, PointInterface $start = null)
|
||||
{
|
||||
$start = $start ? $start : new Point(0, 0);
|
||||
|
||||
return $start->in($this) && $this->width >= $box->getWidth() + $start->getX() && $this->height >= $box->getHeight() + $start->getY();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function square()
|
||||
{
|
||||
return $this->width * $this->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('%dx%d px', $this->width, $this->height);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function widen($width)
|
||||
{
|
||||
return $this->scale($width / $this->width);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function heighten($height)
|
||||
{
|
||||
return $this->scale($height / $this->height);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
/**
|
||||
* Interface for a box
|
||||
*/
|
||||
interface BoxInterface
|
||||
{
|
||||
/**
|
||||
* Gets current image height
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getHeight();
|
||||
|
||||
/**
|
||||
* Gets current image width
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getWidth();
|
||||
|
||||
/**
|
||||
* Creates new BoxInterface instance with ratios applied to both sides
|
||||
*
|
||||
* @param float $ratio
|
||||
*
|
||||
* @return BoxInterface
|
||||
*/
|
||||
public function scale($ratio);
|
||||
|
||||
/**
|
||||
* Creates new BoxInterface, adding given size to both sides
|
||||
*
|
||||
* @param integer $size
|
||||
*
|
||||
* @return BoxInterface
|
||||
*/
|
||||
public function increase($size);
|
||||
|
||||
/**
|
||||
* Checks whether current box can fit given box at a given start position,
|
||||
* start position defaults to top left corner xy(0,0)
|
||||
*
|
||||
* @param BoxInterface $box
|
||||
* @param PointInterface $start
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function contains(BoxInterface $box, PointInterface $start = null);
|
||||
|
||||
/**
|
||||
* Gets current box square, useful for getting total number of pixels in a
|
||||
* given box
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function square();
|
||||
|
||||
/**
|
||||
* Returns a string representation of the current box
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString();
|
||||
|
||||
/**
|
||||
* Resizes box to given width, constraining proportions and returns the new box
|
||||
*
|
||||
* @param integer $width
|
||||
*
|
||||
* @return BoxInterface
|
||||
*/
|
||||
public function widen($width);
|
||||
|
||||
/**
|
||||
* Resizes box to given height, constraining proportions and returns the new box
|
||||
*
|
||||
* @param integer $height
|
||||
*
|
||||
* @return BoxInterface
|
||||
*/
|
||||
public function heighten($height);
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Fill;
|
||||
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\PointInterface;
|
||||
|
||||
/**
|
||||
* Interface for the fill
|
||||
*/
|
||||
interface FillInterface
|
||||
{
|
||||
/**
|
||||
* Gets color of the fill for the given position
|
||||
*
|
||||
* @param PointInterface $position
|
||||
*
|
||||
* @return ColorInterface
|
||||
*/
|
||||
public function getColor(PointInterface $position);
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Fill\Gradient;
|
||||
|
||||
use Imagine\Image\PointInterface;
|
||||
|
||||
/**
|
||||
* Horizontal gradient fill
|
||||
*/
|
||||
final class Horizontal extends Linear
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDistance(PointInterface $position)
|
||||
{
|
||||
return $position->getX();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Fill\Gradient;
|
||||
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Fill\FillInterface;
|
||||
use Imagine\Image\PointInterface;
|
||||
|
||||
/**
|
||||
* Linear gradient fill
|
||||
*/
|
||||
abstract class Linear implements FillInterface
|
||||
{
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $length;
|
||||
|
||||
/**
|
||||
* @var ColorInterface
|
||||
*/
|
||||
private $start;
|
||||
|
||||
/**
|
||||
* @var ColorInterface
|
||||
*/
|
||||
private $end;
|
||||
|
||||
/**
|
||||
* Constructs a linear gradient with overall gradient length, and start and
|
||||
* end shades, which default to 0 and 255 accordingly
|
||||
*
|
||||
* @param integer $length
|
||||
* @param ColorInterface $start
|
||||
* @param ColorInterface $end
|
||||
*/
|
||||
final public function __construct($length, ColorInterface $start, ColorInterface $end)
|
||||
{
|
||||
$this->length = $length;
|
||||
$this->start = $start;
|
||||
$this->end = $end;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
final public function getColor(PointInterface $position)
|
||||
{
|
||||
$l = $this->getDistance($position);
|
||||
|
||||
if ($l >= $this->length) {
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
if ($l < 0) {
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
return $this->start->getPalette()->blend($this->start, $this->end, $l / $this->length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ColorInterface
|
||||
*/
|
||||
final public function getStart()
|
||||
{
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ColorInterface
|
||||
*/
|
||||
final public function getEnd()
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance of the position relative to the beginning of the gradient
|
||||
*
|
||||
* @param PointInterface $position
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
abstract protected function getDistance(PointInterface $position);
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Fill\Gradient;
|
||||
|
||||
use Imagine\Image\PointInterface;
|
||||
|
||||
/**
|
||||
* Vertical gradient fill
|
||||
*/
|
||||
final class Vertical extends Linear
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDistance(PointInterface $position)
|
||||
{
|
||||
return $position->getY();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
|
||||
/**
|
||||
* The font interface
|
||||
*/
|
||||
interface FontInterface
|
||||
{
|
||||
/**
|
||||
* Gets the fontfile for current font
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFile();
|
||||
|
||||
/**
|
||||
* Gets font's integer point size
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getSize();
|
||||
|
||||
/**
|
||||
* Gets font's color
|
||||
*
|
||||
* @return ColorInterface
|
||||
*/
|
||||
public function getColor();
|
||||
|
||||
/**
|
||||
* Gets BoxInterface of font size on the image based on string and angle
|
||||
*
|
||||
* @param string $string
|
||||
* @param integer $angle
|
||||
*
|
||||
* @return BoxInterface
|
||||
*/
|
||||
public function box($string, $angle = 0);
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Histogram;
|
||||
|
||||
/**
|
||||
* Bucket histogram
|
||||
*/
|
||||
final class Bucket implements \Countable
|
||||
{
|
||||
/**
|
||||
* @var Range
|
||||
*/
|
||||
private $range;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $count;
|
||||
|
||||
/**
|
||||
* @param Range $range
|
||||
* @param integer $count
|
||||
*/
|
||||
public function __construct(Range $range, $count = 0)
|
||||
{
|
||||
$this->range = $range;
|
||||
$this->count = $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $value
|
||||
*/
|
||||
public function add($value)
|
||||
{
|
||||
if ($this->range->contains($value)) {
|
||||
$this->count++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer The number of elements in the bucket.
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return $this->count;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Histogram;
|
||||
|
||||
use Imagine\Exception\OutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Range histogram
|
||||
*/
|
||||
final class Range
|
||||
{
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $start;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $end;
|
||||
|
||||
/**
|
||||
* @param integer $start
|
||||
* @param integer $end
|
||||
*
|
||||
* @throws OutOfBoundsException
|
||||
*/
|
||||
public function __construct($start, $end)
|
||||
{
|
||||
if ($end <= $start) {
|
||||
throw new OutOfBoundsException(sprintf('Range end cannot be bigger than start, %d %d given accordingly', $this->start, $this->end));
|
||||
}
|
||||
|
||||
$this->start = $start;
|
||||
$this->end = $end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $value
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function contains($value)
|
||||
{
|
||||
return $value >= $this->start && $value < $this->end;
|
||||
}
|
||||
}
|
||||
173
rainloop/v/0.0.0/app/libraries/Imagine/Image/ImageInterface.php
Normal file
173
rainloop/v/0.0.0/app/libraries/Imagine/Image/ImageInterface.php
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
use Imagine\Draw\DrawerInterface;
|
||||
use Imagine\Effects\EffectsInterface;
|
||||
use Imagine\Image\Palette\PaletteInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Exception\OutOfBoundsException;
|
||||
|
||||
/**
|
||||
* The image interface
|
||||
*/
|
||||
interface ImageInterface extends ManipulatorInterface
|
||||
{
|
||||
const RESOLUTION_PIXELSPERINCH = 'ppi';
|
||||
const RESOLUTION_PIXELSPERCENTIMETER = 'ppc';
|
||||
|
||||
const INTERLACE_NONE = 'none';
|
||||
const INTERLACE_LINE = 'line';
|
||||
const INTERLACE_PLANE = 'plane';
|
||||
const INTERLACE_PARTITION = 'partition';
|
||||
|
||||
const FILTER_UNDEFINED = 'undefined';
|
||||
const FILTER_POINT = 'point';
|
||||
const FILTER_BOX = 'box';
|
||||
const FILTER_TRIANGLE = 'triangle';
|
||||
const FILTER_HERMITE = 'hermite';
|
||||
const FILTER_HANNING = 'hanning';
|
||||
const FILTER_HAMMING = 'hamming';
|
||||
const FILTER_BLACKMAN = 'blackman';
|
||||
const FILTER_GAUSSIAN = 'gaussian';
|
||||
const FILTER_QUADRATIC = 'quadratic';
|
||||
const FILTER_CUBIC = 'cubic';
|
||||
const FILTER_CATROM = 'catrom';
|
||||
const FILTER_MITCHELL = 'mitchell';
|
||||
const FILTER_LANCZOS = 'lanczos';
|
||||
const FILTER_BESSEL = 'bessel';
|
||||
const FILTER_SINC = 'sinc';
|
||||
|
||||
/**
|
||||
* Returns the image content as a binary string
|
||||
*
|
||||
* @param string $format
|
||||
* @param array $options
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return string binary
|
||||
*/
|
||||
public function get($format, array $options = array());
|
||||
|
||||
/**
|
||||
* Returns the image content as a PNG binary string
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return string binary
|
||||
*/
|
||||
public function __toString();
|
||||
|
||||
/**
|
||||
* Instantiates and returns a DrawerInterface instance for image drawing
|
||||
*
|
||||
* @return DrawerInterface
|
||||
*/
|
||||
public function draw();
|
||||
|
||||
/**
|
||||
* @return EffectsInterface
|
||||
*/
|
||||
public function effects();
|
||||
|
||||
/**
|
||||
* Returns current image size
|
||||
*
|
||||
* @return BoxInterface
|
||||
*/
|
||||
public function getSize();
|
||||
|
||||
/**
|
||||
* Transforms creates a grayscale mask from current image, returns a new
|
||||
* image, while keeping the existing image unmodified
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function mask();
|
||||
|
||||
/**
|
||||
* Returns array of image colors as Imagine\Image\Palette\Color\ColorInterface instances
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function histogram();
|
||||
|
||||
/**
|
||||
* Returns color at specified positions of current image
|
||||
*
|
||||
* @param PointInterface $point
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return ColorInterface
|
||||
*/
|
||||
public function getColorAt(PointInterface $point);
|
||||
|
||||
/**
|
||||
* Returns the image layers when applicable.
|
||||
*
|
||||
* @throws RuntimeException In case the layer can not be returned
|
||||
* @throws OutOfBoundsException In case the index is not a valid value
|
||||
*
|
||||
* @return LayersInterface
|
||||
*/
|
||||
public function layers();
|
||||
|
||||
/**
|
||||
* Enables or disables interlacing
|
||||
*
|
||||
* @param string $scheme
|
||||
*
|
||||
* @throws InvalidArgumentException When an unsupported Interface type is supplied
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function interlace($scheme);
|
||||
|
||||
/**
|
||||
* Return the current color palette
|
||||
*
|
||||
* @return PaletteInterface
|
||||
*/
|
||||
public function palette();
|
||||
|
||||
/**
|
||||
* Set a palette for the image. Useful to change colorspace.
|
||||
*
|
||||
* @param PaletteInterface $palette
|
||||
*
|
||||
* @return ImageInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function usePalette(PaletteInterface $palette);
|
||||
|
||||
/**
|
||||
* Applies a color profile on the Image
|
||||
*
|
||||
* @param ProfileInterface $profile
|
||||
*
|
||||
* @return ImageInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function profile(ProfileInterface $profile);
|
||||
|
||||
/**
|
||||
* Returns the Image's meta data
|
||||
*
|
||||
* @return Metadata\MetadataInterface
|
||||
*/
|
||||
public function metadata();
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* The imagine interface
|
||||
*/
|
||||
interface ImagineInterface
|
||||
{
|
||||
const VERSION = '0.7-dev';
|
||||
|
||||
/**
|
||||
* Creates a new empty image with an optional background color
|
||||
*
|
||||
* @param BoxInterface $size
|
||||
* @param ColorInterface $color
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function create(BoxInterface $size, ColorInterface $color = null);
|
||||
|
||||
/**
|
||||
* Opens an existing image from $path
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function open($path);
|
||||
|
||||
/**
|
||||
* Loads an image from a binary $string
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function load($string);
|
||||
|
||||
/**
|
||||
* Loads an image from a resource $resource
|
||||
*
|
||||
* @param resource $resource
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function read($resource);
|
||||
|
||||
/**
|
||||
* Constructs a font with specified $file, $size and $color
|
||||
*
|
||||
* The font size is to be specified in points (e.g. 10pt means 10)
|
||||
*
|
||||
* @param string $file
|
||||
* @param integer $size
|
||||
* @param ColorInterface $color
|
||||
*
|
||||
* @return FontInterface
|
||||
*/
|
||||
public function font($file, $size, ColorInterface $color);
|
||||
}
|
||||
107
rainloop/v/0.0.0/app/libraries/Imagine/Image/LayersInterface.php
Normal file
107
rainloop/v/0.0.0/app/libraries/Imagine/Image/LayersInterface.php
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\OutOfBoundsException;
|
||||
|
||||
/**
|
||||
* The layers interface
|
||||
*/
|
||||
interface LayersInterface extends \Iterator, \Countable, \ArrayAccess
|
||||
{
|
||||
/**
|
||||
* Merge layers into the original objects
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function merge();
|
||||
|
||||
/**
|
||||
* Animates layers
|
||||
*
|
||||
* @param string $format The output output format
|
||||
* @param integer $delay The delay in milliseconds between two frames
|
||||
* @param integer $loops The number of loops, 0 means infinite
|
||||
*
|
||||
* @return LayersInterface
|
||||
*
|
||||
* @throws InvalidArgumentException In case an invalid argument is provided
|
||||
* @throws RuntimeException In case the driver fails to animate
|
||||
*/
|
||||
public function animate($format, $delay, $loops);
|
||||
|
||||
/**
|
||||
* Coalesce layers. Each layer in the sequence is the same size as the first and composited with the next layer in
|
||||
* the sequence.
|
||||
*/
|
||||
public function coalesce();
|
||||
|
||||
/**
|
||||
* Adds an image at the end of the layers stack
|
||||
*
|
||||
* @param ImageInterface $image
|
||||
*
|
||||
* @return LayersInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function add(ImageInterface $image);
|
||||
|
||||
/**
|
||||
* Set an image at offset
|
||||
*
|
||||
* @param integer $offset
|
||||
* @param ImageInterface $image
|
||||
*
|
||||
* @return LayersInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @throws InvalidArgumentException
|
||||
* @throws OutOfBoundsException
|
||||
*/
|
||||
public function set($offset, ImageInterface $image);
|
||||
|
||||
/**
|
||||
* Removes the image at offset
|
||||
*
|
||||
* @param integer $offset
|
||||
*
|
||||
* @return LayersInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function remove($offset);
|
||||
|
||||
/**
|
||||
* Returns the image at offset
|
||||
*
|
||||
* @param integer $offset
|
||||
*
|
||||
* @return ImageInterface
|
||||
*
|
||||
* @throws RuntimeException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function get($offset);
|
||||
|
||||
/**
|
||||
* Returns true if a layer at offset is preset
|
||||
*
|
||||
* @param integer $offset
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function has($offset);
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\OutOfBoundsException;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Fill\FillInterface;
|
||||
|
||||
/**
|
||||
* The manipulator interface
|
||||
*/
|
||||
interface ManipulatorInterface
|
||||
{
|
||||
const THUMBNAIL_INSET = 'inset';
|
||||
const THUMBNAIL_OUTBOUND = 'outbound';
|
||||
|
||||
/**
|
||||
* Copies current source image into a new ImageInterface instance
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function copy();
|
||||
|
||||
/**
|
||||
* Crops a specified box out of the source image (modifies the source image)
|
||||
* Returns cropped self
|
||||
*
|
||||
* @param PointInterface $start
|
||||
* @param BoxInterface $size
|
||||
*
|
||||
* @throws OutOfBoundsException
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function crop(PointInterface $start, BoxInterface $size);
|
||||
|
||||
/**
|
||||
* Resizes current image and returns self
|
||||
*
|
||||
* @param BoxInterface $size
|
||||
* @param string $filter
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED);
|
||||
|
||||
/**
|
||||
* Rotates an image at the given angle.
|
||||
* Optional $background can be used to specify the fill color of the empty
|
||||
* area of rotated image.
|
||||
*
|
||||
* @param integer $angle
|
||||
* @param ColorInterface $background
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function rotate($angle, ColorInterface $background = null);
|
||||
|
||||
/**
|
||||
* Pastes an image into a parent image
|
||||
* Throws exceptions if image exceeds parent image borders or if paste
|
||||
* operation fails
|
||||
*
|
||||
* Returns source image
|
||||
*
|
||||
* @param ImageInterface $image
|
||||
* @param PointInterface $start
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws OutOfBoundsException
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function paste(ImageInterface $image, PointInterface $start);
|
||||
|
||||
/**
|
||||
* Saves the image at a specified path, the target file extension is used
|
||||
* to determine file format, only jpg, jpeg, gif, png, wbmp and xbm are
|
||||
* supported
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $options
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function save($path = null, array $options = array());
|
||||
|
||||
/**
|
||||
* Outputs the image content
|
||||
*
|
||||
* @param string $format
|
||||
* @param array $options
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function show($format, array $options = array());
|
||||
|
||||
/**
|
||||
* Flips current image using horizontal axis
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function flipHorizontally();
|
||||
|
||||
/**
|
||||
* Flips current image using vertical axis
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function flipVertically();
|
||||
|
||||
/**
|
||||
* Remove all profiles and comments
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function strip();
|
||||
|
||||
/**
|
||||
* Generates a thumbnail from a current image
|
||||
* Returns it as a new image, doesn't modify the current image
|
||||
*
|
||||
* @param BoxInterface $size
|
||||
* @param string $mode
|
||||
* @param string $filter The filter to use for resizing, one of ImageInterface::FILTER_*
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function thumbnail(BoxInterface $size, $mode = self::THUMBNAIL_INSET, $filter = ImageInterface::FILTER_UNDEFINED);
|
||||
|
||||
/**
|
||||
* Applies a given mask to current image's alpha channel
|
||||
*
|
||||
* @param ImageInterface $mask
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function applyMask(ImageInterface $mask);
|
||||
|
||||
/**
|
||||
* Fills image with provided filling, by replacing each pixel's color in
|
||||
* the current image with corresponding color from FillInterface, and
|
||||
* returns modified image
|
||||
*
|
||||
* @param FillInterface $fill
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function fill(FillInterface $fill);
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Metadata;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
|
||||
abstract class AbstractMetadataReader implements MetadataReaderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function readFile($file)
|
||||
{
|
||||
if (stream_is_local($file)) {
|
||||
if (!is_file($file)) {
|
||||
throw new InvalidArgumentException(sprintf('File %s does not exist.', $file));
|
||||
}
|
||||
|
||||
return new MetadataBag(array_merge(array('filepath' => realpath($file), 'uri' => $file), $this->extractFromFile($file)));
|
||||
}
|
||||
|
||||
return new MetadataBag(array_merge(array('uri' => $file), $this->extractFromFile($file)));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function readData($data)
|
||||
{
|
||||
return new MetadataBag($this->extractFromData($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function readStream($resource)
|
||||
{
|
||||
if (!is_resource($resource)) {
|
||||
throw new InvalidArgumentException('Invalid resource provided.');
|
||||
}
|
||||
|
||||
return new MetadataBag(array_merge($this->getStreamMetadata($resource), $this->extractFromStream($resource)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URI from a stream resource
|
||||
*
|
||||
* @param resource $resource
|
||||
*
|
||||
* @return string|null The URI f ava
|
||||
*/
|
||||
private function getStreamMetadata($resource)
|
||||
{
|
||||
$metadata = array();
|
||||
|
||||
if (false !== $data = @stream_get_meta_data($resource)) {
|
||||
$metadata['uri'] = $data['uri'];
|
||||
if (stream_is_local($resource)) {
|
||||
$metadata['filepath'] = realpath($data['uri']);
|
||||
}
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts metadata from a file
|
||||
*
|
||||
* @param $file
|
||||
*
|
||||
* @return array An associative array of metadata
|
||||
*/
|
||||
abstract protected function extractFromFile($file);
|
||||
|
||||
/**
|
||||
* Extracts metadata from raw data
|
||||
*
|
||||
* @param $data
|
||||
*
|
||||
* @return array An associative array of metadata
|
||||
*/
|
||||
abstract protected function extractFromData($data);
|
||||
|
||||
/**
|
||||
* Extracts metadata from a stream
|
||||
*
|
||||
* @param $resource
|
||||
*
|
||||
* @return array An associative array of metadata
|
||||
*/
|
||||
abstract protected function extractFromStream($resource);
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Metadata;
|
||||
|
||||
/**
|
||||
* Default metadata reader
|
||||
*/
|
||||
class DefaultMetadataReader extends AbstractMetadataReader
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function extractFromFile($file)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function extractFromData($data)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function extractFromStream($resource)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Metadata;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\NotSupportedException;
|
||||
|
||||
/**
|
||||
* Metadata driven by Exif information
|
||||
*/
|
||||
class ExifMetadataReader extends AbstractMetadataReader
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
if (!self::isSupported()) {
|
||||
throw new NotSupportedException('PHP exif extension is required to use the ExifMetadataReader');
|
||||
}
|
||||
}
|
||||
|
||||
public static function isSupported()
|
||||
{
|
||||
return function_exists('exif_read_data');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function extractFromFile($file)
|
||||
{
|
||||
if (false === $data = @file_get_contents($file)) {
|
||||
throw new InvalidArgumentException(sprintf('File %s is not readable.', $file));
|
||||
}
|
||||
|
||||
return $this->doReadData($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function extractFromData($data)
|
||||
{
|
||||
return $this->doReadData($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function extractFromStream($resource)
|
||||
{
|
||||
if (0 < ftell($resource)) {
|
||||
$metadata = stream_get_meta_data($resource);
|
||||
if ($metadata['seekable']) {
|
||||
rewind($resource);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->doReadData(stream_get_contents($resource));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts metadata from raw data, merges with existing metadata
|
||||
*
|
||||
* @param string $data
|
||||
*
|
||||
* @return MetadataBag
|
||||
*/
|
||||
private function doReadData($data)
|
||||
{
|
||||
if (substr($data, 0, 2) === 'II') {
|
||||
$mime = 'image/tiff';
|
||||
} else {
|
||||
$mime = 'image/jpeg';
|
||||
}
|
||||
|
||||
return $this->extract('data://' . $mime . ';base64,' . base64_encode($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the exif data extraction given a path or data-URI representation.
|
||||
*
|
||||
* @param string $path The path to the file or the data-URI representation.
|
||||
*
|
||||
* @return MetadataBag
|
||||
*/
|
||||
private function extract($path)
|
||||
{
|
||||
if (false === $exifData = @exif_read_data($path, null, true, false)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$metadata = array();
|
||||
$sources = array('EXIF' => 'exif', 'IFD0' => 'ifd0');
|
||||
|
||||
foreach ($sources as $name => $prefix) {
|
||||
if (!isset($exifData[$name])) {
|
||||
continue;
|
||||
}
|
||||
foreach ($exifData[$name] as $prop => $value) {
|
||||
$metadata[$prefix.'.'.$prop] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Metadata;
|
||||
|
||||
/**
|
||||
* An interface for Image Metadata
|
||||
*/
|
||||
class MetadataBag implements \ArrayAccess, \IteratorAggregate, \Countable
|
||||
{
|
||||
/** @var array */
|
||||
private $data;
|
||||
|
||||
public function __construct(array $data = array())
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the metadata key, default value if it does not exist
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed|null $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
return array_key_exists($key, $this->data) ? $this->data[$key] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return array_key_exists($offset, $this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->data[$offset] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->data[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->get($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns metadata as an array
|
||||
*
|
||||
* @return array An associative array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Metadata;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
|
||||
interface MetadataReaderInterface
|
||||
{
|
||||
/**
|
||||
* Reads metadata from a file.
|
||||
*
|
||||
* @param $file The path to the file where to read metadata.
|
||||
*
|
||||
* @throws InvalidArgumentException In case the file does not exist.
|
||||
*
|
||||
* @return MetadataBag
|
||||
*/
|
||||
public function readFile($file);
|
||||
|
||||
/**
|
||||
* Reads metadata from a binary string.
|
||||
*
|
||||
* @param $data The binary string to read.
|
||||
*
|
||||
* @return MetadataBag
|
||||
*/
|
||||
public function readData($data);
|
||||
|
||||
/**
|
||||
* Reads metadata from a stream.
|
||||
*
|
||||
* @param $resource The stream to read.
|
||||
*
|
||||
* @throws InvalidArgumentException In case the resource is not valid.
|
||||
*
|
||||
* @return MetadataBag
|
||||
*/
|
||||
public function readStream($resource);
|
||||
}
|
||||
118
rainloop/v/0.0.0/app/libraries/Imagine/Image/Palette/CMYK.php
Normal file
118
rainloop/v/0.0.0/app/libraries/Imagine/Image/Palette/CMYK.php
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Palette;
|
||||
|
||||
use Imagine\Image\Palette\Color\CMYK as CMYKColor;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Image\Profile;
|
||||
use Imagine\Image\ProfileInterface;
|
||||
|
||||
class CMYK implements PaletteInterface
|
||||
{
|
||||
private $parser;
|
||||
private $profile;
|
||||
private static $colors = array();
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->parser = new ColorParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
return PaletteInterface::PALETTE_CMYK;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function pixelDefinition()
|
||||
{
|
||||
return array(
|
||||
ColorInterface::COLOR_CYAN,
|
||||
ColorInterface::COLOR_MAGENTA,
|
||||
ColorInterface::COLOR_YELLOW,
|
||||
ColorInterface::COLOR_KEYLINE,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsAlpha()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function color($color, $alpha = null)
|
||||
{
|
||||
if (null !== $alpha) {
|
||||
throw new InvalidArgumentException('CMYK palette does not support alpha');
|
||||
}
|
||||
|
||||
$color = $this->parser->parseToCMYK($color);
|
||||
$index = sprintf('cmyk(%d, %d, %d, %d)', $color[0], $color[1], $color[2], $color[3]);
|
||||
|
||||
if (false === array_key_exists($index, self::$colors)) {
|
||||
self::$colors[$index] = new CMYKColor($this, $color);
|
||||
}
|
||||
|
||||
return self::$colors[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blend(ColorInterface $color1, ColorInterface $color2, $amount)
|
||||
{
|
||||
if (!$color1 instanceof CMYKColor || ! $color2 instanceof CMYKColor) {
|
||||
throw new RuntimeException('CMYK palette can only blend CMYK colors');
|
||||
}
|
||||
|
||||
return $this->color(array(
|
||||
min(100, $color1->getCyan() + $color2->getCyan() * $amount),
|
||||
min(100, $color1->getMagenta() + $color2->getMagenta() * $amount),
|
||||
min(100, $color1->getYellow() + $color2->getYellow() * $amount),
|
||||
min(100, $color1->getKeyline() + $color2->getKeyline() * $amount),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function useProfile(ProfileInterface $profile)
|
||||
{
|
||||
$this->profile = $profile;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function profile()
|
||||
{
|
||||
if (!$this->profile) {
|
||||
$this->profile = Profile::fromPath(__DIR__ . '/../../resources/Adobe/CMYK/USWebUncoated.icc');
|
||||
}
|
||||
|
||||
return $this->profile;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Palette\Color;
|
||||
|
||||
use Imagine\Image\Palette\CMYK as CMYKPalette;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
|
||||
final class CMYK implements ColorInterface
|
||||
{
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $c;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $m;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $y;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $k;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var CMYK
|
||||
*/
|
||||
private $palette;
|
||||
|
||||
public function __construct(CMYKPalette $palette, array $color)
|
||||
{
|
||||
$this->palette = $palette;
|
||||
$this->setColor($color);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValue($component)
|
||||
{
|
||||
switch ($component) {
|
||||
case ColorInterface::COLOR_CYAN:
|
||||
return $this->getCyan();
|
||||
case ColorInterface::COLOR_MAGENTA:
|
||||
return $this->getMagenta();
|
||||
case ColorInterface::COLOR_YELLOW:
|
||||
return $this->getYellow();
|
||||
case ColorInterface::COLOR_KEYLINE:
|
||||
return $this->getKeyline();
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Cyan value of the color
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getCyan()
|
||||
{
|
||||
return $this->c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Magenta value of the color
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getMagenta()
|
||||
{
|
||||
return $this->m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Yellow value of the color
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getYellow()
|
||||
{
|
||||
return $this->y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Key value of the color
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getKeyline()
|
||||
{
|
||||
return $this->k;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPalette()
|
||||
{
|
||||
return $this->palette;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAlpha()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dissolve($alpha)
|
||||
{
|
||||
throw new RuntimeException('CMYK does not support dissolution');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lighten($shade)
|
||||
{
|
||||
return $this->palette->color(
|
||||
array(
|
||||
$this->c,
|
||||
$this->m,
|
||||
$this->y,
|
||||
max(0, $this->k - $shade),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function darken($shade)
|
||||
{
|
||||
return $this->palette->color(
|
||||
array(
|
||||
$this->c,
|
||||
$this->m,
|
||||
$this->y,
|
||||
min(100, $this->k + $shade),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function grayscale()
|
||||
{
|
||||
$color = array(
|
||||
$this->c * (1 - $this->k / 100) + $this->k,
|
||||
$this->m * (1 - $this->k / 100) + $this->k,
|
||||
$this->y * (1 - $this->k / 100) + $this->k,
|
||||
);
|
||||
|
||||
$gray = min(100, round(0.299 * $color[0] + 0.587 * $color[1] + 0.114 * $color[2]));
|
||||
|
||||
return $this->palette->color(array($gray, $gray, $gray, $this->k));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isOpaque()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns hex representation of the color
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('cmyk(%d%%, %d%%, %d%%, %d%%)', $this->c, $this->m, $this->y, $this->k);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal, Performs checks for color validity (an of array(C, M, Y, K))
|
||||
*
|
||||
* @param array $color
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function setColor(array $color)
|
||||
{
|
||||
if (count($color) !== 4) {
|
||||
throw new InvalidArgumentException('Color argument must look like array(C, M, Y, K), where C, M, Y, K are the integer values between 0 and 255 for cyan, magenta, yellow and black color indexes accordingly');
|
||||
}
|
||||
|
||||
$colors = array_values($color);
|
||||
array_walk($colors, function ($color) {
|
||||
return max(0, min(100, $color));
|
||||
});
|
||||
|
||||
list($this->c, $this->m, $this->y, $this->k) = $colors;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Palette\Color;
|
||||
|
||||
use Imagine\Image\Palette\PaletteInterface;
|
||||
|
||||
interface ColorInterface
|
||||
{
|
||||
const COLOR_RED = 'red';
|
||||
const COLOR_GREEN = 'green';
|
||||
const COLOR_BLUE = 'blue';
|
||||
|
||||
const COLOR_CYAN = 'cyan';
|
||||
const COLOR_MAGENTA = 'magenta';
|
||||
const COLOR_YELLOW = 'yellow';
|
||||
const COLOR_KEYLINE = 'keyline';
|
||||
|
||||
const COLOR_GRAY = 'gray';
|
||||
|
||||
/**
|
||||
* Return the value of one of the component.
|
||||
*
|
||||
* @param string $component One of the ColorInterface::COLOR_* component
|
||||
*
|
||||
* @return Integer
|
||||
*/
|
||||
public function getValue($component);
|
||||
|
||||
/**
|
||||
* Returns percentage of transparency of the color
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getAlpha();
|
||||
|
||||
/**
|
||||
* Returns the palette attached to the current color
|
||||
*
|
||||
* @return PaletteInterface
|
||||
*/
|
||||
public function getPalette();
|
||||
|
||||
/**
|
||||
* Returns a copy of current color, incrementing the alpha channel by the
|
||||
* given amount
|
||||
*
|
||||
* @param integer $alpha
|
||||
*
|
||||
* @return ColorInterface
|
||||
*/
|
||||
public function dissolve($alpha);
|
||||
|
||||
/**
|
||||
* Returns a copy of the current color, lightened by the specified number
|
||||
* of shades
|
||||
*
|
||||
* @param integer $shade
|
||||
*
|
||||
* @return ColorInterface
|
||||
*/
|
||||
public function lighten($shade);
|
||||
|
||||
/**
|
||||
* Returns a copy of the current color, darkened by the specified number of
|
||||
* shades
|
||||
*
|
||||
* @param integer $shade
|
||||
*
|
||||
* @return ColorInterface
|
||||
*/
|
||||
public function darken($shade);
|
||||
|
||||
/**
|
||||
* Returns a gray related to the current color
|
||||
*
|
||||
* @return ColorInterface
|
||||
*/
|
||||
public function grayscale();
|
||||
|
||||
/**
|
||||
* Checks if the current color is opaque
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function isOpaque();
|
||||
}
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Palette\Color;
|
||||
|
||||
use Imagine\Image\Palette\Grayscale;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
|
||||
final class Gray implements ColorInterface
|
||||
{
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $gray;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $alpha;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var Grayscale
|
||||
*/
|
||||
private $palette;
|
||||
|
||||
public function __construct(Grayscale $palette, array $color, $alpha)
|
||||
{
|
||||
$this->palette = $palette;
|
||||
$this->setColor($color);
|
||||
$this->setAlpha($alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValue($component)
|
||||
{
|
||||
switch ($component) {
|
||||
case ColorInterface::COLOR_GRAY:
|
||||
return $this->getGray();
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Gray value of the color
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getGray()
|
||||
{
|
||||
return $this->gray;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPalette()
|
||||
{
|
||||
return $this->palette;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAlpha()
|
||||
{
|
||||
return $this->alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dissolve($alpha)
|
||||
{
|
||||
return $this->palette->color(
|
||||
array($this->gray), $this->alpha + $alpha
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lighten($shade)
|
||||
{
|
||||
return $this->palette->color(array(min(255, $this->gray + $shade)), $this->alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function darken($shade)
|
||||
{
|
||||
return $this->palette->color(array(max(0, $this->gray - $shade)), $this->alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function grayscale()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isOpaque()
|
||||
{
|
||||
return 100 === $this->alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns hex representation of the color
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('#%02x%02x%02x', $this->gray, $this->gray, $this->gray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs checks for validity of given alpha value and sets it
|
||||
*
|
||||
* @param integer $alpha
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function setAlpha($alpha)
|
||||
{
|
||||
if (!is_int($alpha) || $alpha < 0 || $alpha > 100) {
|
||||
throw new InvalidArgumentException(sprintf('Alpha must be an integer between 0 and 100, %s given', $alpha));
|
||||
}
|
||||
|
||||
$this->alpha = $alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs checks for color validity (array of array(gray))
|
||||
*
|
||||
* @param array $color
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function setColor(array $color)
|
||||
{
|
||||
if (count($color) !== 1) {
|
||||
throw new InvalidArgumentException('Color argument must look like array(gray), where gray is the integer value between 0 and 255 for the grayscale');
|
||||
}
|
||||
|
||||
list($this->gray) = array_values($color);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Palette\Color;
|
||||
|
||||
use Imagine\Image\Palette\RGB as RGBPalette;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
|
||||
final class RGB implements ColorInterface
|
||||
{
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $r;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $g;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $b;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $alpha;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var RGBPalette
|
||||
*/
|
||||
private $palette;
|
||||
|
||||
public function __construct(RGBPalette $palette, array $color, $alpha)
|
||||
{
|
||||
$this->palette = $palette;
|
||||
$this->setColor($color);
|
||||
$this->setAlpha($alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValue($component)
|
||||
{
|
||||
switch ($component) {
|
||||
case ColorInterface::COLOR_RED:
|
||||
return $this->getRed();
|
||||
case ColorInterface::COLOR_GREEN:
|
||||
return $this->getGreen();
|
||||
case ColorInterface::COLOR_BLUE:
|
||||
return $this->getBlue();
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('Color component %s is not valid', $component));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns RED value of the color
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getRed()
|
||||
{
|
||||
return $this->r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns GREEN value of the color
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getGreen()
|
||||
{
|
||||
return $this->g;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns BLUE value of the color
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getBlue()
|
||||
{
|
||||
return $this->b;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPalette()
|
||||
{
|
||||
return $this->palette;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAlpha()
|
||||
{
|
||||
return $this->alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dissolve($alpha)
|
||||
{
|
||||
return $this->palette->color(array($this->r, $this->g, $this->b), $this->alpha + $alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function lighten($shade)
|
||||
{
|
||||
return $this->palette->color(
|
||||
array(
|
||||
min(255, $this->r + $shade),
|
||||
min(255, $this->g + $shade),
|
||||
min(255, $this->b + $shade),
|
||||
), $this->alpha
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function darken($shade)
|
||||
{
|
||||
return $this->palette->color(
|
||||
array(
|
||||
max(0, $this->r - $shade),
|
||||
max(0, $this->g - $shade),
|
||||
max(0, $this->b - $shade),
|
||||
), $this->alpha
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function grayscale()
|
||||
{
|
||||
$gray = min(255, round(0.299 * $this->getRed() + 0.114 * $this->getBlue() + 0.587 * $this->getGreen()));
|
||||
|
||||
return $this->palette->color(array($gray, $gray, $gray), $this->alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isOpaque()
|
||||
{
|
||||
return 100 === $this->alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns hex representation of the color
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('#%02x%02x%02x', $this->r, $this->g, $this->b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Performs checks for validity of given alpha value and sets it
|
||||
*
|
||||
* @param integer $alpha
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function setAlpha($alpha)
|
||||
{
|
||||
if (!is_int($alpha) || $alpha < 0 || $alpha > 100) {
|
||||
throw new InvalidArgumentException(sprintf('Alpha must be an integer between 0 and 100, %s given', $alpha));
|
||||
}
|
||||
|
||||
$this->alpha = $alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Performs checks for color validity (array of array(R, G, B))
|
||||
*
|
||||
* @param array $color
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function setColor(array $color)
|
||||
{
|
||||
if (count($color) !== 3) {
|
||||
throw new InvalidArgumentException('Color argument must look like array(R, G, B), where R, G, B are the integer values between 0 and 255 for red, green and blue color indexes accordingly');
|
||||
}
|
||||
|
||||
list($this->r, $this->g, $this->b) = array_values($color);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Palette;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
|
||||
class ColorParser
|
||||
{
|
||||
/**
|
||||
* Parses a color to a RGB tuple
|
||||
*
|
||||
* @param string|array|integer $color
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function parseToRGB($color)
|
||||
{
|
||||
$color = $this->parse($color);
|
||||
|
||||
if (4 === count($color)) {
|
||||
$color = array(
|
||||
255 * (1 - $color[0] / 100) * (1 - $color[3] / 100),
|
||||
255 * (1 - $color[1] / 100) * (1 - $color[3] / 100),
|
||||
255 * (1 - $color[2] / 100) * (1 - $color[3] / 100),
|
||||
);
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a color to a CMYK tuple
|
||||
*
|
||||
* @param string|array|integer $color
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function parseToCMYK($color)
|
||||
{
|
||||
$color = $this->parse($color);
|
||||
|
||||
if (3 === count($color)) {
|
||||
$r = $color[0] / 255;
|
||||
$g = $color[1] / 255;
|
||||
$b = $color[2] / 255;
|
||||
|
||||
$k = 1 - max($r, $g, $b);
|
||||
|
||||
$color = array(
|
||||
1 === $k ? 0 : round((1 - $r - $k) / (1- $k) * 100),
|
||||
1 === $k ? 0 : round((1 - $g - $k) / (1- $k) * 100),
|
||||
1 === $k ? 0 : round((1 - $b - $k) / (1- $k) * 100),
|
||||
round($k * 100)
|
||||
);
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a color to a grayscale value
|
||||
*
|
||||
* @param string|array|integer $color
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function parseToGrayscale($color)
|
||||
{
|
||||
if (is_array($color) && 1 === count($color)) {
|
||||
return array_values($color);
|
||||
}
|
||||
|
||||
$color = array_unique($this->parse($color));
|
||||
|
||||
if (1 !== count($color)) {
|
||||
throw new InvalidArgumentException('The provided color has different values of red, green and blue components. Grayscale colors must have the same values for these.');
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a color
|
||||
*
|
||||
* @param string|array|integer $color
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function parse($color)
|
||||
{
|
||||
if (!is_string($color) && !is_array($color) && !is_int($color)) {
|
||||
throw new InvalidArgumentException(sprintf('Color must be specified as a hexadecimal string, array or integer, %s given', gettype($color)));
|
||||
}
|
||||
|
||||
if (is_array($color)) {
|
||||
if (3 === count($color) || 4 === count($color)) {
|
||||
return array_values($color);
|
||||
}
|
||||
throw new InvalidArgumentException('Color argument if array, must look like array(R, G, B), or array(C, M, Y, K) where R, G, B are the integer values between 0 and 255 for red, green and blue or cyan, magenta, yellow and black color indexes accordingly');
|
||||
}
|
||||
|
||||
if (is_string($color)) {
|
||||
if (0 === strpos($color, 'cmyk(')) {
|
||||
$substrColor = substr($color, 5, strlen($color) - 6);
|
||||
|
||||
$components = array_map(function ($component) {
|
||||
return round(trim($component, ' %'));
|
||||
}, explode(',', $substrColor));
|
||||
|
||||
if (count($components) !== 4) {
|
||||
throw new InvalidArgumentException(sprintf('Unable to parse color %s', $color));
|
||||
}
|
||||
|
||||
return $components;
|
||||
} else {
|
||||
$color = ltrim($color, '#');
|
||||
|
||||
if (strlen($color) !== 3 && strlen($color) !== 6) {
|
||||
throw new InvalidArgumentException(sprintf('Color must be a hex value in regular (6 characters) or short (3 characters) notation, "%s" given', $color));
|
||||
}
|
||||
|
||||
if (strlen($color) === 3) {
|
||||
$color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2];
|
||||
}
|
||||
|
||||
$color = array_map('hexdec', str_split($color, 2));
|
||||
}
|
||||
}
|
||||
|
||||
if (is_int($color)) {
|
||||
$color = array(255 & ($color >> 16), 255 & ($color >> 8), 255 & $color);
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Palette;
|
||||
|
||||
use Imagine\Image\Palette\Color\Gray as GrayColor;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\ProfileInterface;
|
||||
use Imagine\Image\Profile;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
|
||||
class Grayscale implements PaletteInterface
|
||||
{
|
||||
/**
|
||||
* @var ColorParser
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
/**
|
||||
* @var ProfileInterface
|
||||
*/
|
||||
private $profile;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $colors = array();
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->parser = new ColorParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
return PaletteInterface::PALETTE_GRAYSCALE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function pixelDefinition()
|
||||
{
|
||||
return array(ColorInterface::COLOR_GRAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsAlpha()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function useProfile(ProfileInterface $profile)
|
||||
{
|
||||
$this->profile = $profile;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function profile()
|
||||
{
|
||||
if (!$this->profile) {
|
||||
$this->profile = Profile::fromPath(__DIR__ . '/../../resources/colormanagement.org/ISOcoated_v2_grey1c_bas.ICC');
|
||||
}
|
||||
|
||||
return $this->profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function color($color, $alpha = null)
|
||||
{
|
||||
if (null === $alpha) {
|
||||
$alpha = 0;
|
||||
}
|
||||
|
||||
$color = $this->parser->parseToGrayscale($color);
|
||||
$index = sprintf('#%02x%02x%02x-%d', $color[0], $color[0], $color[0], $alpha);
|
||||
|
||||
if (false === array_key_exists($index, static::$colors)) {
|
||||
static::$colors[$index] = new GrayColor($this, $color, $alpha);
|
||||
}
|
||||
|
||||
return static::$colors[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blend(ColorInterface $color1, ColorInterface $color2, $amount)
|
||||
{
|
||||
if (!$color1 instanceof GrayColor || ! $color2 instanceof GrayColor) {
|
||||
throw new RuntimeException('Grayscale palette can only blend Grayscale colors');
|
||||
}
|
||||
|
||||
return $this->color(
|
||||
array(
|
||||
(int) min(255, min($color1->getGray(), $color2->getGray()) + round(abs($color2->getGray() - $color1->getGray()) * $amount)),
|
||||
),
|
||||
(int) min(100, min($color1->getAlpha(), $color2->getAlpha()) + round(abs($color2->getAlpha() - $color1->getAlpha()) * $amount))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Palette;
|
||||
|
||||
use Imagine\Image\ProfileInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
|
||||
interface PaletteInterface
|
||||
{
|
||||
const PALETTE_GRAYSCALE = 'gray';
|
||||
const PALETTE_RGB = 'rgb';
|
||||
const PALETTE_CMYK = 'cmyk';
|
||||
|
||||
/**
|
||||
* Returns a color given some values
|
||||
*
|
||||
* @param string|array|integer $color A color
|
||||
* @param integer|null $alpha Set alpha to null to disable it
|
||||
*
|
||||
* @return ColorInterface
|
||||
*
|
||||
* @throws InvalidArgumentException In case you pass an alpha value to a
|
||||
* Palette that does not support alpha
|
||||
*/
|
||||
public function color($color, $alpha = null);
|
||||
|
||||
/**
|
||||
* Blend two colors given an amount
|
||||
*
|
||||
* @param ColorInterface $color1
|
||||
* @param ColorInterface $color2
|
||||
* @param float $amount The amount of color2 in color1
|
||||
*
|
||||
* @return ColorInterface
|
||||
*/
|
||||
public function blend(ColorInterface $color1, ColorInterface $color2, $amount);
|
||||
|
||||
/**
|
||||
* Attachs an ICC profile to this Palette.
|
||||
*
|
||||
* (A default profile is provided by default)
|
||||
*
|
||||
* @param ProfileInterface $profile
|
||||
*
|
||||
* @return PaletteInterface
|
||||
*/
|
||||
public function useProfile(ProfileInterface $profile);
|
||||
|
||||
/**
|
||||
* Returns the ICC profile attached to this Palette.
|
||||
*
|
||||
* @return ProfileInterface
|
||||
*/
|
||||
public function profile();
|
||||
|
||||
/**
|
||||
* Returns the name of this Palette, one of PaletteInterface::PALETTE_*
|
||||
* constants
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function name();
|
||||
|
||||
/**
|
||||
* Returns an array containing ColorInterface::COLOR_* constants that
|
||||
* define the structure of colors for a pixel.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function pixelDefinition();
|
||||
|
||||
/**
|
||||
* Tells if alpha channel is supported in this palette
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function supportsAlpha();
|
||||
}
|
||||
129
rainloop/v/0.0.0/app/libraries/Imagine/Image/Palette/RGB.php
Normal file
129
rainloop/v/0.0.0/app/libraries/Imagine/Image/Palette/RGB.php
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Palette;
|
||||
|
||||
use Imagine\Image\Palette\Color\RGB as RGBColor;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\ProfileInterface;
|
||||
use Imagine\Image\Profile;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
|
||||
class RGB implements PaletteInterface
|
||||
{
|
||||
/**
|
||||
* @var ColorParser
|
||||
*/
|
||||
private $parser;
|
||||
|
||||
/**
|
||||
* @var ProfileInterface
|
||||
*/
|
||||
private $profile;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static $colors = array();
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->parser = new ColorParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
return PaletteInterface::PALETTE_RGB;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function pixelDefinition()
|
||||
{
|
||||
return array(
|
||||
ColorInterface::COLOR_RED,
|
||||
ColorInterface::COLOR_GREEN,
|
||||
ColorInterface::COLOR_BLUE,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsAlpha()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function useProfile(ProfileInterface $profile)
|
||||
{
|
||||
$this->profile = $profile;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function profile()
|
||||
{
|
||||
if (!$this->profile) {
|
||||
$this->profile = Profile::fromPath(__DIR__ . '/../../resources/color.org/sRGB_IEC61966-2-1_black_scaled.icc');
|
||||
}
|
||||
|
||||
return $this->profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function color($color, $alpha = null)
|
||||
{
|
||||
if (null === $alpha) {
|
||||
$alpha = 100;
|
||||
}
|
||||
|
||||
$color = $this->parser->parseToRGB($color);
|
||||
$index = sprintf('#%02x%02x%02x-%d', $color[0], $color[1], $color[2], $alpha);
|
||||
|
||||
if (false === array_key_exists($index, static::$colors)) {
|
||||
static::$colors[$index] = new RGBColor($this, $color, $alpha);
|
||||
}
|
||||
|
||||
return static::$colors[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blend(ColorInterface $color1, ColorInterface $color2, $amount)
|
||||
{
|
||||
if (!$color1 instanceof RGBColor || ! $color2 instanceof RGBColor) {
|
||||
throw new RuntimeException('RGB palette can only blend RGB colors');
|
||||
}
|
||||
|
||||
return $this->color(
|
||||
array(
|
||||
(int) min(255, min($color1->getRed(), $color2->getRed()) + round(abs($color2->getRed() - $color1->getRed()) * $amount)),
|
||||
(int) min(255, min($color1->getGreen(), $color2->getGreen()) + round(abs($color2->getGreen() - $color1->getGreen()) * $amount)),
|
||||
(int) min(255, min($color1->getBlue(), $color2->getBlue()) + round(abs($color2->getBlue() - $color1->getBlue()) * $amount)),
|
||||
),
|
||||
(int) min(100, min($color1->getAlpha(), $color2->getAlpha()) + round(abs($color2->getAlpha() - $color1->getAlpha()) * $amount))
|
||||
);
|
||||
}
|
||||
}
|
||||
88
rainloop/v/0.0.0/app/libraries/Imagine/Image/Point.php
Normal file
88
rainloop/v/0.0.0/app/libraries/Imagine/Image/Point.php
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* The point class
|
||||
*/
|
||||
final class Point implements PointInterface
|
||||
{
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $x;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $y;
|
||||
|
||||
/**
|
||||
* Constructs a point of coordinates
|
||||
*
|
||||
* @param integer $x
|
||||
* @param integer $y
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct($x, $y)
|
||||
{
|
||||
if ($x < 0 || $y < 0) {
|
||||
throw new InvalidArgumentException(sprintf('A coordinate cannot be positioned outside of a bounding box (x: %s, y: %s given)', $x, $y));
|
||||
}
|
||||
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getX()
|
||||
{
|
||||
return $this->x;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getY()
|
||||
{
|
||||
return $this->y;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function in(BoxInterface $box)
|
||||
{
|
||||
return $this->x < $box->getWidth() && $this->y < $box->getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function move($amount)
|
||||
{
|
||||
return new Point($this->x + $amount, $this->y + $amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('(%d, %d)', $this->x, $this->y);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image\Point;
|
||||
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Point as OriginalPoint;
|
||||
use Imagine\Image\PointInterface;
|
||||
|
||||
/**
|
||||
* Point center
|
||||
*/
|
||||
final class Center implements PointInterface
|
||||
{
|
||||
/**
|
||||
* @var BoxInterface
|
||||
*/
|
||||
private $box;
|
||||
|
||||
/**
|
||||
* Constructs coordinate with size instance, it needs to be relative to
|
||||
*
|
||||
* @param BoxInterface $box
|
||||
*/
|
||||
public function __construct(BoxInterface $box)
|
||||
{
|
||||
$this->box = $box;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getX()
|
||||
{
|
||||
return ceil($this->box->getWidth() / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getY()
|
||||
{
|
||||
return ceil($this->box->getHeight() / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function in(BoxInterface $box)
|
||||
{
|
||||
return $this->getX() < $box->getWidth() && $this->getY() < $box->getHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function move($amount)
|
||||
{
|
||||
return new OriginalPoint($this->getX() + $amount, $this->getY() + $amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return sprintf('(%d, %d)', $this->getX(), $this->getY());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
/**
|
||||
* The point interface
|
||||
*/
|
||||
interface PointInterface
|
||||
{
|
||||
/**
|
||||
* Gets points x coordinate
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getX();
|
||||
|
||||
/**
|
||||
* Gets points y coordinate
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getY();
|
||||
|
||||
/**
|
||||
* Checks if current coordinate is inside a given bo
|
||||
*
|
||||
* @param BoxInterface $box
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
public function in(BoxInterface $box);
|
||||
|
||||
/**
|
||||
* Returns another point, moved by a given amount from current coordinates
|
||||
*
|
||||
* @param integer $amount
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function move($amount);
|
||||
|
||||
/**
|
||||
* Gets a string representation for the current point
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString();
|
||||
}
|
||||
60
rainloop/v/0.0.0/app/libraries/Imagine/Image/Profile.php
Normal file
60
rainloop/v/0.0.0/app/libraries/Imagine/Image/Profile.php
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
|
||||
class Profile implements ProfileInterface
|
||||
{
|
||||
private $data;
|
||||
private $name;
|
||||
|
||||
public function __construct($name, $data)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function name()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function data()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a profile from a path to a file
|
||||
*
|
||||
* @param String $path
|
||||
*
|
||||
* @return Profile
|
||||
*
|
||||
* @throws InvalidArgumentException In case the provided path is not valid
|
||||
*/
|
||||
public static function fromPath($path)
|
||||
{
|
||||
if (!file_exists($path) || !is_file($path) || !is_readable($path)) {
|
||||
throw new InvalidArgumentException(sprintf('Path %s is an invalid profile file or is not readable', $path));
|
||||
}
|
||||
|
||||
return new static(basename($path), file_get_contents($path));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Image;
|
||||
|
||||
interface ProfileInterface
|
||||
{
|
||||
/**
|
||||
* Returns the name of the profile
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function name();
|
||||
|
||||
/**
|
||||
* Returns the profile data
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function data();
|
||||
}
|
||||
404
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Drawer.php
Normal file
404
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Drawer.php
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Imagick;
|
||||
|
||||
use Imagine\Draw\DrawerInterface;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\AbstractFont;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Point;
|
||||
use Imagine\Image\PointInterface;
|
||||
|
||||
/**
|
||||
* Drawer implementation using the Imagick PHP extension
|
||||
*/
|
||||
final class Drawer implements DrawerInterface
|
||||
{
|
||||
/**
|
||||
* @var Imagick
|
||||
*/
|
||||
private $imagick;
|
||||
|
||||
/**
|
||||
* @param \Imagick $imagick
|
||||
*/
|
||||
public function __construct(\Imagick $imagick)
|
||||
{
|
||||
$this->imagick = $imagick;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function arc(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $thickness = 1)
|
||||
{
|
||||
$x = $center->getX();
|
||||
$y = $center->getY();
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$arc = new \ImagickDraw();
|
||||
|
||||
$arc->setStrokeColor($pixel);
|
||||
$arc->setStrokeWidth(max(1, (int) $thickness));
|
||||
$arc->setFillColor('transparent');
|
||||
$arc->arc($x - $width / 2, $y - $height / 2, $x + $width / 2, $y + $height / 2, $start, $end);
|
||||
|
||||
$this->imagick->drawImage($arc);
|
||||
|
||||
$pixel->clear();
|
||||
$pixel->destroy();
|
||||
|
||||
$arc->clear();
|
||||
$arc->destroy();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Draw arc operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function chord(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
$x = $center->getX();
|
||||
$y = $center->getY();
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$chord = new \ImagickDraw();
|
||||
|
||||
$chord->setStrokeColor($pixel);
|
||||
$chord->setStrokeWidth(max(1, (int) $thickness));
|
||||
|
||||
if ($fill) {
|
||||
$chord->setFillColor($pixel);
|
||||
} else {
|
||||
$this->line(
|
||||
new Point(round($x + $width / 2 * cos(deg2rad($start))), round($y + $height / 2 * sin(deg2rad($start)))),
|
||||
new Point(round($x + $width / 2 * cos(deg2rad($end))), round($y + $height / 2 * sin(deg2rad($end)))),
|
||||
$color
|
||||
);
|
||||
|
||||
$chord->setFillColor('transparent');
|
||||
}
|
||||
|
||||
$chord->arc(
|
||||
$x - $width / 2,
|
||||
$y - $height / 2,
|
||||
$x + $width / 2,
|
||||
$y + $height / 2,
|
||||
$start,
|
||||
$end
|
||||
);
|
||||
|
||||
$this->imagick->drawImage($chord);
|
||||
|
||||
$pixel->clear();
|
||||
$pixel->destroy();
|
||||
|
||||
$chord->clear();
|
||||
$chord->destroy();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Draw chord operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function ellipse(PointInterface $center, BoxInterface $size, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$ellipse = new \ImagickDraw();
|
||||
|
||||
$ellipse->setStrokeColor($pixel);
|
||||
$ellipse->setStrokeWidth(max(1, (int) $thickness));
|
||||
|
||||
if ($fill) {
|
||||
$ellipse->setFillColor($pixel);
|
||||
} else {
|
||||
$ellipse->setFillColor('transparent');
|
||||
}
|
||||
|
||||
$ellipse->ellipse(
|
||||
$center->getX(),
|
||||
$center->getY(),
|
||||
$width / 2,
|
||||
$height / 2,
|
||||
0, 360
|
||||
);
|
||||
|
||||
if (false === $this->imagick->drawImage($ellipse)) {
|
||||
throw new RuntimeException('Ellipse operation failed');
|
||||
}
|
||||
|
||||
$pixel->clear();
|
||||
$pixel->destroy();
|
||||
|
||||
$ellipse->clear();
|
||||
$ellipse->destroy();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Draw ellipse operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function line(PointInterface $start, PointInterface $end, ColorInterface $color, $thickness = 1)
|
||||
{
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$line = new \ImagickDraw();
|
||||
|
||||
$line->setStrokeColor($pixel);
|
||||
$line->setStrokeWidth(max(1, (int) $thickness));
|
||||
$line->setFillColor($pixel);
|
||||
$line->line(
|
||||
$start->getX(),
|
||||
$start->getY(),
|
||||
$end->getX(),
|
||||
$end->getY()
|
||||
);
|
||||
|
||||
$this->imagick->drawImage($line);
|
||||
|
||||
$pixel->clear();
|
||||
$pixel->destroy();
|
||||
|
||||
$line->clear();
|
||||
$line->destroy();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Draw line operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function pieSlice(PointInterface $center, BoxInterface $size, $start, $end, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
$x1 = round($center->getX() + $width / 2 * cos(deg2rad($start)));
|
||||
$y1 = round($center->getY() + $height / 2 * sin(deg2rad($start)));
|
||||
$x2 = round($center->getX() + $width / 2 * cos(deg2rad($end)));
|
||||
$y2 = round($center->getY() + $height / 2 * sin(deg2rad($end)));
|
||||
|
||||
if ($fill) {
|
||||
$this->chord($center, $size, $start, $end, $color, true, $thickness);
|
||||
$this->polygon(
|
||||
array(
|
||||
$center,
|
||||
new Point($x1, $y1),
|
||||
new Point($x2, $y2),
|
||||
),
|
||||
$color,
|
||||
true,
|
||||
$thickness
|
||||
);
|
||||
} else {
|
||||
$this->arc($center, $size, $start, $end, $color, $thickness);
|
||||
$this->line($center, new Point($x1, $y1), $color, $thickness);
|
||||
$this->line($center, new Point($x2, $y2), $color, $thickness);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function dot(PointInterface $position, ColorInterface $color)
|
||||
{
|
||||
$x = $position->getX();
|
||||
$y = $position->getY();
|
||||
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$point = new \ImagickDraw();
|
||||
|
||||
$point->setFillColor($pixel);
|
||||
$point->point($x, $y);
|
||||
|
||||
$this->imagick->drawimage($point);
|
||||
|
||||
$pixel->clear();
|
||||
$pixel->destroy();
|
||||
|
||||
$point->clear();
|
||||
$point->destroy();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Draw point operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function polygon(array $coordinates, ColorInterface $color, $fill = false, $thickness = 1)
|
||||
{
|
||||
if (count($coordinates) < 3) {
|
||||
throw new InvalidArgumentException(sprintf('Polygon must consist of at least 3 coordinates, %d given', count($coordinates)));
|
||||
}
|
||||
|
||||
$points = array_map(function (PointInterface $p) {
|
||||
return array('x' => $p->getX(), 'y' => $p->getY());
|
||||
}, $coordinates);
|
||||
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
$polygon = new \ImagickDraw();
|
||||
|
||||
$polygon->setStrokeColor($pixel);
|
||||
$polygon->setStrokeWidth(max(1, (int) $thickness));
|
||||
|
||||
if ($fill) {
|
||||
$polygon->setFillColor($pixel);
|
||||
} else {
|
||||
$polygon->setFillColor('transparent');
|
||||
}
|
||||
|
||||
$polygon->polygon($points);
|
||||
$this->imagick->drawImage($polygon);
|
||||
|
||||
$pixel->clear();
|
||||
$pixel->destroy();
|
||||
|
||||
$polygon->clear();
|
||||
$polygon->destroy();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Draw polygon operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function text($string, AbstractFont $font, PointInterface $position, $angle = 0, $width = null)
|
||||
{
|
||||
try {
|
||||
$pixel = $this->getColor($font->getColor());
|
||||
$text = new \ImagickDraw();
|
||||
|
||||
$text->setFont($font->getFile());
|
||||
/**
|
||||
* @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027
|
||||
*
|
||||
* ensure font resolution is the same as GD's hard-coded 96
|
||||
*/
|
||||
if (version_compare(phpversion("imagick"), "3.0.2", ">=")) {
|
||||
$text->setResolution(96, 96);
|
||||
$text->setFontSize($font->getSize());
|
||||
} else {
|
||||
$text->setFontSize((int) ($font->getSize() * (96 / 72)));
|
||||
}
|
||||
$text->setFillColor($pixel);
|
||||
$text->setTextAntialias(true);
|
||||
|
||||
$info = $this->imagick->queryFontMetrics($text, $string);
|
||||
$rad = deg2rad($angle);
|
||||
$cos = cos($rad);
|
||||
$sin = sin($rad);
|
||||
|
||||
// round(0 * $cos - 0 * $sin)
|
||||
$x1 = 0;
|
||||
$x2 = round($info['characterWidth'] * $cos - $info['characterHeight'] * $sin);
|
||||
// round(0 * $sin + 0 * $cos)
|
||||
$y1 = 0;
|
||||
$y2 = round($info['characterWidth'] * $sin + $info['characterHeight'] * $cos);
|
||||
|
||||
$xdiff = 0 - min($x1, $x2);
|
||||
$ydiff = 0 - min($y1, $y2);
|
||||
|
||||
if ($width !== null) {
|
||||
$string = $this->wrapText($string, $text, $angle, $width);
|
||||
}
|
||||
|
||||
$this->imagick->annotateImage(
|
||||
$text, $position->getX() + $x1 + $xdiff,
|
||||
$position->getY() + $y2 + $ydiff, $angle, $string
|
||||
);
|
||||
|
||||
$pixel->clear();
|
||||
$pixel->destroy();
|
||||
|
||||
$text->clear();
|
||||
$text->destroy();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Draw text operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets specifically formatted color string from ColorInterface instance
|
||||
*
|
||||
* @param ColorInterface $color
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getColor(ColorInterface $color)
|
||||
{
|
||||
$pixel = new \ImagickPixel((string) $color);
|
||||
$pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100);
|
||||
|
||||
return $pixel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Fits a string into box with given width
|
||||
*/
|
||||
private function wrapText($string, $text, $angle, $width)
|
||||
{
|
||||
$result = '';
|
||||
$words = explode(' ', $string);
|
||||
foreach ($words as $word) {
|
||||
$teststring = $result . ' ' . $word;
|
||||
$testbox = $this->imagick->queryFontMetrics($text, $teststring, true);
|
||||
if ($testbox['textWidth'] > $width) {
|
||||
$result .= ($result == '' ? '' : "\n") . $word;
|
||||
} else {
|
||||
$result .= ($result == '' ? '' : ' ') . $word;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
113
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Effects.php
Normal file
113
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Effects.php
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Imagick;
|
||||
|
||||
use Imagine\Effects\EffectsInterface;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
|
||||
/**
|
||||
* Effects implementation using the Imagick PHP extension
|
||||
*/
|
||||
class Effects implements EffectsInterface
|
||||
{
|
||||
private $imagick;
|
||||
|
||||
public function __construct(\Imagick $imagick)
|
||||
{
|
||||
$this->imagick = $imagick;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function gamma($correction)
|
||||
{
|
||||
try {
|
||||
$this->imagick->gammaImage($correction, \Imagick::CHANNEL_ALL);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to apply gamma correction to the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function negative()
|
||||
{
|
||||
try {
|
||||
$this->imagick->negateImage(false, \Imagick::CHANNEL_ALL);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to negate the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function grayscale()
|
||||
{
|
||||
try {
|
||||
$this->imagick->setImageType(\Imagick::IMGTYPE_GRAYSCALE);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to grayscale the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function colorize(ColorInterface $color)
|
||||
{
|
||||
try {
|
||||
$this->imagick->colorizeImage((string) $color, 1);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to colorize the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function sharpen()
|
||||
{
|
||||
try {
|
||||
$this->imagick->sharpenImage(2, 1);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to sharpen the image');
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function blur($sigma = 1)
|
||||
{
|
||||
try {
|
||||
$this->imagick->gaussianBlurImage(0, $sigma);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to blur the image', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
68
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Font.php
Normal file
68
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Font.php
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Imagick;
|
||||
|
||||
use Imagine\Image\AbstractFont;
|
||||
use Imagine\Image\Box;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
|
||||
/**
|
||||
* Font implementation using the Imagick PHP extension
|
||||
*/
|
||||
final class Font extends AbstractFont
|
||||
{
|
||||
/**
|
||||
* @var \Imagick
|
||||
*/
|
||||
private $imagick;
|
||||
|
||||
/**
|
||||
* @param \Imagick $imagick
|
||||
* @param string $file
|
||||
* @param integer $size
|
||||
* @param ColorInterface $color
|
||||
*/
|
||||
public function __construct(\Imagick $imagick, $file, $size, ColorInterface $color)
|
||||
{
|
||||
$this->imagick = $imagick;
|
||||
|
||||
parent::__construct($file, $size, $color);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function box($string, $angle = 0)
|
||||
{
|
||||
$text = new \ImagickDraw();
|
||||
|
||||
$text->setFont($this->file);
|
||||
|
||||
/**
|
||||
* @see http://www.php.net/manual/en/imagick.queryfontmetrics.php#101027
|
||||
*
|
||||
* ensure font resolution is the same as GD's hard-coded 96
|
||||
*/
|
||||
if (version_compare(phpversion("imagick"), "3.0.2", ">=")) {
|
||||
$text->setResolution(96, 96);
|
||||
$text->setFontSize($this->size);
|
||||
} else {
|
||||
$text->setFontSize((int) ($this->size * (96 / 72)));
|
||||
}
|
||||
|
||||
$info = $this->imagick->queryFontMetrics($text, $string);
|
||||
|
||||
$box = new Box($info['textWidth'], $info['textHeight']);
|
||||
|
||||
return $box;
|
||||
}
|
||||
}
|
||||
880
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Image.php
Normal file
880
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Image.php
Normal file
|
|
@ -0,0 +1,880 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Imagick;
|
||||
|
||||
use Imagine\Exception\OutOfBoundsException;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\AbstractImage;
|
||||
use Imagine\Image\Box;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Metadata\MetadataBag;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Image\Fill\FillInterface;
|
||||
use Imagine\Image\Fill\Gradient\Horizontal;
|
||||
use Imagine\Image\Fill\Gradient\Linear;
|
||||
use Imagine\Image\Point;
|
||||
use Imagine\Image\PointInterface;
|
||||
use Imagine\Image\ProfileInterface;
|
||||
use Imagine\Image\ImageInterface;
|
||||
use Imagine\Image\Palette\PaletteInterface;
|
||||
|
||||
/**
|
||||
* Image implementation using the Imagick PHP extension
|
||||
*/
|
||||
final class Image extends AbstractImage
|
||||
{
|
||||
/**
|
||||
* @var \Imagick
|
||||
*/
|
||||
private $imagick;
|
||||
/**
|
||||
* @var Layers
|
||||
*/
|
||||
private $layers;
|
||||
/**
|
||||
* @var PaletteInterface
|
||||
*/
|
||||
private $palette;
|
||||
|
||||
/**
|
||||
* @var Boolean
|
||||
*/
|
||||
private static $supportsColorspaceConversion;
|
||||
|
||||
private static $colorspaceMapping = array(
|
||||
PaletteInterface::PALETTE_CMYK => \Imagick::COLORSPACE_CMYK,
|
||||
PaletteInterface::PALETTE_RGB => \Imagick::COLORSPACE_RGB,
|
||||
PaletteInterface::PALETTE_GRAYSCALE => \Imagick::COLORSPACE_GRAY,
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructs a new Image instance
|
||||
*
|
||||
* @param \Imagick $imagick
|
||||
* @param PaletteInterface $palette
|
||||
* @param MetadataBag $metadata
|
||||
*/
|
||||
public function __construct(\Imagick $imagick, PaletteInterface $palette, MetadataBag $metadata)
|
||||
{
|
||||
$this->metadata = $metadata;
|
||||
$this->detectColorspaceConversionSupport();
|
||||
$this->imagick = $imagick;
|
||||
if (static::$supportsColorspaceConversion) {
|
||||
$this->setColorspace($palette);
|
||||
}
|
||||
$this->palette = $palette;
|
||||
$this->layers = new Layers($this, $this->palette, $this->imagick);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys allocated imagick resources
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->imagick instanceof \Imagick) {
|
||||
$this->imagick->clear();
|
||||
$this->imagick->destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying \Imagick instance
|
||||
*
|
||||
* @return \Imagick
|
||||
*/
|
||||
public function getImagick()
|
||||
{
|
||||
return $this->imagick;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function copy()
|
||||
{
|
||||
try {
|
||||
if (version_compare(phpversion("imagick"), "3.1.0b1", ">=") || defined("HHVM_VERSION")) {
|
||||
$clone = clone $this->imagick;
|
||||
} else {
|
||||
$clone = $this->imagick->clone();
|
||||
}
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Copy operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return new self($clone, $this->palette, clone $this->metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function crop(PointInterface $start, BoxInterface $size)
|
||||
{
|
||||
if (!$start->in($this->getSize())) {
|
||||
throw new OutOfBoundsException('Crop coordinates must start at minimum 0, 0 position from top left corner, crop height and width must be positive integers and must not exceed the current image borders');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->imagick->cropImage($size->getWidth(), $size->getHeight(), $start->getX(), $start->getY());
|
||||
// Reset canvas for gif format
|
||||
$this->imagick->setImagePage(0, 0, 0, 0);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Crop operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function flipHorizontally()
|
||||
{
|
||||
try {
|
||||
$this->imagick->flopImage();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Horizontal Flip operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function flipVertically()
|
||||
{
|
||||
try {
|
||||
$this->imagick->flipImage();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Vertical flip operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function strip()
|
||||
{
|
||||
try {
|
||||
try {
|
||||
$this->profile($this->palette->profile());
|
||||
} catch (\Exception $e) {
|
||||
// here we discard setting the profile as the previous incorporated profile
|
||||
// is corrupted, let's now strip the image
|
||||
}
|
||||
$this->imagick->stripImage();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Strip operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function paste(ImageInterface $image, PointInterface $start)
|
||||
{
|
||||
if (!$image instanceof self) {
|
||||
throw new InvalidArgumentException(sprintf('Imagick\Image can only paste() Imagick\Image instances, %s given', get_class($image)));
|
||||
}
|
||||
|
||||
if (!$this->getSize()->contains($image->getSize(), $start)) {
|
||||
throw new OutOfBoundsException('Cannot paste image of the given size at the specified position, as it moves outside of the current image\'s box');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->imagick->compositeImage($image->imagick, \Imagick::COMPOSITE_DEFAULT, $start->getX(), $start->getY());
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Paste operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function resize(BoxInterface $size, $filter = ImageInterface::FILTER_UNDEFINED)
|
||||
{
|
||||
try {
|
||||
$this->imagick->resizeImage($size->getWidth(), $size->getHeight(), $this->getFilter($filter), 1);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Resize operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function rotate($angle, ColorInterface $background = null)
|
||||
{
|
||||
$color = $background ? $background : $this->palette->color('fff');
|
||||
|
||||
try {
|
||||
$pixel = $this->getColor($color);
|
||||
|
||||
$this->imagick->rotateimage($pixel, $angle);
|
||||
|
||||
$pixel->clear();
|
||||
$pixel->destroy();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Rotate operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function save($path = null, array $options = array())
|
||||
{
|
||||
$path = null === $path ? $this->imagick->getImageFilename() : $path;
|
||||
if (null === $path) {
|
||||
throw new RuntimeException('You can omit save path only if image has been open from a file');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->prepareOutput($options, $path);
|
||||
$this->imagick->writeImages($path, true);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Save operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function show($format, array $options = array())
|
||||
{
|
||||
header('Content-type: '.$this->getMimeType($format));
|
||||
echo $this->get($format, $options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($format, array $options = array())
|
||||
{
|
||||
try {
|
||||
$options['format'] = $format;
|
||||
$this->prepareOutput($options);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Get operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this->imagick->getImagesBlob();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function interlace($scheme)
|
||||
{
|
||||
static $supportedInterlaceSchemes = array(
|
||||
ImageInterface::INTERLACE_NONE => \Imagick::INTERLACE_NO,
|
||||
ImageInterface::INTERLACE_LINE => \Imagick::INTERLACE_LINE,
|
||||
ImageInterface::INTERLACE_PLANE => \Imagick::INTERLACE_PLANE,
|
||||
ImageInterface::INTERLACE_PARTITION => \Imagick::INTERLACE_PARTITION,
|
||||
);
|
||||
|
||||
if (!array_key_exists($scheme, $supportedInterlaceSchemes)) {
|
||||
throw new InvalidArgumentException('Unsupported interlace type');
|
||||
}
|
||||
|
||||
$this->imagick->setInterlaceScheme($supportedInterlaceSchemes[$scheme]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
* @param string $path
|
||||
*/
|
||||
private function prepareOutput(array $options, $path = null)
|
||||
{
|
||||
if (isset($options['format'])) {
|
||||
$this->imagick->setImageFormat($options['format']);
|
||||
}
|
||||
|
||||
if (isset($options['animated']) && true === $options['animated']) {
|
||||
$format = isset($options['format']) ? $options['format'] : 'gif';
|
||||
$delay = isset($options['animated.delay']) ? $options['animated.delay'] : null;
|
||||
$loops = isset($options['animated.loops']) ? $options['animated.loops'] : 0;
|
||||
|
||||
$options['flatten'] = false;
|
||||
|
||||
$this->layers->animate($format, $delay, $loops);
|
||||
} else {
|
||||
$this->layers->merge();
|
||||
}
|
||||
$this->applyImageOptions($this->imagick, $options, $path);
|
||||
|
||||
// flatten only if image has multiple layers
|
||||
if ((!isset($options['flatten']) || $options['flatten'] === true) && count($this->layers) > 1) {
|
||||
$this->flatten();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->get('png');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function draw()
|
||||
{
|
||||
return new Drawer($this->imagick);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function effects()
|
||||
{
|
||||
return new Effects($this->imagick);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
try {
|
||||
$i = $this->imagick->getIteratorIndex();
|
||||
$this->imagick->rewind();
|
||||
$width = $this->imagick->getImageWidth();
|
||||
$height = $this->imagick->getImageHeight();
|
||||
$this->imagick->setIteratorIndex($i);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Could not get size', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return new Box($width, $height);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function applyMask(ImageInterface $mask)
|
||||
{
|
||||
if (!$mask instanceof self) {
|
||||
throw new InvalidArgumentException('Can only apply instances of Imagine\Imagick\Image as masks');
|
||||
}
|
||||
|
||||
$size = $this->getSize();
|
||||
$maskSize = $mask->getSize();
|
||||
|
||||
if ($size != $maskSize) {
|
||||
throw new InvalidArgumentException(sprintf('The given mask doesn\'t match current image\'s size, Current mask\'s dimensions are %s, while image\'s dimensions are %s', $maskSize, $size));
|
||||
}
|
||||
|
||||
$mask = $mask->mask();
|
||||
$mask->imagick->negateImage(true);
|
||||
|
||||
try {
|
||||
// remove transparent areas of the original from the mask
|
||||
$mask->imagick->compositeImage($this->imagick, \Imagick::COMPOSITE_DSTIN, 0, 0);
|
||||
$this->imagick->compositeImage($mask->imagick, \Imagick::COMPOSITE_COPYOPACITY, 0, 0);
|
||||
|
||||
$mask->imagick->clear();
|
||||
$mask->imagick->destroy();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Apply mask operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function mask()
|
||||
{
|
||||
$mask = $this->copy();
|
||||
|
||||
try {
|
||||
$mask->imagick->modulateImage(100, 0, 100);
|
||||
$mask->imagick->setImageMatte(false);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Mask operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return ImageInterface
|
||||
*/
|
||||
public function fill(FillInterface $fill)
|
||||
{
|
||||
try {
|
||||
if ($this->isLinearOpaque($fill)) {
|
||||
$this->applyFastLinear($fill);
|
||||
} else {
|
||||
$iterator = $this->imagick->getPixelIterator();
|
||||
|
||||
foreach ($iterator as $y => $pixels) {
|
||||
foreach ($pixels as $x => $pixel) {
|
||||
$color = $fill->getColor(new Point($x, $y));
|
||||
|
||||
$pixel->setColor((string) $color);
|
||||
$pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100);
|
||||
}
|
||||
|
||||
$iterator->syncIterator();
|
||||
}
|
||||
}
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Fill operation failed', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function histogram()
|
||||
{
|
||||
try {
|
||||
$pixels = $this->imagick->getImageHistogram();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Error while fetching histogram', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$image = $this;
|
||||
|
||||
return array_map(function (\ImagickPixel $pixel) use ($image) {
|
||||
return $image->pixelToColor($pixel);
|
||||
},$pixels);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getColorAt(PointInterface $point)
|
||||
{
|
||||
if (!$point->in($this->getSize())) {
|
||||
throw new RuntimeException(sprintf('Error getting color at point [%s,%s]. The point must be inside the image of size [%s,%s]', $point->getX(), $point->getY(), $this->getSize()->getWidth(), $this->getSize()->getHeight()));
|
||||
}
|
||||
|
||||
try {
|
||||
$pixel = $this->imagick->getImagePixelColor($point->getX(), $point->getY());
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Error while getting image pixel color', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this->pixelToColor($pixel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a color given a pixel, depending the Palette context
|
||||
*
|
||||
* Note : this method is public for PHP 5.3 compatibility
|
||||
*
|
||||
* @param \ImagickPixel $pixel
|
||||
*
|
||||
* @return ColorInterface
|
||||
*
|
||||
* @throws InvalidArgumentException In case a unknown color is requested
|
||||
*/
|
||||
public function pixelToColor(\ImagickPixel $pixel)
|
||||
{
|
||||
static $colorMapping = array(
|
||||
ColorInterface::COLOR_RED => \Imagick::COLOR_RED,
|
||||
ColorInterface::COLOR_GREEN => \Imagick::COLOR_GREEN,
|
||||
ColorInterface::COLOR_BLUE => \Imagick::COLOR_BLUE,
|
||||
ColorInterface::COLOR_CYAN => \Imagick::COLOR_CYAN,
|
||||
ColorInterface::COLOR_MAGENTA => \Imagick::COLOR_MAGENTA,
|
||||
ColorInterface::COLOR_YELLOW => \Imagick::COLOR_YELLOW,
|
||||
ColorInterface::COLOR_KEYLINE => \Imagick::COLOR_BLACK,
|
||||
// There is no gray component in \Imagick, let's use one of the RGB comp
|
||||
ColorInterface::COLOR_GRAY => \Imagick::COLOR_RED,
|
||||
);
|
||||
|
||||
$alpha = $this->palette->supportsAlpha() ? (int) round($pixel->getColorValue(\Imagick::COLOR_ALPHA) * 100) : null;
|
||||
$palette = $this->palette();
|
||||
|
||||
return $this->palette->color(array_map(function ($color) use ($palette, $pixel, $colorMapping) {
|
||||
if (!isset($colorMapping[$color])) {
|
||||
throw new InvalidArgumentException(sprintf('Color %s is not mapped in Imagick', $color));
|
||||
}
|
||||
$multiplier = 255;
|
||||
if ($palette->name() === PaletteInterface::PALETTE_CMYK) {
|
||||
$multiplier = 100;
|
||||
}
|
||||
|
||||
return $pixel->getColorValue($colorMapping[$color]) * $multiplier;
|
||||
}, $this->palette->pixelDefinition()), $alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function layers()
|
||||
{
|
||||
return $this->layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function usePalette(PaletteInterface $palette)
|
||||
{
|
||||
if (!isset(static::$colorspaceMapping[$palette->name()])) {
|
||||
throw new InvalidArgumentException(sprintf('The palette %s is not supported by Imagick driver', $palette->name()));
|
||||
}
|
||||
|
||||
if ($this->palette->name() === $palette->name()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (!static::$supportsColorspaceConversion) {
|
||||
throw new RuntimeException('Your version of Imagick does not support colorspace conversions.');
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
$hasICCProfile = (Boolean) $this->imagick->getImageProfile('icc');
|
||||
} catch (\ImagickException $e) {
|
||||
$hasICCProfile = false;
|
||||
}
|
||||
|
||||
if (!$hasICCProfile) {
|
||||
$this->profile($this->palette->profile());
|
||||
}
|
||||
|
||||
$this->profile($palette->profile());
|
||||
$this->setColorspace($palette);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to set colorspace', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function palette()
|
||||
{
|
||||
return $this->palette;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function profile(ProfileInterface $profile)
|
||||
{
|
||||
try {
|
||||
$this->imagick->profileImage('icc', $profile->data());
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException(sprintf('Unable to add profile %s to image', $profile->name()), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Flatten the image.
|
||||
*/
|
||||
private function flatten()
|
||||
{
|
||||
/**
|
||||
* @see https://github.com/mkoppanen/imagick/issues/45
|
||||
*/
|
||||
try {
|
||||
if (method_exists($this->imagick, 'mergeImageLayers') && defined('Imagick::LAYERMETHOD_UNDEFINED')) {
|
||||
$this->imagick = $this->imagick->mergeImageLayers(\Imagick::LAYERMETHOD_UNDEFINED);
|
||||
} elseif (method_exists($this->imagick, 'flattenImages')) {
|
||||
$this->imagick = $this->imagick->flattenImages();
|
||||
}
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Flatten operation failed', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Applies options before save or output
|
||||
*
|
||||
* @param \Imagick $image
|
||||
* @param array $options
|
||||
* @param string $path
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function applyImageOptions(\Imagick $image, array $options, $path)
|
||||
{
|
||||
if (isset($options['format'])) {
|
||||
$format = $options['format'];
|
||||
} elseif ('' !== $extension = pathinfo($path, \PATHINFO_EXTENSION)) {
|
||||
$format = $extension;
|
||||
} else {
|
||||
$format = pathinfo($image->getImageFilename(), \PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
$format = strtolower($format);
|
||||
|
||||
$options = $this->updateSaveOptions($options);
|
||||
|
||||
if (isset($options['jpeg_quality']) && in_array($format, array('jpeg', 'jpg', 'pjpeg'))) {
|
||||
$image->setImageCompressionQuality($options['jpeg_quality']);
|
||||
}
|
||||
|
||||
if ((isset($options['png_compression_level']) || isset($options['png_compression_filter'])) && $format === 'png') {
|
||||
// first digit: compression level (default: 7)
|
||||
if (isset($options['png_compression_level'])) {
|
||||
if ($options['png_compression_level'] < 0 || $options['png_compression_level'] > 9) {
|
||||
throw new InvalidArgumentException('png_compression_level option should be an integer from 0 to 9');
|
||||
}
|
||||
$compression = $options['png_compression_level'] * 10;
|
||||
} else {
|
||||
$compression = 70;
|
||||
}
|
||||
|
||||
// second digit: compression filter (default: 5)
|
||||
if (isset($options['png_compression_filter'])) {
|
||||
if ($options['png_compression_filter'] < 0 || $options['png_compression_filter'] > 9) {
|
||||
throw new InvalidArgumentException('png_compression_filter option should be an integer from 0 to 9');
|
||||
}
|
||||
$compression += $options['png_compression_filter'];
|
||||
} else {
|
||||
$compression += 5;
|
||||
}
|
||||
|
||||
$image->setImageCompressionQuality($compression);
|
||||
}
|
||||
|
||||
if (isset($options['resolution-units']) && isset($options['resolution-x']) && isset($options['resolution-y'])) {
|
||||
if ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERCENTIMETER) {
|
||||
$image->setImageUnits(\Imagick::RESOLUTION_PIXELSPERCENTIMETER);
|
||||
} elseif ($options['resolution-units'] == ImageInterface::RESOLUTION_PIXELSPERINCH) {
|
||||
$image->setImageUnits(\Imagick::RESOLUTION_PIXELSPERINCH);
|
||||
} else {
|
||||
throw new RuntimeException('Unsupported image unit format');
|
||||
}
|
||||
|
||||
$filter = ImageInterface::FILTER_UNDEFINED;
|
||||
if (!empty($options['resampling-filter'])) {
|
||||
$filter = $options['resampling-filter'];
|
||||
}
|
||||
|
||||
$image->setImageResolution($options['resolution-x'], $options['resolution-y']);
|
||||
$image->resampleImage($options['resolution-x'], $options['resolution-y'], $this->getFilter($filter), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets specifically formatted color string from Color instance
|
||||
*
|
||||
* @param ColorInterface $color
|
||||
*
|
||||
* @return \ImagickPixel
|
||||
*/
|
||||
private function getColor(ColorInterface $color)
|
||||
{
|
||||
$pixel = new \ImagickPixel((string) $color);
|
||||
$pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100);
|
||||
|
||||
return $pixel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether given $fill is linear and opaque
|
||||
*
|
||||
* @param FillInterface $fill
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
private function isLinearOpaque(FillInterface $fill)
|
||||
{
|
||||
return $fill instanceof Linear && $fill->getStart()->isOpaque() && $fill->getEnd()->isOpaque();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs optimized gradient fill for non-opaque linear gradients
|
||||
*
|
||||
* @param Linear $fill
|
||||
*/
|
||||
private function applyFastLinear(Linear $fill)
|
||||
{
|
||||
$gradient = new \Imagick();
|
||||
$size = $this->getSize();
|
||||
$color = sprintf('gradient:%s-%s', (string) $fill->getStart(), (string) $fill->getEnd());
|
||||
|
||||
if ($fill instanceof Horizontal) {
|
||||
$gradient->newPseudoImage($size->getHeight(), $size->getWidth(), $color);
|
||||
$gradient->rotateImage(new \ImagickPixel(), 90);
|
||||
} else {
|
||||
$gradient->newPseudoImage($size->getWidth(), $size->getHeight(), $color);
|
||||
}
|
||||
|
||||
$this->imagick->compositeImage($gradient, \Imagick::COMPOSITE_OVER, 0, 0);
|
||||
$gradient->clear();
|
||||
$gradient->destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal
|
||||
*
|
||||
* Get the mime type based on format.
|
||||
*
|
||||
* @param string $format
|
||||
*
|
||||
* @return string mime-type
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function getMimeType($format)
|
||||
{
|
||||
static $mimeTypes = array(
|
||||
'jpeg' => 'image/jpeg',
|
||||
'jpg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
'png' => 'image/png',
|
||||
'wbmp' => 'image/vnd.wap.wbmp',
|
||||
'xbm' => 'image/xbm',
|
||||
);
|
||||
|
||||
if (!isset($mimeTypes[$format])) {
|
||||
throw new RuntimeException(sprintf('Unsupported format given. Only %s are supported, %s given', implode(", ", array_keys($mimeTypes)), $format));
|
||||
}
|
||||
|
||||
return $mimeTypes[$format];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets colorspace and image type, assigns the palette.
|
||||
*
|
||||
* @param PaletteInterface $palette
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function setColorspace(PaletteInterface $palette)
|
||||
{
|
||||
static $typeMapping = array(
|
||||
// We use Matte variants to preserve alpha
|
||||
PaletteInterface::PALETTE_CMYK => \Imagick::IMGTYPE_TRUECOLORMATTE,
|
||||
PaletteInterface::PALETTE_RGB => \Imagick::IMGTYPE_TRUECOLORMATTE,
|
||||
PaletteInterface::PALETTE_GRAYSCALE => \Imagick::IMGTYPE_GRAYSCALEMATTE,
|
||||
);
|
||||
|
||||
if (!isset(static::$colorspaceMapping[$palette->name()])) {
|
||||
throw new InvalidArgumentException(sprintf('The palette %s is not supported by Imagick driver', $palette->name()));
|
||||
}
|
||||
|
||||
$this->imagick->setType($typeMapping[$palette->name()]);
|
||||
$this->imagick->setColorspace(static::$colorspaceMapping[$palette->name()]);
|
||||
$this->palette = $palette;
|
||||
}
|
||||
|
||||
/**
|
||||
* Older imagemagick versions does not support colorspace conversions.
|
||||
* Let's detect if it is supported.
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
private function detectColorspaceConversionSupport()
|
||||
{
|
||||
if (null !== static::$supportsColorspaceConversion) {
|
||||
return static::$supportsColorspaceConversion;
|
||||
}
|
||||
|
||||
return static::$supportsColorspaceConversion = method_exists('Imagick', 'setColorspace');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filter if it's supported.
|
||||
*
|
||||
* @param string $filter
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @throws InvalidArgumentException If the filter is unsupported.
|
||||
*/
|
||||
private function getFilter($filter = ImageInterface::FILTER_UNDEFINED)
|
||||
{
|
||||
static $supportedFilters = array(
|
||||
ImageInterface::FILTER_UNDEFINED => \Imagick::FILTER_UNDEFINED,
|
||||
ImageInterface::FILTER_BESSEL => \Imagick::FILTER_BESSEL,
|
||||
ImageInterface::FILTER_BLACKMAN => \Imagick::FILTER_BLACKMAN,
|
||||
ImageInterface::FILTER_BOX => \Imagick::FILTER_BOX,
|
||||
ImageInterface::FILTER_CATROM => \Imagick::FILTER_CATROM,
|
||||
ImageInterface::FILTER_CUBIC => \Imagick::FILTER_CUBIC,
|
||||
ImageInterface::FILTER_GAUSSIAN => \Imagick::FILTER_GAUSSIAN,
|
||||
ImageInterface::FILTER_HANNING => \Imagick::FILTER_HANNING,
|
||||
ImageInterface::FILTER_HAMMING => \Imagick::FILTER_HAMMING,
|
||||
ImageInterface::FILTER_HERMITE => \Imagick::FILTER_HERMITE,
|
||||
ImageInterface::FILTER_LANCZOS => \Imagick::FILTER_LANCZOS,
|
||||
ImageInterface::FILTER_MITCHELL => \Imagick::FILTER_MITCHELL,
|
||||
ImageInterface::FILTER_POINT => \Imagick::FILTER_POINT,
|
||||
ImageInterface::FILTER_QUADRATIC => \Imagick::FILTER_QUADRATIC,
|
||||
ImageInterface::FILTER_SINC => \Imagick::FILTER_SINC,
|
||||
ImageInterface::FILTER_TRIANGLE => \Imagick::FILTER_TRIANGLE
|
||||
);
|
||||
|
||||
if (!array_key_exists($filter, $supportedFilters)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The resampling filter "%s" is not supported by Imagick driver.',
|
||||
$filter
|
||||
));
|
||||
}
|
||||
|
||||
return $supportedFilters[$filter];
|
||||
}
|
||||
}
|
||||
176
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Imagine.php
Normal file
176
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Imagine.php
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Imagick;
|
||||
|
||||
use Imagine\Exception\NotSupportedException;
|
||||
use Imagine\Image\AbstractImagine;
|
||||
use Imagine\Image\BoxInterface;
|
||||
use Imagine\Image\Metadata\MetadataBag;
|
||||
use Imagine\Image\Palette\Color\ColorInterface;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Image\Palette\CMYK;
|
||||
use Imagine\Image\Palette\RGB;
|
||||
use Imagine\Image\Palette\Grayscale;
|
||||
|
||||
/**
|
||||
* Imagine implementation using the Imagick PHP extension
|
||||
*/
|
||||
final class Imagine extends AbstractImagine
|
||||
{
|
||||
/**
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (!class_exists('Imagick')) {
|
||||
throw new RuntimeException('Imagick not installed');
|
||||
}
|
||||
|
||||
if (version_compare('6.2.9', $this->getVersion(new \Imagick())) > 0) {
|
||||
throw new RuntimeException('ImageMagick version 6.2.9 or higher is required');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function open($path)
|
||||
{
|
||||
$path = $this->checkPath($path);
|
||||
|
||||
try {
|
||||
$imagick = new \Imagick($path);
|
||||
$image = new Image($imagick, $this->createPalette($imagick), $this->getMetadataReader()->readFile($path));
|
||||
} catch (\Exception $e) {
|
||||
throw new RuntimeException(sprintf('Unable to open image %s', $path), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function create(BoxInterface $size, ColorInterface $color = null)
|
||||
{
|
||||
$width = $size->getWidth();
|
||||
$height = $size->getHeight();
|
||||
|
||||
$palette = null !== $color ? $color->getPalette() : new RGB();
|
||||
$color = null !== $color ? $color : $palette->color('fff');
|
||||
|
||||
try {
|
||||
$pixel = new \ImagickPixel((string) $color);
|
||||
$pixel->setColorValue(\Imagick::COLOR_ALPHA, $color->getAlpha() / 100);
|
||||
|
||||
$imagick = new \Imagick();
|
||||
$imagick->newImage($width, $height, $pixel);
|
||||
$imagick->setImageMatte(true);
|
||||
$imagick->setImageBackgroundColor($pixel);
|
||||
|
||||
if (version_compare('6.3.1', $this->getVersion($imagick)) < 0) {
|
||||
$imagick->setImageOpacity($pixel->getColorValue(\Imagick::COLOR_ALPHA));
|
||||
}
|
||||
|
||||
$pixel->clear();
|
||||
$pixel->destroy();
|
||||
|
||||
return new Image($imagick, $palette, new MetadataBag());
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Could not create empty image', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load($string)
|
||||
{
|
||||
try {
|
||||
$imagick = new \Imagick();
|
||||
|
||||
$imagick->readImageBlob($string);
|
||||
$imagick->setImageMatte(true);
|
||||
|
||||
return new Image($imagick, $this->createPalette($imagick), $this->getMetadataReader()->readData($string));
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Could not load image from string', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($resource)
|
||||
{
|
||||
if (!is_resource($resource)) {
|
||||
throw new InvalidArgumentException('Variable does not contain a stream resource');
|
||||
}
|
||||
|
||||
try {
|
||||
$imagick = new \Imagick();
|
||||
$imagick->readImageFile($resource);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Could not read image from resource', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return new Image($imagick, $this->createPalette($imagick), $this->getMetadataReader()->readStream($resource));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function font($file, $size, ColorInterface $color)
|
||||
{
|
||||
return new Font(new \Imagick(), $file, $size, $color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the palette corresponding to an \Imagick resource colorspace
|
||||
*
|
||||
* @param \Imagick $imagick
|
||||
*
|
||||
* @return CMYK|Grayscale|RGB
|
||||
*
|
||||
* @throws NotSupportedException
|
||||
*/
|
||||
private function createPalette(\Imagick $imagick)
|
||||
{
|
||||
switch ($imagick->getImageColorspace()) {
|
||||
case \Imagick::COLORSPACE_RGB:
|
||||
case \Imagick::COLORSPACE_SRGB:
|
||||
return new RGB();
|
||||
case \Imagick::COLORSPACE_CMYK:
|
||||
return new CMYK();
|
||||
case \Imagick::COLORSPACE_GRAY:
|
||||
return new Grayscale();
|
||||
default:
|
||||
throw new NotSupportedException('Only RGB and CMYK colorspace are currently supported');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ImageMagick version
|
||||
*
|
||||
* @param \Imagick $imagick
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getVersion(\Imagick $imagick)
|
||||
{
|
||||
$v = $imagick->getVersion();
|
||||
list($version) = sscanf($v['versionString'], 'ImageMagick %s %04d-%02d-%02d %s %s');
|
||||
|
||||
return $version;
|
||||
}
|
||||
}
|
||||
271
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Layers.php
Normal file
271
rainloop/v/0.0.0/app/libraries/Imagine/Imagick/Layers.php
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Imagine package.
|
||||
*
|
||||
* (c) Bulat Shakirzyanov <mallluhuct@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Imagine\Imagick;
|
||||
|
||||
use Imagine\Image\AbstractLayers;
|
||||
use Imagine\Image\Metadata\MetadataBag;
|
||||
use Imagine\Exception\RuntimeException;
|
||||
use Imagine\Exception\OutOfBoundsException;
|
||||
use Imagine\Exception\InvalidArgumentException;
|
||||
use Imagine\Image\Palette\PaletteInterface;
|
||||
|
||||
class Layers extends AbstractLayers
|
||||
{
|
||||
/**
|
||||
* @var Image
|
||||
*/
|
||||
private $image;
|
||||
/**
|
||||
* @var \Imagick
|
||||
*/
|
||||
private $resource;
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
private $offset = 0;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $layers = array();
|
||||
|
||||
private $palette;
|
||||
|
||||
public function __construct(Image $image, PaletteInterface $palette, \Imagick $resource)
|
||||
{
|
||||
$this->image = $image;
|
||||
$this->resource = $resource;
|
||||
$this->palette = $palette;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function merge()
|
||||
{
|
||||
foreach ($this->layers as $offset => $image) {
|
||||
try {
|
||||
$this->resource->setIteratorIndex($offset);
|
||||
$this->resource->setImage($image->getImagick());
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to substitute layer', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function animate($format, $delay, $loops)
|
||||
{
|
||||
if ('gif' !== strtolower($format)) {
|
||||
throw new InvalidArgumentException('Animated picture is currently only supported on gif');
|
||||
}
|
||||
|
||||
if (!is_int($loops) || $loops < 0) {
|
||||
throw new InvalidArgumentException('Loops must be a positive integer.');
|
||||
}
|
||||
|
||||
if (null !== $delay && (!is_int($delay) || $delay < 0)) {
|
||||
throw new InvalidArgumentException('Delay must be either null or a positive integer.');
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($this as $offset => $layer) {
|
||||
$this->resource->setIteratorIndex($offset);
|
||||
$this->resource->setFormat($format);
|
||||
|
||||
if (null !== $delay) {
|
||||
$layer->getImagick()->setImageDelay($delay / 10);
|
||||
$layer->getImagick()->setImageTicksPerSecond(100);
|
||||
}
|
||||
$layer->getImagick()->setImageIterations($loops);
|
||||
|
||||
$this->resource->setImage($layer->getImagick());
|
||||
}
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to animate layers', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function coalesce()
|
||||
{
|
||||
try {
|
||||
$coalescedResource = $this->resource->coalesceImages();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to coalesce layers', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$count = $coalescedResource->getNumberImages();
|
||||
for ($offset = 0; $offset < $count; $offset++) {
|
||||
try {
|
||||
$coalescedResource->setIteratorIndex($offset);
|
||||
$this->layers[$offset] = new Image($coalescedResource->getImage(), $this->palette, new MetadataBag());
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to retrieve layer', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->extractAt($this->offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to extract layer at given offset
|
||||
*
|
||||
* @param integer $offset
|
||||
*
|
||||
* @return Image
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
private function extractAt($offset)
|
||||
{
|
||||
if (!isset($this->layers[$offset])) {
|
||||
try {
|
||||
$this->resource->setIteratorIndex($offset);
|
||||
$this->layers[$offset] = new Image($this->resource->getImage(), $this->palette, new MetadataBag());
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException(sprintf('Failed to extract layer %d', $offset), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->layers[$offset];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
++$this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->offset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return $this->offset < count($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
try {
|
||||
return $this->resource->getNumberImages();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Failed to count the number of layers', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return is_int($offset) && $offset >= 0 && $offset < count($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->extractAt($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetSet($offset, $image)
|
||||
{
|
||||
if (!$image instanceof Image) {
|
||||
throw new InvalidArgumentException('Only an Imagick Image can be used as layer');
|
||||
}
|
||||
|
||||
if (null === $offset) {
|
||||
$offset = count($this) - 1;
|
||||
} else {
|
||||
if (!is_int($offset)) {
|
||||
throw new InvalidArgumentException('Invalid offset for layer, it must be an integer');
|
||||
}
|
||||
|
||||
if (count($this) < $offset || 0 > $offset) {
|
||||
throw new OutOfBoundsException(sprintf('Invalid offset for layer, it must be a value between 0 and %d, %d given', count($this), $offset));
|
||||
}
|
||||
|
||||
if (isset($this[$offset])) {
|
||||
unset($this[$offset]);
|
||||
$offset = $offset - 1;
|
||||
}
|
||||
}
|
||||
|
||||
$frame = $image->getImagick();
|
||||
|
||||
try {
|
||||
if (count($this) > 0) {
|
||||
$this->resource->setIteratorIndex($offset);
|
||||
}
|
||||
$this->resource->addImage($frame);
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Unable to set the layer', $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$this->layers = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
try {
|
||||
$this->extractAt($offset);
|
||||
} catch (RuntimeException $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->resource->setIteratorIndex($offset);
|
||||
$this->resource->removeImage();
|
||||
} catch (\ImagickException $e) {
|
||||
throw new RuntimeException('Unable to remove layer', $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8324,6 +8324,83 @@ class Actions
|
|||
return $aValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Imagine\Image\AbstractImage $oImage
|
||||
* @param int $iOrientation
|
||||
*/
|
||||
private function rotateImageByOrientation(&$oImage, $iOrientation)
|
||||
{
|
||||
if (0 < $iOrientation)
|
||||
{
|
||||
switch ($iOrientation)
|
||||
{
|
||||
default:
|
||||
case 1:
|
||||
break;
|
||||
|
||||
case 2: // horizontal flip
|
||||
$oImage->flipHorizontally();
|
||||
break;
|
||||
|
||||
case 3: // 180 rotate left
|
||||
$oImage->rotate(180);
|
||||
break;
|
||||
|
||||
case 4: // vertical flip
|
||||
$oImage->flipVertically();
|
||||
break;
|
||||
|
||||
case 5: // vertical flip + 90 rotate right
|
||||
$oImage->flipVertically();
|
||||
$oImage->rotate(-90);
|
||||
break;
|
||||
|
||||
case 6: // 90 rotate right
|
||||
$oImage->rotate(-90);
|
||||
break;
|
||||
|
||||
case 7: // horizontal flip + 90 rotate right
|
||||
$oImage->flipHorizontally();
|
||||
$oImage->rotate(-90);
|
||||
break;
|
||||
|
||||
case 8: // 90 rotate left
|
||||
$oImage->rotate(90);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Imagine\Image\AbstractImage $oImage
|
||||
*/
|
||||
private function correctImageOrientation($oImage, $bDetectImageOrientation = true, $iThumbnailBoxSize = null)
|
||||
{
|
||||
$iOrientation = 1;
|
||||
if ($bDetectImageOrientation && \MailSo\Base\Utils::FunctionExistsAndEnabled('exif_read_data') &&
|
||||
\MailSo\Base\Utils::FunctionExistsAndEnabled('gd_info'))
|
||||
{
|
||||
$oMetadata = $oImage->metadata(new \Imagine\Image\Metadata\ExifMetadataReader());
|
||||
$iOrientation = isset($oMetadata['ifd0.Orientation']) &&
|
||||
is_numeric($oMetadata['ifd0.Orientation']) ? (int) $oMetadata['ifd0.Orientation'] : 1;
|
||||
}
|
||||
|
||||
if ($iThumbnailBoxSize && 0 < $iThumbnailBoxSize)
|
||||
{
|
||||
$oImage = $oImage->thumbnail(
|
||||
new \Imagine\Image\Box($iThumbnailBoxSize, $iThumbnailBoxSize),
|
||||
\Imagine\Image\ImageInterface::THUMBNAIL_OUTBOUND);
|
||||
|
||||
$this->rotateImageByOrientation($oImage, $iOrientation);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->rotateImageByOrientation($oImage, $iOrientation);
|
||||
}
|
||||
|
||||
return $oImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bDownload
|
||||
* @param bool $bThumbnail = false
|
||||
|
|
@ -8343,6 +8420,8 @@ class Actions
|
|||
$sFileNameIn = isset($aValues['FileName']) ? (string) $aValues['FileName'] : '';
|
||||
$sFileHashIn = isset($aValues['FileHash']) ? (string) $aValues['FileHash'] : '';
|
||||
|
||||
$bDetectImageOrientation = !!$this->Config()->Get('labs', 'detect_image_exif_orientation', true);
|
||||
|
||||
if (!empty($sFileHashIn))
|
||||
{
|
||||
$this->verifyCacheByKey($sRawKey);
|
||||
|
|
@ -8386,7 +8465,7 @@ class Actions
|
|||
|
||||
$self = $this;
|
||||
return $this->MailClient()->MessageMimeStream(
|
||||
function($rResource, $sContentType, $sFileName, $sMimeIndex = '') use ($self, $oAccount, $sRawKey, $sContentTypeIn, $sFileNameIn, $bDownload, $bThumbnail) {
|
||||
function($rResource, $sContentType, $sFileName, $sMimeIndex = '') use ($self, $oAccount, $sRawKey, $sContentTypeIn, $sFileNameIn, $bDownload, $bThumbnail, $bDetectImageOrientation) {
|
||||
if ($oAccount && \is_resource($rResource))
|
||||
{
|
||||
$sContentTypeOut = $sContentTypeIn;
|
||||
|
|
@ -8412,30 +8491,48 @@ class Actions
|
|||
$bDone = false;
|
||||
if ($bThumbnail && !$bDownload)
|
||||
{
|
||||
$sFileName = '';
|
||||
$rTempResource = \MailSo\Base\StreamWrappers\TempFile::CreateStream(
|
||||
\MailSo\Base\Utils::Md5Rand($sFileNameOut), $sFileName);
|
||||
|
||||
if (@\is_resource($rTempResource))
|
||||
{
|
||||
$bDone = true;
|
||||
|
||||
\MailSo\Base\Utils::MultipleStreamWriter($rResource, array($rTempResource));
|
||||
@\fclose($rTempResource);
|
||||
|
||||
try
|
||||
{
|
||||
$oThumb = new \PHPThumb\GD($sFileName);
|
||||
if ($oThumb)
|
||||
{
|
||||
$oThumb->adaptiveResize(60, 60)->show();
|
||||
}
|
||||
$oImagine = new \Imagine\Gd\Imagine();
|
||||
|
||||
$bDone = true;
|
||||
$oImage = $oImagine->load(\stream_get_contents($rResource));
|
||||
|
||||
$oImage = $this->correctImageOrientation($oImage, $bDetectImageOrientation, 60);
|
||||
|
||||
\header('Content-Disposition: inline; '.
|
||||
\trim(\MailSo\Base\Utils::EncodeHeaderUtf8AttributeValue('filename', $sFileNameOut.'_thumb60x60.png')), true);
|
||||
|
||||
$oImage->show('png');
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$self->Logger()->WriteExceptionShort($oException);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bDone && !$bDownload && $bDetectImageOrientation &&
|
||||
\in_array($sContentTypeOut, array('image/png', 'image/jpeg', 'image/jpg')) &&
|
||||
\MailSo\Base\Utils::FunctionExistsAndEnabled('gd_info'))
|
||||
{
|
||||
try
|
||||
{
|
||||
$oImagine = new \Imagine\Gd\Imagine();
|
||||
|
||||
$bDone = true;
|
||||
$oImage = $oImagine->load(\stream_get_contents($rResource));
|
||||
|
||||
$oImage = $this->correctImageOrientation($oImage, $bDetectImageOrientation);
|
||||
|
||||
\header('Content-Disposition: inline; '.
|
||||
\trim(\MailSo\Base\Utils::EncodeHeaderUtf8AttributeValue('filename', $sFileNameOut)), true);
|
||||
|
||||
$oImage->show($sContentTypeOut === 'image/png' ? 'png' : 'jpg');
|
||||
}
|
||||
catch (\Exception $oException)
|
||||
{
|
||||
$self->Logger()->WriteExceptionShort($oException);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bDone)
|
||||
|
|
|
|||
|
|
@ -352,6 +352,7 @@ Enables caching in the system'),
|
|||
'fast_cache_memcache_port' => array(11211),
|
||||
'fast_cache_memcache_expire' => array(43200),
|
||||
'use_local_proxy_for_external_images' => array(false),
|
||||
'detect_image_exif_orientation' => array(true),
|
||||
'cookie_default_path' => array(''),
|
||||
'startup_url' => array(''),
|
||||
'emogrifier' => array(true),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue