Skip to content

Commit

Permalink
Merge pull request #2573 from MGatner/image-withfile
Browse files Browse the repository at this point in the history
Image verification
  • Loading branch information
lonnieezell authored Feb 20, 2020
2 parents 6b93add + 7f347e0 commit 489c2bf
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 43 deletions.
15 changes: 15 additions & 0 deletions system/Images/Exceptions/ImageException.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@

class ImageException extends FrameworkException implements ExceptionInterface
{
public static function forMissingImage()
{
return new static(lang('Images.sourceImageRequired'));
}

public static function forFileNotSupported()
{
return new static(lang('Images.fileNotSupported'));
}

public static function forMissingAngle()
{
return new static(lang('Images.rotationAngleRequired'));
Expand All @@ -15,6 +25,11 @@ public static function forInvalidDirection(string $dir = null)
return new static(lang('Images.invalidDirection', [$dir]));
}

public static function forInvalidPath()
{
return new static(lang('Images.invalidPath'));
}

public static function forEXIFUnsupported()
{
return new static(lang('Images.exifNotSupported'));
Expand Down
83 changes: 64 additions & 19 deletions system/Images/Handlers/BaseHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ abstract class BaseHandler implements ImageHandlerInterface
*/
protected $image = null;

/**
* Whether the image file has been confirmed.
*
* @var bool
*/
protected $verified = false;

/**
* Image width.
*
Expand Down Expand Up @@ -158,6 +165,7 @@ public function withFile(string $path)
// Clear out the old resource so that
// it doesn't try to use a previous image
$this->resource = null;
$this->verified = false;

$this->image = new Image($path, true);

Expand All @@ -177,9 +185,9 @@ protected function ensureResource()
{
if ($this->resource === null)
{
$path = $this->image->getPathname();
$path = $this->image()->getPathname();
// if valid image type, make corresponding image resource
switch ($this->image->imageType)
switch ($this->image()->imageType)
{
case IMAGETYPE_GIF:
$this->resource = imagecreatefromgif($path);
Expand All @@ -206,6 +214,43 @@ public function getFile()
return $this->image;
}

/**
* Verifies that a file has been supplied and it is an image.
*
* @return Image The image instance
* @throws type ImageException
*/
protected function image(): ?Image
{
if ($this->verified)
{
return $this->image;
}

// Verify withFile has been called
if (empty($this->image))
{
throw ImageException::forMissingImage();
}

// Verify the loaded image is an Image instance
if (! $this->image instanceof Image)
{
throw ImageException::forInvalidPath();
}

// File::__construct has verified the file exists - make sure it is an image
if (! is_int($this->image->imageType))
{
throw ImageException::forFileNotSupported();
}

// Note that the image has been verified
$this->verified = true;

return $this->image;
}

//--------------------------------------------------------------------

/**
Expand Down Expand Up @@ -236,7 +281,7 @@ public function getResource()
public function resize(int $width, int $height, bool $maintainRatio = false, string $masterDim = 'auto')
{
// If the target width/height match the source, then we have nothing to do here.
if ($this->image->origWidth === $width && $this->image->origHeight === $height)
if ($this->image()->origWidth === $width && $this->image()->origHeight === $height)
{
return $this;
}
Expand Down Expand Up @@ -302,7 +347,7 @@ public function crop(int $width = null, int $height = null, int $x = null, int $
*/
public function convert(int $imageType)
{
$this->image->imageType = $imageType;
$this->image()->imageType = $imageType;
return $this;
}

Expand Down Expand Up @@ -359,8 +404,8 @@ public function rotate(float $angle)
*/
public function flatten(int $red = 255, int $green = 255, int $blue = 255)
{
$this->width = $this->image->origWidth;
$this->height = $this->image->origHeight;
$this->width = $this->image()->origWidth;
$this->height = $this->image()->origHeight;

return $this->_flatten();
}
Expand Down Expand Up @@ -538,11 +583,11 @@ public function getEXIF(string $key = null, bool $silent = false)
}

$exif = null; // default
switch ($this->image->imageType)
switch ($this->image()->imageType)
{
case IMAGETYPE_JPEG:
case IMAGETYPE_TIFF_II:
$exif = exif_read_data($this->image->getPathname());
$exif = exif_read_data($this->image()->getPathname());
if (! is_null($key) && is_array($exif))
{
$exif = $exif[$key] ?? false;
Expand Down Expand Up @@ -576,8 +621,8 @@ public function getEXIF(string $key = null, bool $silent = false)
*/
public function fit(int $width, int $height = null, string $position = 'center')
{
$origWidth = $this->image->origWidth;
$origHeight = $this->image->origHeight;
$origWidth = $this->image()->origWidth;
$origHeight = $this->image()->origHeight;

list($cropWidth, $cropHeight) = $this->calcAspectRatio($width, $height, $origWidth, $origHeight);

Expand Down Expand Up @@ -749,9 +794,9 @@ protected abstract function process(string $action);
*/
public function __call(string $name, array $args = [])
{
if (method_exists($this->image, $name))
if (method_exists($this->image(), $name))
{
return $this->image->$name(...$args);
return $this->image()->$name(...$args);
}
}

Expand All @@ -772,11 +817,11 @@ public function __call(string $name, array $args = [])
protected function reproportion()
{
if (($this->width === 0 && $this->height === 0) ||
$this->image->origWidth === 0 ||
$this->image->origHeight === 0 ||
$this->image()->origWidth === 0 ||
$this->image()->origHeight === 0 ||
( ! ctype_digit((string) $this->width) && ! ctype_digit((string) $this->height)) ||
! ctype_digit((string) $this->image->origWidth) ||
! ctype_digit((string) $this->image->origHeight)
! ctype_digit((string) $this->image()->origWidth) ||
! ctype_digit((string) $this->image()->origHeight)
)
{
return;
Expand All @@ -790,7 +835,7 @@ protected function reproportion()
{
if ($this->width > 0 && $this->height > 0)
{
$this->masterDim = ((($this->image->origHeight / $this->image->origWidth) - ($this->height / $this->width)) < 0) ? 'width' : 'height';
$this->masterDim = ((($this->image()->origHeight / $this->image()->origWidth) - ($this->height / $this->width)) < 0) ? 'width' : 'height';
}
else
{
Expand All @@ -805,11 +850,11 @@ protected function reproportion()

if ($this->masterDim === 'width')
{
$this->height = (int) ceil($this->width * $this->image->origHeight / $this->image->origWidth);
$this->height = (int) ceil($this->width * $this->image()->origHeight / $this->image()->origWidth);
}
else
{
$this->width = (int) ceil($this->image->origWidth * $this->height / $this->image->origHeight);
$this->width = (int) ceil($this->image()->origWidth * $this->height / $this->image()->origHeight);
}
}

Expand Down
30 changes: 15 additions & 15 deletions system/Images/Handlers/GDHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ public function _flip(string $direction)
{
$srcImg = $this->createImage();

$width = $this->image->origWidth;
$height = $this->image->origHeight;
$width = $this->image()->origWidth;
$height = $this->image()->origHeight;

if ($direction === 'horizontal')
{
Expand Down Expand Up @@ -254,8 +254,8 @@ public function _crop()
*/
protected function process(string $action)
{
$origWidth = $this->image->origWidth;
$origHeight = $this->image->origHeight;
$origWidth = $this->image()->origWidth;
$origHeight = $this->image()->origHeight;

if ($action === 'crop')
{
Expand All @@ -266,8 +266,8 @@ protected function process(string $action)
// Modify the "original" width/height to the new
// values so that methods that come after have the
// correct size to work with.
$this->image->origHeight = $this->height;
$this->image->origWidth = $this->width;
$this->image()->origHeight = $this->height;
$this->image()->origWidth = $this->width;
}

// Create the image handle
Expand All @@ -286,7 +286,7 @@ protected function process(string $action)

$dest = $create($this->width, $this->height);

if ($this->image->imageType === IMAGETYPE_PNG) // png we can actually preserve transparency
if ($this->image()->imageType === IMAGETYPE_PNG) // png we can actually preserve transparency
{
imagealphablending($dest, false);
imagesavealpha($dest, true);
Expand Down Expand Up @@ -318,9 +318,9 @@ protected function process(string $action)
*/
public function save(string $target = null, int $quality = 90): bool
{
$target = empty($target) ? $this->image->getPathname() : $target;
$target = empty($target) ? $this->image()->getPathname() : $target;

switch ($this->image->imageType)
switch ($this->image()->imageType)
{
case IMAGETYPE_GIF:
if (! function_exists('imagegif'))
Expand Down Expand Up @@ -389,12 +389,12 @@ protected function createImage(string $path = '', string $imageType = '')

if ($path === '')
{
$path = $this->image->getPathname();
$path = $this->image()->getPathname();
}

if ($imageType === '')
{
$imageType = $this->image->imageType;
$imageType = $this->image()->imageType;
}

switch ($imageType)
Expand Down Expand Up @@ -490,21 +490,21 @@ protected function _text(string $text, array $options = [])
if ($options['vAlign'] === 'middle')
{
// Don't apply padding when you're in the middle of the image.
$yAxis += ($this->image->origHeight / 2) + ($fontheight / 2) - $options['padding'];
$yAxis += ($this->image()->origHeight / 2) + ($fontheight / 2) - $options['padding'];
}
elseif ($options['vAlign'] === 'bottom')
{
$yAxis = ($this->image->origHeight - $fontheight - $options['shadowOffset'] - ($fontheight / 2)) - $yAxis;
$yAxis = ($this->image()->origHeight - $fontheight - $options['shadowOffset'] - ($fontheight / 2)) - $yAxis;
}

// Set horizontal alignment
if ($options['hAlign'] === 'right')
{
$xAxis += ($this->image->origWidth - ($fontwidth * strlen($text)) - $options['shadowOffset']) - (2 * $options['padding']);
$xAxis += ($this->image()->origWidth - ($fontwidth * strlen($text)) - $options['shadowOffset']) - (2 * $options['padding']);
}
elseif ($options['hAlign'] === 'center')
{
$xAxis += floor(($this->image->origWidth - ($fontwidth * strlen($text))) / 2);
$xAxis += floor(($this->image()->origWidth - ($fontwidth * strlen($text))) / 2);
}

$options['xAxis'] = $xAxis;
Expand Down
16 changes: 8 additions & 8 deletions system/Images/Handlers/ImageMagickHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public function __construct($config = null)
*/
public function _resize(bool $maintainRatio = false)
{
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
$destination = $this->getResourcePath();

$escape = '\\';
Expand All @@ -123,7 +123,7 @@ public function _resize(bool $maintainRatio = false)
*/
public function _crop()
{
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
$destination = $this->getResourcePath();

$action = ' -crop ' . $this->width . 'x' . $this->height . '+' . $this->xAxis . '+' . $this->yAxis . ' "' . $source . '" "' . $destination . '"';
Expand All @@ -148,7 +148,7 @@ protected function _rotate(int $angle)
{
$angle = '-rotate ' . $angle;

$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
$destination = $this->getResourcePath();

$action = ' ' . $angle . ' "' . $source . '" "' . $destination . '"';
Expand All @@ -174,7 +174,7 @@ public function _flatten(int $red = 255, int $green = 255, int $blue = 255)
{
$flatten = "-background RGB({$red},{$green},{$blue}) -flatten";

$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
$destination = $this->getResourcePath();

$action = ' ' . $flatten . ' "' . $source . '" "' . $destination . '"';
Expand All @@ -198,7 +198,7 @@ public function _flip(string $direction)
{
$angle = $direction === 'horizontal' ? '-flop' : '-flip';

$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
$destination = $this->getResourcePath();

$action = ' ' . $angle . ' "' . $source . '" "' . $destination . '"';
Expand Down Expand Up @@ -286,7 +286,7 @@ protected function process(string $action, int $quality = 100): array
*/
public function save(string $target = null, int $quality = 90): bool
{
$target = empty($target) ? $this->image : $target;
$target = empty($target) ? $this->image() : $target;

// If no new resource has been created, then we're
// simply copy the existing one.
Expand All @@ -295,7 +295,7 @@ public function save(string $target = null, int $quality = 90): bool
$name = basename($target);
$path = pathinfo($target, PATHINFO_DIRNAME);

return $this->image->copy($path, $name);
return $this->image()->copy($path, $name);
}

// Copy the file through ImageMagick so that it has
Expand Down Expand Up @@ -433,7 +433,7 @@ protected function _text(string $text, array $options = [])
// Text
$cmd .= " -annotate 0 '{$text}'";

$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
$source = ! empty($this->resource) ? $this->resource : $this->image()->getPathname();
$destination = $this->getResourcePath();

$cmd = " '{$source}' {$cmd} '{$destination}'";
Expand Down
6 changes: 5 additions & 1 deletion system/Images/Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ public function getProperties(bool $return = false)
{
$path = $this->getPathname();

$vals = getimagesize($path);
if (! $vals = getimagesize($path))
{
throw ImageException::forFileNotSupported();
}

$types = [
1 => 'gif',
2 => 'jpeg',
Expand Down
1 change: 1 addition & 0 deletions system/Language/en/Images.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
'gifNotSupported' => 'GIF images are often not supported due to licensing restrictions. You may have to use JPG or PNG images instead.',
'jpgNotSupported' => 'JPG images are not supported.',
'pngNotSupported' => 'PNG images are not supported.',
'fileNotSupported' => 'The supplied file is not a supported image type.',
'unsupportedImageCreate' => 'Your server does not support the GD function required to process this type of image.',
'jpgOrPngRequired' => 'The image resize protocol specified in your preferences only works with JPEG or PNG image types.',
'rotateUnsupported' => 'Image rotation does not appear to be supported by your server.',
Expand Down
Loading

0 comments on commit 489c2bf

Please sign in to comment.