Image.php

Created Diff never expires
53 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
550 lines
75 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
573 lines
<?php
<?php
/**
/**
* @brief Image Class
* @brief Image Class
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @package Invision Community
* @since 19 Feb 2013
* @since 19 Feb 2013
*/
*/


namespace IPS;
namespace IPS;


/* To prevent PHP errors (extending class does not exist) revealing path */
/* To prevent PHP errors (extending class does not exist) revealing path */


use InvalidArgumentException;
use InvalidArgumentException;
use IPS\Image\Gd;
use IPS\Image\Gd;
use IPS\Image\Imagemagick;
use IPS\Image\Imagemagick;
use LogicException;
use LogicException;
use function defined;
use function defined;
use function file_put_contents;
use function file_put_contents;
use function function_exists;
use function function_exists;
use function in_array;
use function in_array;
use function strlen;
use function strlen;
use function substr;
use function substr;


if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
{
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
exit;
}
}


/**
/**
* Image Class
* Image Class
*/
*/
abstract class Image
abstract class Image
{
{
/**
/**
* @brief Image Extensions
* @brief Image Extensions
*/
*/
public static array $imageExtensions = array( 'gif', 'jpeg', 'jpe', 'jpg', 'png' );
public static array $imageExtensions = array( 'gif', 'jpeg', 'jpe', 'jpg', 'png' );
/**
/**
* @brief Image Mime Types
* @brief Image Mime Types
*/
*/
public static array $imageMimes = array( 'image/gif', 'image/jpeg', 'image/pjpeg', 'image/png', 'image/webp', 'image/avif' );
public static array $imageMimes = array( 'image/gif', 'image/jpeg', 'image/pjpeg', 'image/png', 'image/webp', 'image/avif' );
/**
/**
* @brief Allow EXIF processing
* @brief Allow EXIF processing
*/
*/
public static bool $exifEnabled = TRUE;
public static bool $exifEnabled = TRUE;
/**
/**
* Determine if EXIF extraction is supported
* Determine if EXIF extraction is supported
*
*
* @return bool
* @return bool
*/
*/
public static function exifSupported(): bool
public static function exifSupported(): bool
{
{
return function_exists( 'exif_read_data' ) and static::$exifEnabled;
return function_exists( 'exif_read_data' ) and static::$exifEnabled;
}
}
/**
/**
* @brief Has the image been automatically rotated?
* @brief Has the image been automatically rotated?
*/
*/
public bool $hasBeenRotated = FALSE;
public bool $hasBeenRotated = FALSE;


/**
/**
* Create Object
* Create Object
*
*
* @param string $contents Contents
* @param string $contents Contents
* @param bool $checkRotation Check image to correct rotation
* @param bool $checkRotation Check image to correct rotation
* @return Imagemagick|Gd|Image
* @return Imagemagick|Gd|Image
* @throws InvalidArgumentException
* @throws InvalidArgumentException
* @link https://en.wikipedia.org/wiki/List_of_file_signatures
* @link https://en.wikipedia.org/wiki/List_of_file_signatures
*/
*/
public static function create( string $contents, bool $checkRotation=TRUE ): Imagemagick|Image|Gd
public static function create( string $contents, bool $checkRotation=TRUE ): Imagemagick|Image|Gd
{
{
/* Work out the type */
/* Work out the type */
$imageType = NULL;
$imageType = NULL;
$signatures = array(
$signatures = array(
'gif' => array(
'gif' => array(
'47' . '49' . '46' . '38' . '37' . '61',
'47' . '49' . '46' . '38' . '37' . '61',
'47' . '49' . '46' . '38' . '39' . '61'
'47' . '49' . '46' . '38' . '39' . '61'
),
),
'jpeg' => array(
'jpeg' => array(
'ff' . 'd8' . 'ff'
'ff' . 'd8' . 'ff'
),
),
'png' => array(
'png' => array(
'89' . '50' . '4e' . '47' . '0d' . '0a' . '1a' . '0a'
'89' . '50' . '4e' . '47' . '0d' . '0a' . '1a' . '0a'
),
),
);
);


$bytesNeeded = max( array_merge( array_map( 'strlen', array_map( 'hex2bin', array_merge( $signatures['gif'], $signatures['jpeg'], $signatures['png'] ) ) ), array( 12 ) ) );
$bytesNeeded = max( array_merge( array_map( 'strlen', array_map( 'hex2bin', array_merge( $signatures['gif'], $signatures['jpeg'], $signatures['png'] ) ) ), array( 12 ) ) );
$fileHeader = substr( $contents, 0, $bytesNeeded );
$fileHeader = substr( $contents, 0, $bytesNeeded );


/* Try webp first since it's special: RIFF, 4 bytes for size, WEBP: */
/* Try webp first since it's special: RIFF, 4 bytes for size, WEBP: */
if ( bin2hex( substr( $fileHeader, 0, 4 ) ) === '52' . '49' . '46' . '46' AND bin2hex( substr( $fileHeader, 8, 4 ) ) === '57' . '45' . '42' . '50' )
if ( bin2hex( substr( $fileHeader, 0, 4 ) ) === '52' . '49' . '46' . '46' AND bin2hex( substr( $fileHeader, 8, 4 ) ) === '57' . '45' . '42' . '50' )
{
{
$imageType = 'webp';
$imageType = 'webp';
}
}


/* AVIF has 3 bytes of 00, then another byte that varies, and then ftypavif */
/* AVIF has 3 bytes of 00, then another byte that varies, and then ftypavif */
if( bin2hex( substr( $fileHeader, 0, 3 ) ) === '00' . '00' . '00' AND bin2hex( substr( $fileHeader, 4, 8 ) ) === '66' . '74' . '79' . '70' . '61' . '76' . '69' . '66' )
if( bin2hex( substr( $fileHeader, 0, 3 ) ) === '00' . '00' . '00' AND bin2hex( substr( $fileHeader, 4, 8 ) ) === '66' . '74' . '79' . '70' . '61' . '76' . '69' . '66' )
{
{
$imageType = 'avif';
$imageType = 'avif';
}
}


/* If it's not webp, try the rest of the image types */
/* If it's not webp, try the rest of the image types */
if( !$imageType )
if( !$imageType )
{
{
foreach ( $signatures as $type => $_signatures )
foreach ( $signatures as $type => $_signatures )
{
{
foreach ( $_signatures as $signature )
foreach ( $_signatures as $signature )
{
{
if ( bin2hex( substr( $fileHeader, 0, strlen( hex2bin( $signature ) ) ) ) === $signature )
if ( bin2hex( substr( $fileHeader, 0, strlen( hex2bin( $signature ) ) ) ) === $signature )
{
{
$imageType = $type;
$imageType = $type;
break 2;
break 2;
}
}
}
}
}
}
}
}


if ( $imageType === NULL )
if ( $imageType === NULL )
{
{
throw new InvalidArgumentException;
throw new InvalidArgumentException;
}
}
/* Create object */
/* Create object */
if( Settings::i()->image_suite == 'imagemagick' and class_exists( 'Imagick', FALSE ) )
if( Settings::i()->image_suite == 'imagemagick' and class_exists( 'Imagick', FALSE ) )
{
{
$obj = new Imagemagick( $contents );
$obj = new Imagemagick( $contents );
}
}
else
else
{
{
$obj = new Gd( $contents );
$obj = new Gd( $contents );
}
}
$obj->type = $imageType;
$obj->type = $imageType;
/* Animated? @see https://www.php.net/manual/en/function.imagecreatefromgif.php#102915 */
/* Animated? @see https://www.php.net/manual/en/function.imagecreatefromgif.php#102915 */
if ( $obj->type === 'gif' and preg_match( '#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $contents ) )
if ( $obj->type === 'gif' and preg_match( '#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $contents ) )
{
{
$obj->isAnimatedGif = TRUE;
$obj->isAnimatedGif = TRUE;
$obj->contents = $contents;
$obj->contents = $contents;
}
}
/* Set EXIF data immediately */
/* Set EXIF data immediately */
if( static::exifSupported() AND $checkRotation )
if( static::exifSupported() AND $checkRotation )
{
{
$obj->setExifData( $contents );
$obj->setExifData( $contents );


/* If the image is misoriented, attempt to automatically reorient */
/* If the image is misoriented, attempt to automatically reorient */
$orientation = $obj->getImageOrientation();
$orientation = $obj->getImageOrientation();


/* Valid orientation values:
/* Valid orientation values:
1 = 0 degrees: the correct orientation, no adjustment is required.
1 = 0 degrees: the correct orientation, no adjustment is required.
2 = 0 degrees, mirrored: image has been flipped back-to-front.
2 = 0 degrees, mirrored: image has been flipped back-to-front.
3 = 180 degrees: image is upside down.
3 = 180 degrees: image is upside down.
4 = 180 degrees, mirrored: image has been flipped back-to-front and is upside down.
4 = 180 degrees, mirrored: image has been flipped back-to-front and is upside down.
5 = 90 degrees: image has been flipped back-to-front and is on its side.
5 = 90 degrees clockwise, mirrored: image has been flipped back-to-front and is on its side.
6 = 90 degrees, mirrored: image is on its side.
6 = 90 degrees clockwise: image is on its side.
7 = 270 degrees: image has been flipped back-to-front and is on its far side.
7 = 270 degrees clockwise, mirrored: image has been flipped back-to-front and is on its far side.
8 = 270 degrees, mirrored: image is on its far side.*/
8 = 270 degrees clockwise: image is on its far side.*/


/* Differences in orientation between GD and ImageMagick can cause auto-reorient to not work properly
/* Log orientation and dimensions for debugging */
GD rotates counter-clockwise; ImageMagick rotates clockwise */
error_log("Orientation EXIF : " . ($orientation ?? 'Aucune') . ", Type : " . get_class($obj) . ", Largeur: {$obj->width}, Hauteur: {$obj->height}");


if ( !( $obj instanceof Image\Imagemagick ) )
if ( $obj instanceof Image\Imagemagick )
{
/* Use autoOrient for ImageMagick to handle EXIF orientation automatically */
$obj->autoOrient();
$obj->hasBeenRotated = TRUE;

/* Update dimensions after rotation */
$obj->width = $obj->getWidth();
$obj->height = $obj->getHeight();

/* Log dimensions after autoOrient */
error_log("Après autoOrient - Largeur: {$obj->width}, Hauteur: {$obj->height}");

/* Has the image been flipped? */
if( in_array( $orientation, array( 2, 4, 5, 7 ) ) )
{
$obj->flip();
}
}
else
{
{
/* GD does not support autoOrient, so apply manual rotations */
switch ( $orientation )
switch ( $orientation )
{
{
case 3:
case 3:
case 4:
case 4:
$obj->rotate( 180 );
$obj->rotate( 180 );
$obj->hasBeenRotated = TRUE;
$obj->hasBeenRotated = TRUE;
break;
break;


case 5:
case 5:
case 6:
case 6:
$obj->rotate( -90 );
$obj->rotate( -90 );
$obj->hasBeenRotated = TRUE;
$obj->hasBeenRotated = TRUE;
break;
break;


case 7:
case 7:
case 8:
case 8:
$obj->rotate( 90 );
$obj->rotate( 90 );
$obj->hasBeenRotated = TRUE;
$obj->hasBeenRotated = TRUE;
break;
break;
}
}
}

else
/* Has the image been flipped? */
{
if( in_array( $orientation, array( 2, 4, 5, 7 ) ) )
switch( $orientation )
{
{
case 3:
$obj->flip();
case 4:
$obj->rotate( 180 );
$obj->hasBeenRotated = TRUE;
break;

case 5:
case 6:
$obj->rotate( 90 );
$obj->hasBeenRotated = TRUE;
break;

case 7:
case 8:
$obj->rotate( -90 );
$obj->hasBeenRotated = TRUE;
break;
}
}
}
}

/* Has the image been flipped? */
if( in_array( $orientation, array( 2, 4, 5, 7 ) ) )
{
$obj->flip();
}
}
}
/* Return */
/* Return */
return $obj;
return $obj;
}
}
/**
/**
* @brief Type ('png', 'jpeg' or 'gif')
* @brief Type ('png', 'jpeg' or 'gif')
*/
*/
public ?string $type = NULL;
public ?string $type = NULL;
/**
/**
* @brief Width
* @brief Width
*/
*/
public ?int $width = null;
public ?int $width = null;
/**
/**
* @brief Height
* @brief Height
*/
*/
public ?int $height = null;
public ?int $height = null;
/**
/**
* @brief Is this an animated gif?
* @brief Is this an animated gif?
*/
*/
public bool $isAnimatedGif = FALSE;
public bool $isAnimatedGif = FALSE;
/**
/**
* @brief Contents of the image file when animated gif
* @brief Contents of the image file when animated gif
*/
*/
public ?string $contents = NULL;
public ?string $contents = NULL;


/**
/**
* @brief EXIF data - has to be pulled and stored before GD manipulates image
* @brief EXIF data - has to be pulled and stored before GD manipulates image
*/
*/
protected array $exif = array();
protected array $exif = array();
/**
/**
* Resize to maximum
* Resize to maximum
*
*
* @param int|null $maxWidth Max Width (in pixels) or NULL
* @param int|null $maxWidth Max Width (in pixels) or NULL
* @param int|null $maxHeight Max Height (in pixels) or NULL
* @param int|null $maxHeight Max Height (in pixels) or NULL
* @param bool $retainRatio If TRUE, the image will keep it's current width/height ratio rather than being squashed
* @param bool $retainRatio If TRUE, the image will keep its current width/height ratio rather than being squashed
* @return bool Returns TRUE if it actually resized, or FALSE if it wasn't necessary
* @return bool Returns TRUE if it actually resized, or FALSE if it wasn't necessary
*/
*/
public function resizeToMax(int $maxWidth=NULL, int $maxHeight=NULL, bool $retainRatio=TRUE ): bool
public function resizeToMax(int $maxWidth=NULL, int $maxHeight=NULL, bool $retainRatio=TRUE ): bool
{
{
/* If the image is smaller than max we can skip */
/* If the image is smaller than max we can skip */
if( ( $maxWidth == NULL or $this->width < $maxWidth ) and ( $maxHeight == NULL or $this->height < $maxHeight ) )
if( ( $maxWidth == NULL or $this->width < $maxWidth ) and ( $maxHeight == NULL or $this->height < $maxHeight ) )
{
{
return FALSE;
return FALSE;
}
}


/* Work out the maximum width/height */
/* Work out the maximum width/height */
$width = ( $maxWidth !== NULL and $this->width > $maxWidth ) ? $maxWidth : $this->width;
$width = ( $maxWidth !== NULL and $this->width > $maxWidth ) ? $maxWidth : $this->width;
$height = ( $maxHeight !== NULL and $this->height > $maxHeight ) ? $maxHeight : $this->height;
$height = ( $maxHeight !== NULL and $this->height > $maxHeight ) ? $maxHeight : $this->height;
if ( $width != $this->width or $height != $this->height )
if ( $width != $this->width or $height != $this->height )
{
{
/* Adjust the width/height as necessary if we want to keep the ratio */
/* Adjust the width/height as necessary if we want to keep the ratio */
if ( $retainRatio === TRUE )
if ( $retainRatio === TRUE )
{
{
if ( ( $this->height - $height ) <= ( $this->width - $width ) )
if ( ( $this->height - $height ) <= ( $this->width - $width ) )
{
{
$ratio = $this->height / $this->width;
$ratio = $this->height / $this->width;
$height = $width * $ratio;
$height = $width * $ratio;
}
}
else
else
{
{
$ratio = $this->width / $this->height;
$ratio = $this->width / $this->height;
$width = $height * $ratio;
$width = $height * $ratio;
}
}
}
}


/* And resize */
/* And resize */
$this->resize( $width, $height );
$this->resize( $width, $height );
return TRUE;
return TRUE;
}
}
return FALSE;
return FALSE;
}
}
/**
/**
* Add Watermark
* Add Watermark
*
*
* @param Image $watermark The watermark
* @param Image $watermark The watermark
* @return void
* @return void
*/
*/
public function watermark( Image $watermark ) : void
public function watermark( Image $watermark ) : void
{
{
/* If it's too big, resize the watermark */
/* If it's too big, resize the watermark */
$watermark->resizeToMax( $this->width, $this->height );
$watermark->resizeToMax( $this->width, $this->height );


/* Impose */
/* Impose */
$this->impose( $watermark, $this->width - $watermark->width, $this->height - $watermark->height );
$this->impose( $watermark, $this->width - $watermark->width, $this->height - $watermark->height );
}
}


/**
/**
* Parse file object to extract EXIF data
* Parse file object to extract EXIF data
*
*
* @return array
* @return array
* @throws LogicException
* @throws LogicException
*/
*/
public function parseExif(): array
public function parseExif(): array
{
{
if( !static::exifSupported() )
if( !static::exifSupported() )
{
{
throw new LogicException( 'NO_EXIF' );
throw new LogicException( 'NO_EXIF' );
}
}


if( !in_array( $this->type, array( 'jpeg', 'jpg', 'jpe' ) ) )
if( !in_array( $this->type, array( 'jpeg', 'jpg', 'jpe' ) ) )
{
{
return array();
return array();
}
}


$result = array();
$result = array();


/* Read the data and store in an array */
/* Read the data and store in an array */
if( $values = $this->getExifData() )
if( $values = $this->getExifData() )
{
{
foreach( $values as $section => $data )
foreach( $values as $section => $data )
{
{
foreach( $data as $name => $value )
foreach( $data as $name => $value )
{
{
$result[ $section . '.' . $name ] = $value;
$result[ $section . '.' . $name ] = $value;
}
}
}
}
}
}


/* Return the EXIF data */
/* Return the EXIF data */
return $result;
return $result;
}
}
/**
/**
* Get EXIF data, if possible
* Get EXIF data, if possible
*
*
* @return array
* @return array
*/
*/
public function getExifData(): array
public function getExifData(): array
{
{
return $this->exif;
return $this->exif;
}
}


/**
/**
* Get EXIF data, if possible
* Get EXIF data, if possible
*
*
* @param string $contents Image contents
* @param string $contents Image contents
* @return void
* @return void
*/
*/
public function setExifData( string $contents ) : void
public function setExifData( string $contents ) : void
{
{
if( !in_array( $this->type, array( 'jpeg', 'jpg', 'jpe' ) ) )
if( !in_array( $this->type, array( 'jpeg', 'jpg', 'jpe' ) ) )
{
{
return;
return;
}
}


/* Exif requires a file on disk, so write it temporarily */
/* Exif requires a file on disk, so write it temporarily */
$temporary = tempnam( TEMP_DIRECTORY, 'exif' );
$temporary = tempnam( TEMP_DIRECTORY, 'exif' );
if ( $temporary === FALSE )
{
throw new \RuntimeException('Unable to create temporary file for EXIF data');
}
file_put_contents( $temporary, $contents );
file_put_contents( $temporary, $contents );


$result = @exif_read_data( $temporary, NULL, TRUE );
$result = @exif_read_data( $temporary, NULL, TRUE );


/* Remove the temporary file */
/* Remove the temporary file */
if( @is_file( $temporary ) )
if( @is_file( $temporary ) )
{
{
@unlink( $temporary );
@unlink( $temporary );
}
}


$this->exif = $result;
$this->exif = $result ?: array();
}
}


/**
/**
* Create a new blank canvas image
* Create a new blank canvas image
*
*
* @param int $width Width
* @param int $width Width
* @param int $height Height
* @param int $height Height
* @param array $rgb Color to use for bg
* @param array $rgb Color to use for bg
* @return Image
* @return Image
*/
*/
public static function newImageCanvas( int $width, int $height, array $rgb ): Image
public static function newImageCanvas( int $width, int $height, array $rgb ): Image
{
{
if( Settings::i()->image_suite == 'imagemagick' and class_exists( 'Imagick', FALSE ) )
if( Settings::i()->image_suite == 'imagemagick' and class_exists( 'Imagick', FALSE ) )
{
{
return Imagemagick::newImageCanvas( $width, $height, $rgb );
return Imagemagick::newImageCanvas( $width, $height, $rgb );
}
}
else
else
{
{
return Gd::newImageCanvas( $width, $height, $rgb );
return Gd::newImageCanvas( $width, $height, $rgb );
}
}
}
}


/**
/**
* Write text on our image
* Write text on our image
*
*
* @param string $text Text
* @param string $text Text
* @param string $font Path to font to use
* @param string $font Path to font to use
* @param int $size Size of text
* @param int $size Size of text
* @return void
* @return void
*/
*/
abstract public function write( string $text, string $font, int $size ) : void;
abstract public function write( string $text, string $font, int $size ) : void;


/**
/**
* Get Contents
* Get Contents
*
*
* @return string
* @return string
*/
*/
abstract public function __toString();
abstract public function __toString();

/**
* Automatically orient the image based on EXIF data
*
* @return void
*/
abstract public function autoOrient(): void;
/**
/**
* Resize
* Resize
*
*
* @param int $width Width (in pixels)
* @param int $width Width (in pixels)
* @param int $height Height (in pixels)
* @param int $height Height (in pixels)
* @return void
* @return void
*/
*/
abstract public function resize( int $width, int $height ) : void;
abstract public function resize( int $width, int $height ) : void;


/**
/**
* Crop to a given width and height (will attempt to downsize first)
* Crop to a given width and height
*
*
* @param int $width Width (in pixels)
* @param int $width Width (in pixels)
* @param int $height Height (in pixels)
* @param int $height Height (in pixels)
* @return void
* @return void
*/
*/
abstract public function crop( int $width, int $height ) : void;
abstract public function crop( int $width, int $height ) : void;
/**
/**
* Crop at specific points
* Crop at specific points
*
*
* @param int $point1X x-point for top-left corner
* @param int $point1X x-point for top-left corner
* @param int $point1Y y-point for top-left corner
* @param int $point1Y y-point for top-left corner
* @param int $point2X x-point for bottom-right corner
* @param int $point2X x-point for bottom-right corner
* @param int $point2Y y-point for bottom-right corner
* @param int $point2Y y-point for bottom-right corner
* @return void
* @return void
*/
*/
abstract public function cropToPoints( int $point1X, int $point1Y, int $point2X, int $point2Y ) : void;
abstract public function cropToPoints( int $point1X, int $point1Y, int $point2X, int $point2Y ) : void;
/**
/**
* Impose image
* Impose image
*
*
* @param Image $image Image to impose
* @param Image $image Image to impose
* @param int $x Location to impose to, x axis
* @param int $x Location to impose to, x axis
* @param int $y Location to impose to, y axis
* @param int $y Location to impose to, y axis
* @return void
* @return void
*/
*/
abstract public function impose( Image $image, int $x=0, int $y=0 ) : void;
abstract public function impose( Image $image, int $x=0, int $y=0 ) : void;


/**
/**
* Rotate image
* Rotate image
*
*
* @param int $angle Angle of rotation
* @param int $angle Angle of rotation
* @return void
* @return void
*/
*/
abstract public function rotate( int $angle ) : void;
abstract public function rotate( int $angle ) : void;


/**
/**
* Flip image horizontally
*
* @return void
* @return void
*/
*/
abstract public function flip():void;
abstract public function flip(): void;
/**
/**
* Get Image Orientation
* Get Image Orientation
*
*
* @return int|NULL
* @return int|NULL
*/
*/
public function getImageOrientation(): ?int
public function getImageOrientation(): ?int
{
{
if ( static::exifSupported() )
if ( static::exifSupported() )
{
{
$exif = $this->parseExif();
$exif = $this->parseExif();


if ( isset( $exif['IFD0.Orientation'] ) )
if ( isset( $exif['IFD0.Orientation'] ) )
{
{
return (int) $exif['IFD0.Orientation'];
return (int) $exif['IFD0.Orientation'];
}
}
}
}
return null;
return null;
}
}
/**
/**
* Set Image Orientation
* Set Image Orientation
*
*
* @param int $orientation The orientation
* @param int $orientation The orientation
* @return void
* @return void
*/
*/
abstract public function setImageOrientation( int $orientation ) : void;
abstract public function setImageOrientation( int $orientation ) : void;


/**
/**
* Get Image Width
*
* @return int|null
*/
abstract public function getWidth(): ?int;

/**
* Get Image Height
*
* @return int|null
*/
abstract public function getHeight(): ?int;

/**
* Can we write text reliably on an image?
* Can we write text reliably on an image?
*
*
* @return bool
* @return bool
*/
*/
public static function canWriteText(): bool
public static function canWriteText(): bool
{
{
/* Create object */
if( Settings::i()->image_suite == 'imagemagick' and class_exists( 'Imagick', FALSE ) )
if( Settings::i()->image_suite == 'imagemagick' and class_exists( 'Imagick', FALSE ) )
{
{
return Image\Imagemagick::canWriteText();
return Image\Imagemagick::canWriteText();
}
}
else
else
{
{
return Image\Gd::canWriteText();
return Image\Gd::canWriteText();
}
}
}
}
/**
/**
* Return an array of supported extensions
* Return an array of supported extensions
*
*
* @return array
* @return array
*/
*/
public static function supportedExtensions(): array
public static function supportedExtensions(): array
{
{
if( Settings::i()->image_suite == 'imagemagick' and class_exists( 'Imagick', FALSE ) )
if( Settings::i()->image_suite == 'imagemagick' and class_exists( 'Imagick', FALSE ) )
{
{
return Image\Imagemagick::supportedExtensions();
return Image\Imagemagick::supportedExtensions();
}
}
else
else
{
{
return Image\Gd::supportedExtensions();
return Image\Gd::supportedExtensions();
}
}
}
}


/**
/**
* Is this a square image ( width == height )
* Is this a square image ( width == height )
*
*
* @return bool
* @return bool
*/
*/
public function isSquare(): bool
public function isSquare(): bool
{
{
return $this->width === $this->height;
return $this->width === $this->height;
}
}
}
}