First Local Commit - After Clean up.
Signed-off-by: Rick Hays <rhays@haysgang.com>
This commit is contained in:
42
system/Images/Exceptions/ImageException.php
Normal file
42
system/Images/Exceptions/ImageException.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php namespace CodeIgniter\Images\Exceptions;
|
||||
|
||||
use CodeIgniter\Exceptions\ExceptionInterface;
|
||||
use CodeIgniter\Exceptions\FrameworkException;
|
||||
|
||||
class ImageException extends FrameworkException implements ExceptionInterface
|
||||
{
|
||||
public static function forMissingAngle()
|
||||
{
|
||||
return new static(lang('Images.rotationAngleRequired'));
|
||||
}
|
||||
|
||||
public static function forInvalidDirection(string $dir = null)
|
||||
{
|
||||
return new static(lang('Images.invalidDirection', [$dir]));
|
||||
}
|
||||
|
||||
public static function forEXIFUnsupported()
|
||||
{
|
||||
return new static(lang('Images.exifNotSupported'));
|
||||
}
|
||||
|
||||
public static function forInvalidImageCreate(string $extra = null)
|
||||
{
|
||||
return new static(lang('Images.unsupportedImageCreate') . ' ' . $extra);
|
||||
}
|
||||
|
||||
public static function forSaveFailed()
|
||||
{
|
||||
return new static(lang('Images.saveFailed'));
|
||||
}
|
||||
|
||||
public static function forInvalidImageLibraryPath(string $path = null)
|
||||
{
|
||||
return new static(lang('Images.libPathInvalid', [$path]));
|
||||
}
|
||||
|
||||
public static function forImageProcessFailed()
|
||||
{
|
||||
return new static(lang('Images.imageProcessFailed'));
|
||||
}
|
||||
}
|
||||
842
system/Images/Handlers/BaseHandler.php
Normal file
842
system/Images/Handlers/BaseHandler.php
Normal file
@@ -0,0 +1,842 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Images\Handlers;
|
||||
|
||||
use CodeIgniter\Images\Exceptions\ImageException;
|
||||
use CodeIgniter\Images\Image;
|
||||
use CodeIgniter\Images\ImageHandlerInterface;
|
||||
|
||||
/**
|
||||
* Base image handling implementation
|
||||
*/
|
||||
abstract class BaseHandler implements ImageHandlerInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Configuration settings.
|
||||
*
|
||||
* @var \Config\Images
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The image/file instance
|
||||
*
|
||||
* @var \CodeIgniter\Images\Image
|
||||
*/
|
||||
protected $image = null;
|
||||
|
||||
/**
|
||||
* Image width.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $width = 0;
|
||||
|
||||
/**
|
||||
* Image height.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $height = 0;
|
||||
|
||||
/**
|
||||
* File permission mask.
|
||||
*
|
||||
* @var type
|
||||
*/
|
||||
protected $filePermissions = 0644;
|
||||
|
||||
/**
|
||||
* X-axis.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $xAxis = 0;
|
||||
|
||||
/**
|
||||
* Y-axis.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $yAxis = 0;
|
||||
|
||||
/**
|
||||
* Master dimensioning.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $masterDim = 'auto';
|
||||
|
||||
/**
|
||||
* Default options for text watermarking.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $textDefaults = [
|
||||
'fontPath' => null,
|
||||
'fontSize' => 16,
|
||||
'color' => 'ffffff',
|
||||
'opacity' => 1.0,
|
||||
'vAlign' => 'bottom',
|
||||
'hAlign' => 'center',
|
||||
'vOffset' => 0,
|
||||
'hOffset' => 0,
|
||||
'padding' => 0,
|
||||
'withShadow' => false,
|
||||
'shadowColor' => '000000',
|
||||
'shadowOffset' => 3,
|
||||
];
|
||||
|
||||
/**
|
||||
* Temporary image used by the different engines.
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
protected $resource;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param type $config
|
||||
*/
|
||||
public function __construct($config = null)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sets another image for this handler to work on.
|
||||
* Keeps us from needing to continually instantiate the handler.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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->image = new Image($path, true);
|
||||
|
||||
$this->image->getProperties(false);
|
||||
$this->width = $this->image->origWidth;
|
||||
$this->height = $this->image->origHeight;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Make the image resource object if needed
|
||||
*/
|
||||
protected function ensureResource()
|
||||
{
|
||||
if ($this->resource === null)
|
||||
{
|
||||
$path = $this->image->getPathname();
|
||||
// if valid image type, make corresponding image resource
|
||||
switch ($this->image->imageType)
|
||||
{
|
||||
case IMAGETYPE_GIF:
|
||||
$this->resource = imagecreatefromgif($path);
|
||||
break;
|
||||
case IMAGETYPE_JPEG:
|
||||
$this->resource = imagecreatefromjpeg($path);
|
||||
break;
|
||||
case IMAGETYPE_PNG:
|
||||
$this->resource = imagecreatefrompng($path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the image instance.
|
||||
*
|
||||
* @return \CodeIgniter\Images\Image
|
||||
*/
|
||||
public function getFile()
|
||||
{
|
||||
return $this->image;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the temporary image used during the image processing.
|
||||
* Good for extending the system or doing things this library
|
||||
* is not intended to do.
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
$this->ensureResource();
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Resize the image
|
||||
*
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @param boolean $maintainRatio If true, will get the closest match possible while keeping aspect ratio true.
|
||||
* @param string $masterDim
|
||||
*
|
||||
* @return BaseHandler
|
||||
*/
|
||||
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)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
|
||||
if ($maintainRatio)
|
||||
{
|
||||
$this->masterDim = $masterDim;
|
||||
$this->reproportion();
|
||||
}
|
||||
|
||||
return $this->_resize($maintainRatio);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Crops the image to the desired height and width. If one of the height/width values
|
||||
* is not provided, that value will be set the appropriate value based on offsets and
|
||||
* image dimensions.
|
||||
*
|
||||
* @param integer|null $width
|
||||
* @param integer|null $height
|
||||
* @param integer|null $x X-axis coord to start cropping from the left of image
|
||||
* @param integer|null $y Y-axis coord to start cropping from the top of image
|
||||
* @param boolean $maintainRatio
|
||||
* @param string $masterDim
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function crop(int $width = null, int $height = null, int $x = null, int $y = null, bool $maintainRatio = false, string $masterDim = 'auto')
|
||||
{
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
$this->xAxis = $x;
|
||||
$this->yAxis = $y;
|
||||
|
||||
if ($maintainRatio)
|
||||
{
|
||||
$this->masterDim = $masterDim;
|
||||
$this->reproportion();
|
||||
}
|
||||
|
||||
$result = $this->_crop();
|
||||
|
||||
$this->xAxis = null;
|
||||
$this->yAxis = null;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Changes the stored image type to indicate the new file format to use when saving.
|
||||
* Does not touch the actual resource.
|
||||
*
|
||||
* @param integer|null $imageType A PHP imageType constant, e.g. https://www.php.net/manual/en/function.image-type-to-mime-type.php
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function convert(int $imageType)
|
||||
{
|
||||
$this->image->imageType = $imageType;
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Rotates the image on the current canvas.
|
||||
*
|
||||
* @param float $angle
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function rotate(float $angle)
|
||||
{
|
||||
// Allowed rotation values
|
||||
$degs = [
|
||||
90,
|
||||
180,
|
||||
270,
|
||||
];
|
||||
|
||||
if ($angle === '' || ! in_array($angle, $degs))
|
||||
{
|
||||
throw ImageException::forMissingAngle();
|
||||
}
|
||||
|
||||
// cast angle as an int, for our use
|
||||
$angle = (int) $angle;
|
||||
|
||||
// Reassign the width and height
|
||||
if ($angle === 90 || $angle === 270)
|
||||
{
|
||||
$temp = $this->height;
|
||||
$this->width = $this->height;
|
||||
$this->height = $temp;
|
||||
}
|
||||
|
||||
// Call the Handler-specific version.
|
||||
$this->_rotate($angle);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Flattens transparencies, default white background
|
||||
*
|
||||
* @param integer $red
|
||||
* @param integer $green
|
||||
* @param integer $blue
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function flatten(int $red = 255, int $green = 255, int $blue = 255)
|
||||
{
|
||||
$this->width = $this->image->origWidth;
|
||||
$this->height = $this->image->origHeight;
|
||||
|
||||
return $this->_flatten();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handler-specific method to flattening an image's transparencies.
|
||||
*
|
||||
* @param integer $red
|
||||
* @param integer $green
|
||||
* @param integer $blue
|
||||
*
|
||||
* @return mixed
|
||||
* @internal param int $angle
|
||||
*/
|
||||
protected abstract function _flatten(int $red = 255, int $green = 255, int $blue = 255);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handler-specific method to handle rotating an image in 90 degree increments.
|
||||
*
|
||||
* @param integer $angle
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected abstract function _rotate(int $angle);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Flips an image either horizontally or vertically.
|
||||
*
|
||||
* @param string $dir Either 'vertical' or 'horizontal'
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function flip(string $dir = 'vertical')
|
||||
{
|
||||
$dir = strtolower($dir);
|
||||
|
||||
if ($dir !== 'vertical' && $dir !== 'horizontal')
|
||||
{
|
||||
throw ImageException::forInvalidDirection($dir);
|
||||
}
|
||||
|
||||
return $this->_flip($dir);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handler-specific method to handle flipping an image along its
|
||||
* horizontal or vertical axis.
|
||||
*
|
||||
* @param string $direction
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected abstract function _flip(string $direction);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Overlays a string of text over the image.
|
||||
*
|
||||
* Valid options:
|
||||
*
|
||||
* - color Text Color (hex number)
|
||||
* - shadowColor Color of the shadow (hex number)
|
||||
* - hAlign Horizontal alignment: left, center, right
|
||||
* - vAlign Vertical alignment: top, middle, bottom
|
||||
* - hOffset
|
||||
* - vOffset
|
||||
* - fontPath
|
||||
* - fontSize
|
||||
* - shadowOffset
|
||||
*
|
||||
* @param string $text
|
||||
* @param array $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function text(string $text, array $options = [])
|
||||
{
|
||||
$options = array_merge($this->textDefaults, $options);
|
||||
$options['color'] = trim($options['color'], '# ');
|
||||
$options['shadowColor'] = trim($options['shadowColor'], '# ');
|
||||
|
||||
$this->_text($text, $options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handler-specific method for overlaying text on an image.
|
||||
*
|
||||
* @param string $text
|
||||
* @param array $options
|
||||
*/
|
||||
protected abstract function _text(string $text, array $options = []);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Reads the EXIF information from the image and modifies the orientation
|
||||
* so that displays correctly in the browser. This is especially an issue
|
||||
* with images taken by smartphones who always store the image up-right,
|
||||
* but set the orientation flag to display it correctly.
|
||||
*
|
||||
* @param boolean $silent If true, will ignore exceptions when PHP doesn't support EXIF.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function reorient(bool $silent = false)
|
||||
{
|
||||
$orientation = $this->getEXIF('Orientation', $silent);
|
||||
|
||||
switch ($orientation)
|
||||
{
|
||||
case 2:
|
||||
return $this->flip('horizontal');
|
||||
break;
|
||||
case 3:
|
||||
return $this->rotate(180);
|
||||
break;
|
||||
case 4:
|
||||
return $this->rotate(180)
|
||||
->flip('horizontal');
|
||||
break;
|
||||
case 5:
|
||||
return $this->rotate(270)
|
||||
->flip('horizontal');
|
||||
break;
|
||||
case 6:
|
||||
return $this->rotate(270);
|
||||
break;
|
||||
case 7:
|
||||
return $this->rotate(90)
|
||||
->flip('horizontal');
|
||||
break;
|
||||
case 8:
|
||||
return $this->rotate(90);
|
||||
break;
|
||||
default:
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Retrieve the EXIF information from the image, if possible. Returns
|
||||
* an array of the information, or null if nothing can be found.
|
||||
*
|
||||
* EXIF data is only supported fr JPEG & TIFF formats.
|
||||
*
|
||||
* @param string|null $key If specified, will only return this piece of EXIF data.
|
||||
*
|
||||
* @param boolean $silent If true, will not throw our own exceptions.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getEXIF(string $key = null, bool $silent = false)
|
||||
{
|
||||
if (! function_exists('exif_read_data'))
|
||||
{
|
||||
if ($silent)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$exif = null; // default
|
||||
switch ($this->image->imageType)
|
||||
{
|
||||
case IMAGETYPE_JPEG:
|
||||
case IMAGETYPE_TIFF_II:
|
||||
$exif = exif_read_data($this->image->getPathname());
|
||||
if (! is_null($key) && is_array($exif))
|
||||
{
|
||||
$exif = $exif[$key] ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
return $exif;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Combine cropping and resizing into a single command.
|
||||
*
|
||||
* Supported positions:
|
||||
* - top-left
|
||||
* - top
|
||||
* - top-right
|
||||
* - left
|
||||
* - center
|
||||
* - right
|
||||
* - bottom-left
|
||||
* - bottom
|
||||
* - bottom-right
|
||||
*
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @param string $position
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function fit(int $width, int $height = null, string $position = 'center')
|
||||
{
|
||||
$origWidth = $this->image->origWidth;
|
||||
$origHeight = $this->image->origHeight;
|
||||
|
||||
list($cropWidth, $cropHeight) = $this->calcAspectRatio($width, $height, $origWidth, $origHeight);
|
||||
|
||||
if (is_null($height))
|
||||
{
|
||||
$height = ceil(($width / $cropWidth) * $cropHeight);
|
||||
}
|
||||
|
||||
list($x, $y) = $this->calcCropCoords($cropWidth, $cropHeight, $origWidth, $origHeight, $position);
|
||||
|
||||
return $this->crop($cropWidth, $cropHeight, $x, $y)
|
||||
->resize($width, $height);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Calculate image aspect ratio.
|
||||
*
|
||||
* @param $width
|
||||
* @param null $height
|
||||
* @param $origWidth
|
||||
* @param $origHeight
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function calcAspectRatio($width, $height = null, $origWidth, $origHeight): array
|
||||
{
|
||||
// If $height is null, then we have it easy.
|
||||
// Calc based on full image size and be done.
|
||||
if (is_null($height))
|
||||
{
|
||||
$height = ($width / $origWidth) * $origHeight;
|
||||
|
||||
return [
|
||||
$width,
|
||||
(int) $height,
|
||||
];
|
||||
}
|
||||
|
||||
$xRatio = $width / $origWidth;
|
||||
$yRatio = $height / $origHeight;
|
||||
|
||||
if ($xRatio > $yRatio)
|
||||
{
|
||||
return [
|
||||
$origWidth,
|
||||
(int) ($origWidth * $height / $width),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
(int) ($origHeight * $width / $height),
|
||||
$origHeight,
|
||||
];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Based on the position, will determine the correct x/y coords to
|
||||
* crop the desired portion from the image.
|
||||
*
|
||||
* @param $width
|
||||
* @param $height
|
||||
* @param $origWidth
|
||||
* @param $origHeight
|
||||
* @param $position
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function calcCropCoords($width, $height, $origWidth, $origHeight, $position): array
|
||||
{
|
||||
$position = strtolower($position);
|
||||
$x = $y = 0;
|
||||
|
||||
switch ($position)
|
||||
{
|
||||
case 'top-left':
|
||||
$x = 0;
|
||||
$y = 0;
|
||||
break;
|
||||
case 'top':
|
||||
$x = floor(($origWidth - $width) / 2);
|
||||
$y = 0;
|
||||
break;
|
||||
case 'top-right':
|
||||
$x = $origWidth - $width;
|
||||
$y = 0;
|
||||
break;
|
||||
case 'left':
|
||||
$x = 0;
|
||||
$y = floor(($origHeight - $height) / 2);
|
||||
break;
|
||||
case 'center':
|
||||
$x = floor(($origWidth - $width) / 2);
|
||||
$y = floor(($origHeight - $height) / 2);
|
||||
break;
|
||||
case 'right':
|
||||
$x = ($origWidth - $width);
|
||||
$y = floor(($origHeight - $height) / 2);
|
||||
break;
|
||||
case 'bottom-left':
|
||||
$x = 0;
|
||||
$y = $origHeight - $height;
|
||||
break;
|
||||
case 'bottom':
|
||||
$x = floor(($origWidth - $width) / 2);
|
||||
$y = $origHeight - $height;
|
||||
break;
|
||||
case 'bottom-right':
|
||||
$x = ($origWidth - $width);
|
||||
$y = $origHeight - $height;
|
||||
break;
|
||||
}
|
||||
|
||||
return [
|
||||
$x,
|
||||
$y,
|
||||
];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the version of the image library in use.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public abstract function getVersion();
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Saves any changes that have been made to file.
|
||||
*
|
||||
* Example:
|
||||
* $image->resize(100, 200, true)
|
||||
* ->save($target);
|
||||
*
|
||||
* @param string $target
|
||||
* @param integer $quality
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public abstract function save(string $target = null, int $quality = 90);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Does the driver-specific processing of the image.
|
||||
*
|
||||
* @param string $action
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected abstract function process(string $action);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Provide access to the Image class' methods if they don't exist
|
||||
* on the handler itself.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $args
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call(string $name, array $args = [])
|
||||
{
|
||||
if (method_exists($this->image, $name))
|
||||
{
|
||||
return $this->image->$name(...$args);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Re-proportion Image Width/Height
|
||||
*
|
||||
* When creating thumbs, the desired width/height
|
||||
* can end up warping the image due to an incorrect
|
||||
* ratio between the full-sized image and the thumb.
|
||||
*
|
||||
* This function lets us re-proportion the width/height
|
||||
* if users choose to maintain the aspect ratio when resizing.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function reproportion()
|
||||
{
|
||||
if (($this->width === 0 && $this->height === 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)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanitize
|
||||
$this->width = (int) $this->width;
|
||||
$this->height = (int) $this->height;
|
||||
|
||||
if ($this->masterDim !== 'width' && $this->masterDim !== 'height')
|
||||
{
|
||||
if ($this->width > 0 && $this->height > 0)
|
||||
{
|
||||
$this->masterDim = ((($this->image->origHeight / $this->image->origWidth) - ($this->height / $this->width)) < 0) ? 'width' : 'height';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->masterDim = ($this->height === 0) ? 'width' : 'height';
|
||||
}
|
||||
}
|
||||
elseif (($this->masterDim === 'width' && $this->width === 0) || ($this->masterDim === 'height' && $this->height === 0)
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->masterDim === 'width')
|
||||
{
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return image width.
|
||||
*
|
||||
* accessor for testing; not part of interface
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getWidth()
|
||||
{
|
||||
return ($this->resource !== null) ? $this->_getWidth() : $this->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return image height.
|
||||
*
|
||||
* accessor for testing; not part of interface
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public function getHeight()
|
||||
{
|
||||
return ($this->resource !== null) ? $this->_getHeight() : $this->height;
|
||||
}
|
||||
|
||||
}
|
||||
591
system/Images/Handlers/GDHandler.php
Normal file
591
system/Images/Handlers/GDHandler.php
Normal file
@@ -0,0 +1,591 @@
|
||||
<?php
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Images\Handlers;
|
||||
|
||||
use CodeIgniter\Images\Exceptions\ImageException;
|
||||
|
||||
/**
|
||||
* Image handler for GD package
|
||||
*/
|
||||
class GDHandler extends BaseHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param type $config
|
||||
* @throws type
|
||||
*/
|
||||
public function __construct($config = null)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
// We should never see this, so can't test it
|
||||
// @codeCoverageIgnoreStart
|
||||
if (! extension_loaded('gd'))
|
||||
{
|
||||
throw ImageException::forMissingExtension('GD');
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handles the rotation of an image resource.
|
||||
* Doesn't save the image, but replaces the current resource.
|
||||
*
|
||||
* @param integer $angle
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function _rotate(int $angle): bool
|
||||
{
|
||||
// Create the image handle
|
||||
$srcImg = $this->createImage();
|
||||
|
||||
// Set the background color
|
||||
// This won't work with transparent PNG files so we are
|
||||
// going to have to figure out how to determine the color
|
||||
// of the alpha channel in a future release.
|
||||
|
||||
$white = imagecolorallocate($srcImg, 255, 255, 255);
|
||||
|
||||
// Rotate it!
|
||||
$destImg = imagerotate($srcImg, $angle, $white);
|
||||
|
||||
// Kill the file handles
|
||||
imagedestroy($srcImg);
|
||||
|
||||
$this->resource = $destImg;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Flattens transparencies
|
||||
*
|
||||
* @param integer $red
|
||||
* @param integer $green
|
||||
* @param integer $blue
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function _flatten(int $red = 255, int $green = 255, int $blue = 255)
|
||||
{
|
||||
$srcImg = $this->createImage();
|
||||
|
||||
if (function_exists('imagecreatetruecolor'))
|
||||
{
|
||||
$create = 'imagecreatetruecolor';
|
||||
$copy = 'imagecopyresampled';
|
||||
}
|
||||
else
|
||||
{
|
||||
$create = 'imagecreate';
|
||||
$copy = 'imagecopyresized';
|
||||
}
|
||||
$dest = $create($this->width, $this->height);
|
||||
|
||||
$matte = imagecolorallocate($dest, $red, $green, $blue);
|
||||
|
||||
imagefilledrectangle($dest, 0, 0, $this->width, $this->height, $matte);
|
||||
imagecopy($dest, $srcImg, 0, 0, 0, 0, $this->width, $this->height);
|
||||
|
||||
// Kill the file handles
|
||||
imagedestroy($srcImg);
|
||||
|
||||
$this->resource = $dest;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Flips an image along it's vertical or horizontal axis.
|
||||
*
|
||||
* @param string $direction
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function _flip(string $direction)
|
||||
{
|
||||
$srcImg = $this->createImage();
|
||||
|
||||
$width = $this->image->origWidth;
|
||||
$height = $this->image->origHeight;
|
||||
|
||||
if ($direction === 'horizontal')
|
||||
{
|
||||
for ($i = 0; $i < $height; $i ++)
|
||||
{
|
||||
$left = 0;
|
||||
$right = $width - 1;
|
||||
|
||||
while ($left < $right)
|
||||
{
|
||||
$cl = imagecolorat($srcImg, $left, $i);
|
||||
$cr = imagecolorat($srcImg, $right, $i);
|
||||
|
||||
imagesetpixel($srcImg, $left, $i, $cr);
|
||||
imagesetpixel($srcImg, $right, $i, $cl);
|
||||
|
||||
$left ++;
|
||||
$right --;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ($i = 0; $i < $width; $i ++)
|
||||
{
|
||||
$top = 0;
|
||||
$bottom = $height - 1;
|
||||
|
||||
while ($top < $bottom)
|
||||
{
|
||||
$ct = imagecolorat($srcImg, $i, $top);
|
||||
$cb = imagecolorat($srcImg, $i, $bottom);
|
||||
|
||||
imagesetpixel($srcImg, $i, $top, $cb);
|
||||
imagesetpixel($srcImg, $i, $bottom, $ct);
|
||||
|
||||
$top ++;
|
||||
$bottom --;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->resource = $srcImg;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get GD version
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getVersion()
|
||||
{
|
||||
if (function_exists('gd_info'))
|
||||
{
|
||||
$gd_version = @gd_info();
|
||||
|
||||
return preg_replace('/\D/', '', $gd_version['GD Version']);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Resizes the image.
|
||||
*
|
||||
* @return boolean|\CodeIgniter\Images\Handlers\GDHandler
|
||||
*/
|
||||
public function _resize()
|
||||
{
|
||||
return $this->process('resize');
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Crops the image.
|
||||
*
|
||||
* @return boolean|\CodeIgniter\Images\Handlers\GDHandler
|
||||
*/
|
||||
public function _crop()
|
||||
{
|
||||
return $this->process('crop');
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handles all of the grunt work of resizing, etc.
|
||||
*
|
||||
* @param string $action
|
||||
*
|
||||
* @return $this|bool
|
||||
*/
|
||||
protected function process(string $action)
|
||||
{
|
||||
$origWidth = $this->image->origWidth;
|
||||
$origHeight = $this->image->origHeight;
|
||||
|
||||
if ($action === 'crop')
|
||||
{
|
||||
// Reassign the source width/height if cropping
|
||||
$origWidth = $this->width;
|
||||
$origHeight = $this->height;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Create the image handle
|
||||
$src = $this->createImage();
|
||||
|
||||
if (function_exists('imagecreatetruecolor'))
|
||||
{
|
||||
$create = 'imagecreatetruecolor';
|
||||
$copy = 'imagecopyresampled';
|
||||
}
|
||||
else
|
||||
{
|
||||
$create = 'imagecreate';
|
||||
$copy = 'imagecopyresized';
|
||||
}
|
||||
|
||||
$dest = $create($this->width, $this->height);
|
||||
|
||||
if ($this->image->imageType === IMAGETYPE_PNG) // png we can actually preserve transparency
|
||||
{
|
||||
imagealphablending($dest, false);
|
||||
imagesavealpha($dest, true);
|
||||
}
|
||||
|
||||
$copy($dest, $src, 0, 0, $this->xAxis, $this->yAxis, $this->width, $this->height, $origWidth, $origHeight);
|
||||
|
||||
imagedestroy($src);
|
||||
$this->resource = $dest;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Saves any changes that have been made to file. If no new filename is
|
||||
* provided, the existing image is overwritten, otherwise a copy of the
|
||||
* file is made at $target.
|
||||
*
|
||||
* Example:
|
||||
* $image->resize(100, 200, true)
|
||||
* ->save();
|
||||
*
|
||||
* @param string|null $target
|
||||
* @param integer $quality
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function save(string $target = null, int $quality = 90): bool
|
||||
{
|
||||
$target = empty($target) ? $this->image->getPathname() : $target;
|
||||
|
||||
switch ($this->image->imageType)
|
||||
{
|
||||
case IMAGETYPE_GIF:
|
||||
if (! function_exists('imagegif'))
|
||||
{
|
||||
throw ImageException::forInvalidImageCreate(lang('images.gifNotSupported'));
|
||||
}
|
||||
|
||||
if (! @imagegif($this->resource, $target))
|
||||
{
|
||||
throw ImageException::forSaveFailed();
|
||||
}
|
||||
break;
|
||||
case IMAGETYPE_JPEG:
|
||||
if (! function_exists('imagejpeg'))
|
||||
{
|
||||
throw ImageException::forInvalidImageCreate(lang('images.jpgNotSupported'));
|
||||
}
|
||||
|
||||
if (! @imagejpeg($this->resource, $target, $quality))
|
||||
{
|
||||
throw ImageException::forSaveFailed();
|
||||
}
|
||||
break;
|
||||
case IMAGETYPE_PNG:
|
||||
if (! function_exists('imagepng'))
|
||||
{
|
||||
throw ImageException::forInvalidImageCreate(lang('images.pngNotSupported'));
|
||||
}
|
||||
|
||||
if (! @imagepng($this->resource, $target))
|
||||
{
|
||||
throw ImageException::forSaveFailed();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw ImageException::forInvalidImageCreate();
|
||||
break;
|
||||
}
|
||||
|
||||
imagedestroy($this->resource);
|
||||
|
||||
chmod($target, $this->filePermissions);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create Image Resource
|
||||
*
|
||||
* This simply creates an image resource handle
|
||||
* based on the type of image being processed
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $imageType
|
||||
*
|
||||
* @return resource|boolean
|
||||
*/
|
||||
protected function createImage(string $path = '', string $imageType = '')
|
||||
{
|
||||
if ($this->resource !== null)
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
if ($path === '')
|
||||
{
|
||||
$path = $this->image->getPathname();
|
||||
}
|
||||
|
||||
if ($imageType === '')
|
||||
{
|
||||
$imageType = $this->image->imageType;
|
||||
}
|
||||
|
||||
switch ($imageType)
|
||||
{
|
||||
case IMAGETYPE_GIF:
|
||||
if (! function_exists('imagecreatefromgif'))
|
||||
{
|
||||
throw ImageException::forInvalidImageCreate(lang('images.gifNotSupported'));
|
||||
}
|
||||
|
||||
return imagecreatefromgif($path);
|
||||
case IMAGETYPE_JPEG:
|
||||
if (! function_exists('imagecreatefromjpeg'))
|
||||
{
|
||||
throw ImageException::forInvalidImageCreate(lang('images.jpgNotSupported'));
|
||||
}
|
||||
|
||||
return imagecreatefromjpeg($path);
|
||||
case IMAGETYPE_PNG:
|
||||
if (! function_exists('imagecreatefrompng'))
|
||||
{
|
||||
throw ImageException::forInvalidImageCreate(lang('images.pngNotSupported'));
|
||||
}
|
||||
|
||||
return imagecreatefrompng($path);
|
||||
default:
|
||||
throw ImageException::forInvalidImageCreate('Ima');
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add text overlay to an image.
|
||||
*
|
||||
* @param string $text
|
||||
* @param array $options
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _text(string $text, array $options = [])
|
||||
{
|
||||
// Reverse the vertical offset
|
||||
// When the image is positioned at the bottom
|
||||
// we don't want the vertical offset to push it
|
||||
// further down. We want the reverse, so we'll
|
||||
// invert the offset. Note: The horizontal
|
||||
// offset flips itself automatically
|
||||
|
||||
if ($options['vAlign'] === 'bottom')
|
||||
{
|
||||
$options['vOffset'] = $options['vOffset'] * -1;
|
||||
}
|
||||
|
||||
if ($options['hAlign'] === 'right')
|
||||
{
|
||||
$options['hOffset'] = $options['hOffset'] * -1;
|
||||
}
|
||||
|
||||
// Set font width and height
|
||||
// These are calculated differently depending on
|
||||
// whether we are using the true type font or not
|
||||
if (! empty($options['fontPath']))
|
||||
{
|
||||
if (function_exists('imagettfbbox'))
|
||||
{
|
||||
$temp = imagettfbbox($options['fontSize'], 0, $options['fontPath'], $text);
|
||||
$temp = $temp[2] - $temp[0];
|
||||
|
||||
$fontwidth = $temp / strlen($text);
|
||||
}
|
||||
else
|
||||
{
|
||||
$fontwidth = $options['fontSize'] - ($options['fontSize'] / 4);
|
||||
}
|
||||
|
||||
$fontheight = $options['fontSize'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$fontwidth = imagefontwidth($options['fontSize']);
|
||||
$fontheight = imagefontheight($options['fontSize']);
|
||||
}
|
||||
|
||||
$options['fontheight'] = $fontheight;
|
||||
$options['fontwidth'] = $fontwidth;
|
||||
|
||||
// Set base X and Y axis values
|
||||
$xAxis = $options['hOffset'] + $options['padding'];
|
||||
$yAxis = $options['vOffset'] + $options['padding'];
|
||||
|
||||
// Set vertical alignment
|
||||
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'];
|
||||
}
|
||||
elseif ($options['vAlign'] === 'bottom')
|
||||
{
|
||||
$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']);
|
||||
}
|
||||
elseif ($options['hAlign'] === 'center')
|
||||
{
|
||||
$xAxis += floor(($this->image->origWidth - ($fontwidth * strlen($text))) / 2);
|
||||
}
|
||||
|
||||
$options['xAxis'] = $xAxis;
|
||||
$options['yAxis'] = $yAxis;
|
||||
|
||||
if ($options['withShadow'])
|
||||
{
|
||||
// Offset from text
|
||||
$options['xShadow'] = $xAxis + $options['shadowOffset'];
|
||||
$options['yShadow'] = $yAxis + $options['shadowOffset'];
|
||||
|
||||
$this->textOverlay($text, $options, true);
|
||||
}
|
||||
|
||||
$this->textOverlay($text, $options, false);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handler-specific method for overlaying text on an image.
|
||||
*
|
||||
* @param string $text
|
||||
* @param array $options
|
||||
* @param boolean $isShadow Whether we are drawing the dropshadow or actual text
|
||||
*/
|
||||
protected function textOverlay(string $text, array $options = [], bool $isShadow = false)
|
||||
{
|
||||
$src = $this->createImage();
|
||||
|
||||
/* Set RGB values for shadow
|
||||
*
|
||||
* Get the rest of the string and split it into 2-length
|
||||
* hex values:
|
||||
*/
|
||||
$opacity = ($options['opacity'] * 127);
|
||||
|
||||
// Allow opacity to be applied to the text
|
||||
imagealphablending($src, true);
|
||||
|
||||
$color = $isShadow ? $options['shadowColor'] : $options['color'];
|
||||
$color = str_split(substr($color, 0, 6), 2);
|
||||
$color = imagecolorclosestalpha($src, hexdec($color[0]), hexdec($color[1]), hexdec($color[2]), $opacity);
|
||||
|
||||
$xAxis = $isShadow ? $options['xShadow'] : $options['xAxis'];
|
||||
$yAxis = $isShadow ? $options['yShadow'] : $options['yAxis'];
|
||||
|
||||
// Add the shadow to the source image
|
||||
if (! empty($options['fontPath']))
|
||||
{
|
||||
// We have to add fontheight because imagettftext locates the bottom left corner, not top-left corner.
|
||||
imagettftext($src, $options['fontSize'], 0, $xAxis, $yAxis + $options['fontheight'], $color, $options['fontPath'], $text);
|
||||
}
|
||||
else
|
||||
{
|
||||
imagestring($src, $options['fontSize'], $xAxis, $yAxis, $text, $color);
|
||||
}
|
||||
|
||||
$this->resource = $src;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return image width.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function _getWidth()
|
||||
{
|
||||
return imagesx($this->resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return image height.
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function _getHeight()
|
||||
{
|
||||
return imagesy($this->resource);
|
||||
}
|
||||
|
||||
}
|
||||
466
system/Images/Handlers/ImageMagickHandler.php
Normal file
466
system/Images/Handlers/ImageMagickHandler.php
Normal file
@@ -0,0 +1,466 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Images\Handlers;
|
||||
|
||||
use CodeIgniter\Images\Exceptions\ImageException;
|
||||
|
||||
/**
|
||||
* Class ImageMagickHandler
|
||||
*
|
||||
* To make this library as compatible as possible with the broadest
|
||||
* number of installations, we do not use the Imagick extension,
|
||||
* but simply use the command line version.
|
||||
*
|
||||
* hmm - the width & height accessors at the end use the imagick extension.
|
||||
*
|
||||
* FIXME - This needs conversion & unit testing, to use the imagick extension
|
||||
*
|
||||
* @package CodeIgniter\Images\Handlers
|
||||
*/
|
||||
class ImageMagickHandler extends BaseHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* Stores image resource in memory.
|
||||
*
|
||||
* @var
|
||||
*/
|
||||
protected $resource;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param type $config
|
||||
* @throws type
|
||||
*/
|
||||
public function __construct($config = null)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
// We should never see this, so can't test it
|
||||
// @codeCoverageIgnoreStart
|
||||
if (! (extension_loaded('imagick') || class_exists('Imagick')))
|
||||
{
|
||||
throw ImageException::forMissingExtension('IMAGICK');
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handles the actual resizing of the image.
|
||||
*
|
||||
* @param boolean $maintainRatio
|
||||
*
|
||||
* @return ImageMagickHandler
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function _resize(bool $maintainRatio = false)
|
||||
{
|
||||
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
|
||||
$destination = $this->getResourcePath();
|
||||
|
||||
$escape = '\\';
|
||||
if (stripos(PHP_OS, 'WIN') === 0)
|
||||
{
|
||||
$escape = '';
|
||||
}
|
||||
|
||||
$action = $maintainRatio === true ? ' -resize ' . $this->width . 'x' . $this->height . ' "' . $source . '" "' . $destination . '"' : ' -resize ' . $this->width . 'x' . $this->height . "{$escape}! \"" . $source . '" "' . $destination . '"';
|
||||
|
||||
$this->process($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Crops the image.
|
||||
*
|
||||
* @return boolean|\CodeIgniter\Images\Handlers\ImageMagickHandler
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function _crop()
|
||||
{
|
||||
$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 . '"';
|
||||
|
||||
$this->process($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handles the rotation of an image resource.
|
||||
* Doesn't save the image, but replaces the current resource.
|
||||
*
|
||||
* @param integer $angle
|
||||
*
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function _rotate(int $angle)
|
||||
{
|
||||
$angle = '-rotate ' . $angle;
|
||||
|
||||
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
|
||||
$destination = $this->getResourcePath();
|
||||
|
||||
$action = ' ' . $angle . ' "' . $source . '" "' . $destination . '"';
|
||||
|
||||
$this->process($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Flattens transparencies, default white background
|
||||
*
|
||||
* @param integer $red
|
||||
* @param integer $green
|
||||
* @param integer $blue
|
||||
*
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
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();
|
||||
$destination = $this->getResourcePath();
|
||||
|
||||
$action = ' ' . $flatten . ' "' . $source . '" "' . $destination . '"';
|
||||
|
||||
$this->process($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Flips an image along it's vertical or horizontal axis.
|
||||
*
|
||||
* @param string $direction
|
||||
*
|
||||
* @return $this
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function _flip(string $direction)
|
||||
{
|
||||
$angle = $direction === 'horizontal' ? '-flop' : '-flip';
|
||||
|
||||
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
|
||||
$destination = $this->getResourcePath();
|
||||
|
||||
$action = ' ' . $angle . ' "' . $source . '" "' . $destination . '"';
|
||||
|
||||
$this->process($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get driver version
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getVersion(): string
|
||||
{
|
||||
$result = $this->process('-version');
|
||||
|
||||
// The first line has the version in it...
|
||||
preg_match('/(ImageMagick\s[\S]+)/', $result[0], $matches);
|
||||
|
||||
return str_replace('ImageMagick ', '', $matches[0]);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handles all of the grunt work of resizing, etc.
|
||||
*
|
||||
* @param string $action
|
||||
* @param integer $quality
|
||||
*
|
||||
* @return array Lines of output from shell command
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function process(string $action, int $quality = 100): array
|
||||
{
|
||||
// Do we have a vaild library path?
|
||||
if (empty($this->config->libraryPath))
|
||||
{
|
||||
throw ImageException::forInvalidImageLibraryPath($this->config->libraryPath);
|
||||
}
|
||||
|
||||
if (! preg_match('/convert$/i', $this->config->libraryPath))
|
||||
{
|
||||
$this->config->libraryPath = rtrim($this->config->libraryPath, '/') . '/convert';
|
||||
}
|
||||
|
||||
$cmd = $this->config->libraryPath;
|
||||
$cmd .= $action === '-version' ? ' ' . $action : ' -quality ' . $quality . ' ' . $action;
|
||||
|
||||
$retval = 1;
|
||||
// exec() might be disabled
|
||||
if (function_usable('exec'))
|
||||
{
|
||||
@exec($cmd, $output, $retval);
|
||||
}
|
||||
|
||||
// Did it work?
|
||||
if ($retval > 0)
|
||||
{
|
||||
throw ImageException::forImageProcessFailed();
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Saves any changes that have been made to file. If no new filename is
|
||||
* provided, the existing image is overwritten, otherwise a copy of the
|
||||
* file is made at $target.
|
||||
*
|
||||
* Example:
|
||||
* $image->resize(100, 200, true)
|
||||
* ->save();
|
||||
*
|
||||
* @param string|null $target
|
||||
* @param integer $quality
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function save(string $target = null, int $quality = 90): bool
|
||||
{
|
||||
$target = empty($target) ? $this->image : $target;
|
||||
|
||||
// If no new resource has been created, then we're
|
||||
// simply copy the existing one.
|
||||
if (empty($this->resource))
|
||||
{
|
||||
$name = basename($target);
|
||||
$path = pathinfo($target, PATHINFO_DIRNAME);
|
||||
|
||||
return $this->image->copy($path, $name);
|
||||
}
|
||||
|
||||
// Copy the file through ImageMagick so that it has
|
||||
// a chance to convert file format.
|
||||
$action = '"' . $this->resource . '" "' . $target . '"';
|
||||
|
||||
$result = $this->process($action, $quality);
|
||||
|
||||
unlink($this->resource);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get Image Resource
|
||||
*
|
||||
* This simply creates an image resource handle
|
||||
* based on the type of image being processed.
|
||||
* Since ImageMagick is used on the cli, we need to
|
||||
* ensure we have a temporary file on the server
|
||||
* that we can use.
|
||||
*
|
||||
* To ensure we can use all features, like transparency,
|
||||
* during the process, we'll use a PNG as the temp file type.
|
||||
*
|
||||
* @return resource|boolean
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getResourcePath()
|
||||
{
|
||||
if (! is_null($this->resource))
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
$this->resource = WRITEPATH . 'cache/' . time() . '_' . bin2hex(random_bytes(10)) . '.png';
|
||||
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Handler-specific method for overlaying text on an image.
|
||||
*
|
||||
* @param string $text
|
||||
* @param array $options
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function _text(string $text, array $options = [])
|
||||
{
|
||||
$cmd = '';
|
||||
|
||||
// Reverse the vertical offset
|
||||
// When the image is positioned at the bottom
|
||||
// we don't want the vertical offset to push it
|
||||
// further down. We want the reverse, so we'll
|
||||
// invert the offset. Note: The horizontal
|
||||
// offset flips itself automatically
|
||||
if ($options['vAlign'] === 'bottom')
|
||||
{
|
||||
$options['vOffset'] = $options['vOffset'] * -1;
|
||||
}
|
||||
|
||||
if ($options['hAlign'] === 'right')
|
||||
{
|
||||
$options['hOffset'] = $options['hOffset'] * -1;
|
||||
}
|
||||
|
||||
// Font
|
||||
if (! empty($options['fontPath']))
|
||||
{
|
||||
$cmd .= " -font '{$options['fontPath']}'";
|
||||
}
|
||||
|
||||
if (isset($options['hAlign']) && isset($options['vAlign']))
|
||||
{
|
||||
switch ($options['hAlign'])
|
||||
{
|
||||
case 'left':
|
||||
$xAxis = $options['hOffset'] + $options['padding'];
|
||||
$yAxis = $options['vOffset'] + $options['padding'];
|
||||
$gravity = $options['vAlign'] === 'top' ? 'NorthWest' : 'West';
|
||||
if ($options['vAlign'] === 'bottom')
|
||||
{
|
||||
$gravity = 'SouthWest';
|
||||
$yAxis = $options['vOffset'] - $options['padding'];
|
||||
}
|
||||
break;
|
||||
case 'center':
|
||||
$xAxis = $options['hOffset'] + $options['padding'];
|
||||
$yAxis = $options['vOffset'] + $options['padding'];
|
||||
$gravity = $options['vAlign'] === 'top' ? 'North' : 'Center';
|
||||
if ($options['vAlign'] === 'bottom')
|
||||
{
|
||||
$yAxis = $options['vOffset'] - $options['padding'];
|
||||
$gravity = 'South';
|
||||
}
|
||||
break;
|
||||
case 'right':
|
||||
$xAxis = $options['hOffset'] - $options['padding'];
|
||||
$yAxis = $options['vOffset'] + $options['padding'];
|
||||
$gravity = $options['vAlign'] === 'top' ? 'NorthEast' : 'East';
|
||||
if ($options['vAlign'] === 'bottom')
|
||||
{
|
||||
$gravity = 'SouthEast';
|
||||
$yAxis = $options['vOffset'] - $options['padding'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$xAxis = $xAxis >= 0 ? '+' . $xAxis : $xAxis;
|
||||
$yAxis = $yAxis >= 0 ? '+' . $yAxis : $yAxis;
|
||||
|
||||
$cmd .= " -gravity {$gravity} -geometry {$xAxis}{$yAxis}";
|
||||
}
|
||||
|
||||
// Color
|
||||
if (isset($options['color']))
|
||||
{
|
||||
list($r, $g, $b) = sscanf("#{$options['color']}", '#%02x%02x%02x');
|
||||
|
||||
$cmd .= " -fill 'rgba({$r},{$g},{$b},{$options['opacity']})'";
|
||||
}
|
||||
|
||||
// Font Size - use points....
|
||||
if (isset($options['fontSize']))
|
||||
{
|
||||
$cmd .= " -pointsize {$options['fontSize']}";
|
||||
}
|
||||
|
||||
// Text
|
||||
$cmd .= " -annotate 0 '{$text}'";
|
||||
|
||||
$source = ! empty($this->resource) ? $this->resource : $this->image->getPathname();
|
||||
$destination = $this->getResourcePath();
|
||||
|
||||
$cmd = " '{$source}' {$cmd} '{$destination}'";
|
||||
|
||||
$this->process($cmd);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return the width of an image.
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public function _getWidth()
|
||||
{
|
||||
return imagesx($this->resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the height of an image.
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public function _getHeight()
|
||||
{
|
||||
return imagesy($this->resource);
|
||||
}
|
||||
|
||||
}
|
||||
170
system/Images/Image.php
Normal file
170
system/Images/Image.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Images;
|
||||
|
||||
use CodeIgniter\Files\File;
|
||||
use CodeIgniter\Images\Exceptions\ImageException;
|
||||
|
||||
/**
|
||||
* Encapsulation of an Image file
|
||||
*/
|
||||
class Image extends File
|
||||
{
|
||||
|
||||
/**
|
||||
* The original image width in pixels.
|
||||
*
|
||||
* @var
|
||||
*/
|
||||
public $origWidth;
|
||||
|
||||
/**
|
||||
* The original image height in pixels.
|
||||
*
|
||||
* @var
|
||||
*/
|
||||
public $origHeight;
|
||||
|
||||
/**
|
||||
* The image type constant.
|
||||
*
|
||||
* @see http://php.net/manual/en/image.constants.php
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $imageType;
|
||||
|
||||
/**
|
||||
* attributes string with size info:
|
||||
* 'height="100" width="200"'
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $sizeStr;
|
||||
|
||||
/**
|
||||
* The image's mime type, i.e. image/jpeg
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mime;
|
||||
|
||||
/**
|
||||
* Makes a copy of itself to the new location. If no filename is provided
|
||||
* it will use the existing filename.
|
||||
*
|
||||
* @param string $targetPath The directory to store the file in
|
||||
* @param string|null $targetName The new name of the copied file.
|
||||
* @param integer $perms File permissions to be applied after copy.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function copy(string $targetPath, string $targetName = null, int $perms = 0644): bool
|
||||
{
|
||||
$targetPath = rtrim($targetPath, '/ ') . '/';
|
||||
|
||||
$targetName = is_null($targetName) ? $this->getFilename() : $targetName;
|
||||
|
||||
if (empty($targetName))
|
||||
{
|
||||
throw ImageException::forInvalidFile($targetName);
|
||||
}
|
||||
|
||||
if (! is_dir($targetPath))
|
||||
{
|
||||
mkdir($targetName, 0755, true);
|
||||
}
|
||||
|
||||
if (! copy($this->getPathname(), "{$targetPath}{$targetName}"))
|
||||
{
|
||||
throw ImageException::forCopyError($targetPath);
|
||||
}
|
||||
|
||||
chmod("{$targetPath}/{$targetName}", $perms);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get image properties
|
||||
*
|
||||
* A helper function that gets info about the file
|
||||
*
|
||||
* @param boolean $return
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getProperties(bool $return = false)
|
||||
{
|
||||
$path = $this->getPathname();
|
||||
|
||||
$vals = getimagesize($path);
|
||||
$types = [
|
||||
1 => 'gif',
|
||||
2 => 'jpeg',
|
||||
3 => 'png',
|
||||
];
|
||||
|
||||
$mime = 'image/' . ($types[$vals[2]] ?? 'jpg');
|
||||
|
||||
if ($return === true)
|
||||
{
|
||||
return [
|
||||
'width' => $vals[0],
|
||||
'height' => $vals[1],
|
||||
'image_type' => $vals[2],
|
||||
'size_str' => $vals[3],
|
||||
'mime_type' => $mime,
|
||||
];
|
||||
}
|
||||
|
||||
$this->origWidth = $vals[0];
|
||||
$this->origHeight = $vals[1];
|
||||
$this->imageType = $vals[2];
|
||||
$this->sizeStr = $vals[3];
|
||||
$this->mime = $mime;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
207
system/Images/ImageHandlerInterface.php
Normal file
207
system/Images/ImageHandlerInterface.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Images;
|
||||
|
||||
/**
|
||||
* Expected behavior of an Image handler
|
||||
*/
|
||||
interface ImageHandlerInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Resize the image
|
||||
*
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @param boolean $maintainRatio If true, will get the closest match possible while keeping aspect ratio true.
|
||||
* @param string $masterDim
|
||||
*/
|
||||
public function resize(int $width, int $height, bool $maintainRatio = false, string $masterDim = 'auto');
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Crops the image to the desired height and width. If one of the height/width values
|
||||
* is not provided, that value will be set the appropriate value based on offsets and
|
||||
* image dimensions.
|
||||
*
|
||||
* @param integer|null $width
|
||||
* @param integer|null $height
|
||||
* @param integer|null $x X-axis coord to start cropping from the left of image
|
||||
* @param integer|null $y Y-axis coord to start cropping from the top of image
|
||||
* @param boolean $maintainRatio
|
||||
* @param string $masterDim
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function crop(int $width = null, int $height = null, int $x = null, int $y = null, bool $maintainRatio = false, string $masterDim = 'auto');
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Changes the stored image type to indicate the new file format to use when saving.
|
||||
* Does not touch the actual resource.
|
||||
*
|
||||
* @param integer|null $imageType A PHP imagetype constant, e.g. https://www.php.net/manual/en/function.image-type-to-mime-type.php
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function convert(int $imageType);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Rotates the image on the current canvas.
|
||||
*
|
||||
* @param float $angle
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function rotate(float $angle);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Flattens transparencies, default white background
|
||||
*
|
||||
* @param integer $red
|
||||
* @param integer $green
|
||||
* @param integer $blue
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function flatten(int $red = 255, int $green = 255, int $blue = 255);
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Reads the EXIF information from the image and modifies the orientation
|
||||
* so that displays correctly in the browser.
|
||||
*
|
||||
* @return ImageHandlerInterface
|
||||
*/
|
||||
public function reorient();
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Retrieve the EXIF information from the image, if possible. Returns
|
||||
* an array of the information, or null if nothing can be found.
|
||||
*
|
||||
* @param string|null $key If specified, will only return this piece of EXIF data.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getEXIF(string $key = null);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Flip an image horizontally or vertically
|
||||
*
|
||||
* @param string $dir Direction to flip, either 'vertical' or 'horizontal'
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function flip(string $dir = 'vertical');
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Combine cropping and resizing into a single command.
|
||||
*
|
||||
* Supported positions:
|
||||
* - top-left
|
||||
* - top
|
||||
* - top-right
|
||||
* - left
|
||||
* - center
|
||||
* - right
|
||||
* - bottom-left
|
||||
* - bottom
|
||||
* - bottom-right
|
||||
*
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @param string $position
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function fit(int $width, int $height, string $position);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Overlays a string of text over the image.
|
||||
*
|
||||
* Valid options:
|
||||
*
|
||||
* - color Text Color (hex number)
|
||||
* - shadowColor Color of the shadow (hex number)
|
||||
* - hAlign Horizontal alignment: left, center, right
|
||||
* - vAlign Vertical alignment: top, middle, bottom
|
||||
* - hOffset
|
||||
* - vOffset
|
||||
* - fontPath
|
||||
* - fontSize
|
||||
* - shadowOffset
|
||||
*
|
||||
* @param string $text
|
||||
* @param array $options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function text(string $text, array $options = []);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Saves any changes that have been made to file.
|
||||
*
|
||||
* Example:
|
||||
* $image->resize(100, 200, true)
|
||||
* ->save($target);
|
||||
*
|
||||
* @param string $target
|
||||
* @param integer $quality
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function save(string $target = null, int $quality = 90);
|
||||
}
|
||||
Reference in New Issue
Block a user