2012-01-01 20:57:26 +04:00
< ? php
/**
2016-07-21 18:07:57 +03:00
* @ copyright Copyright ( c ) 2016 , ownCloud , Inc .
*
2017-11-06 17:56:42 +03:00
* @ author Bartek Przybylski < bart . p . pl @ gmail . com >
2019-12-03 21:57:53 +03:00
* @ author Bart Visscher < bartv @ thisnet . nl >
2016-05-26 20:56:05 +03:00
* @ author Björn Schießle < bjoern @ schiessle . org >
2015-03-26 13:44:34 +03:00
* @ author Byron Marohn < combustible @ live . com >
* @ author Christopher Schäpers < kondou @ ts . unde . re >
2020-03-31 11:49:10 +03:00
* @ author Christoph Wurst < christoph @ winzerhof - wurst . at >
2017-11-06 22:15:27 +03:00
* @ author Georg Ehrke < oc . list @ georgehrke . com >
2015-03-26 13:44:34 +03:00
* @ author j - ed < juergen @ eisfair . org >
2016-07-21 18:07:57 +03:00
* @ author Joas Schilling < coding @ schilljs . com >
2015-03-26 13:44:34 +03:00
* @ author Johannes Willnecker < johannes @ willnecker . com >
* @ author Jörn Friedrich Dreyer < jfd @ butonic . de >
2019-12-03 21:57:53 +03:00
* @ author Julius Härtl < jus @ bitgrid . net >
2016-05-26 20:56:05 +03:00
* @ author Lukas Reschke < lukas @ statuscode . ch >
2015-03-26 13:44:34 +03:00
* @ author Morris Jobke < hey @ morrisjobke . de >
* @ author Olivier Paroz < github @ oparoz . com >
2016-07-21 19:13:36 +03:00
* @ author Robin Appelman < robin @ icewind . nl >
2017-11-06 17:56:42 +03:00
* @ author Roeland Jago Douma < roeland @ famdouma . nl >
2019-12-03 21:57:53 +03:00
* @ author Samuel CHEMLA < chemla . samuel @ gmail . com >
2015-03-26 13:44:34 +03:00
* @ author Thomas Müller < thomas . mueller @ tmit . eu >
* @ author Thomas Tanghus < thomas @ tanghus . net >
*
* @ license AGPL - 3.0
*
* This code is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License , version 3 ,
* as published by the Free Software Foundation .
2014-11-05 18:44:19 +03:00
*
2015-03-26 13:44:34 +03:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
2014-11-05 18:44:19 +03:00
*
2015-03-26 13:44:34 +03:00
* You should have received a copy of the GNU Affero General Public License , version 3 ,
2019-12-03 21:57:53 +03:00
* along with this program . If not , see < http :// www . gnu . org / licenses />
2014-11-05 18:44:19 +03:00
*
2012-01-01 20:57:26 +04:00
*/
2015-02-26 13:37:37 +03:00
/**
* Class for basic image manipulation
*/
2015-03-13 12:10:11 +03:00
class OC_Image implements \OCP\IImage {
2016-01-04 16:18:01 +03:00
/** @var false|resource */
2012-02-10 01:44:26 +04:00
protected $resource = false ; // tmp resource.
2016-01-04 16:18:01 +03:00
/** @var int */
2013-08-06 18:56:50 +04:00
protected $imageType = IMAGETYPE_PNG ; // Default to png if file type isn't evident.
2016-01-04 16:18:01 +03:00
/** @var string */
protected $mimeType = 'image/png' ; // Default to png
/** @var int */
2013-08-06 18:56:50 +04:00
protected $bitDepth = 24 ;
2016-01-04 16:18:01 +03:00
/** @var null|string */
2013-08-06 18:56:50 +04:00
protected $filePath = null ;
2016-01-04 16:18:01 +03:00
/** @var finfo */
2013-08-06 18:56:50 +04:00
private $fileInfo ;
2016-01-04 16:18:01 +03:00
/** @var \OCP\ILogger */
2014-11-05 18:44:19 +03:00
private $logger ;
2017-02-22 14:11:42 +03:00
/** @var \OCP\IConfig */
private $config ;
2016-10-26 22:36:33 +03:00
/** @var array */
private $exif ;
2014-11-05 18:44:19 +03:00
2012-01-01 20:57:26 +04:00
/**
2014-05-19 19:50:53 +04:00
* Constructor .
2014-11-05 18:44:19 +03:00
*
2014-04-16 00:55:20 +04:00
* @ param resource | string $imageRef The path to a local file , a base64 encoded string or a resource created by
2014-03-17 11:17:56 +04:00
* an imagecreate * function .
2014-11-05 18:44:19 +03:00
* @ param \OCP\ILogger $logger
2017-02-22 14:11:42 +03:00
* @ param \OCP\IConfig $config
2018-01-17 13:46:30 +03:00
* @ throws \InvalidArgumentException in case the $imageRef parameter is not null
2014-03-17 11:17:56 +04:00
*/
2017-02-22 14:17:55 +03:00
public function __construct ( $imageRef = null , \OCP\ILogger $logger = null , \OCP\IConfig $config = null ) {
2014-11-05 18:44:19 +03:00
$this -> logger = $logger ;
2017-02-22 14:17:55 +03:00
if ( $logger === null ) {
2014-11-05 18:44:19 +03:00
$this -> logger = \OC :: $server -> getLogger ();
}
2017-02-22 14:11:42 +03:00
$this -> config = $config ;
if ( $config === null ) {
$this -> config = \OC :: $server -> getConfig ();
}
2014-11-05 18:44:19 +03:00
2013-08-06 18:56:50 +04:00
if ( \OC_Util :: fileInfoLoaded ()) {
$this -> fileInfo = new finfo ( FILEINFO_MIME_TYPE );
}
2017-02-22 14:17:55 +03:00
if ( $imageRef !== null ) {
2018-01-17 13:46:30 +03:00
throw new \InvalidArgumentException ( 'The first parameter in the constructor is not supported anymore. Please use any of the load* methods of the image object to load an image.' );
2012-01-01 20:57:26 +04:00
}
}
2012-01-01 23:06:35 +04:00
/**
2014-11-05 18:44:19 +03:00
* Determine whether the object contains an image resource .
*
* @ return bool
*/
2012-01-02 02:26:24 +04:00
public function valid () { // apparently you can't name a method 'empty'...
2012-02-10 01:44:26 +04:00
return is_resource ( $this -> resource );
2012-01-02 02:26:24 +04:00
}
/**
2014-11-05 18:44:19 +03:00
* Returns the MIME type of the image or an empty string if no image is loaded .
*
* @ return string
*/
2012-01-02 02:26:24 +04:00
public function mimeType () {
2013-08-06 18:56:50 +04:00
return $this -> valid () ? $this -> mimeType : '' ;
2012-01-02 02:26:24 +04:00
}
/**
2014-11-05 18:44:19 +03:00
* Returns the width of the image or - 1 if no image is loaded .
*
* @ return int
*/
2012-01-02 02:26:24 +04:00
public function width () {
2012-02-12 17:28:16 +04:00
return $this -> valid () ? imagesx ( $this -> resource ) : - 1 ;
2012-01-02 02:26:24 +04:00
}
/**
2014-11-05 18:44:19 +03:00
* Returns the height of the image or - 1 if no image is loaded .
*
* @ return int
*/
2012-01-02 02:26:24 +04:00
public function height () {
2012-02-12 17:28:16 +04:00
return $this -> valid () ? imagesy ( $this -> resource ) : - 1 ;
2012-01-01 23:06:35 +04:00
}
2012-07-05 23:09:48 +04:00
/**
2014-11-05 18:44:19 +03:00
* Returns the width when the image orientation is top - left .
*
* @ return int
*/
2012-07-05 23:09:48 +04:00
public function widthTopLeft () {
$o = $this -> getOrientation ();
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->widthTopLeft() Orientation: ' . $o , [ 'app' => 'core' ]);
2014-11-05 18:44:19 +03:00
switch ( $o ) {
2012-07-05 23:09:48 +04:00
case - 1 :
case 1 :
case 2 : // Not tested
case 3 :
case 4 : // Not tested
return $this -> width ();
case 5 : // Not tested
case 6 :
case 7 : // Not tested
case 8 :
return $this -> height ();
}
return $this -> width ();
}
/**
2014-11-05 18:44:19 +03:00
* Returns the height when the image orientation is top - left .
*
* @ return int
*/
2012-07-05 23:09:48 +04:00
public function heightTopLeft () {
$o = $this -> getOrientation ();
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->heightTopLeft() Orientation: ' . $o , [ 'app' => 'core' ]);
2014-11-05 18:44:19 +03:00
switch ( $o ) {
2012-07-05 23:09:48 +04:00
case - 1 :
case 1 :
case 2 : // Not tested
case 3 :
case 4 : // Not tested
return $this -> height ();
case 5 : // Not tested
case 6 :
case 7 : // Not tested
case 8 :
return $this -> width ();
}
return $this -> height ();
}
2012-01-01 20:57:26 +04:00
/**
2014-05-19 19:50:53 +04:00
* Outputs the image .
2014-11-05 18:44:19 +03:00
*
2014-03-17 11:17:56 +04:00
* @ param string $mimeType
* @ return bool
*/
2014-11-05 18:44:19 +03:00
public function show ( $mimeType = null ) {
if ( $mimeType === null ) {
2014-03-14 14:13:45 +04:00
$mimeType = $this -> mimeType ();
}
2014-11-05 18:44:19 +03:00
header ( 'Content-Type: ' . $mimeType );
2014-03-14 14:13:45 +04:00
return $this -> _output ( null , $mimeType );
2012-01-02 15:09:45 +04:00
}
/**
2014-05-19 19:50:53 +04:00
* Saves the image .
2014-11-05 18:44:19 +03:00
*
2014-03-17 11:17:56 +04:00
* @ param string $filePath
* @ param string $mimeType
* @ return bool
*/
2012-01-02 16:40:23 +04:00
2014-11-05 18:44:19 +03:00
public function save ( $filePath = null , $mimeType = null ) {
if ( $mimeType === null ) {
2014-03-14 14:13:45 +04:00
$mimeType = $this -> mimeType ();
}
2017-02-22 14:17:55 +03:00
if ( $filePath === null ) {
if ( $this -> filePath === null ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): called with no path.' , [ 'app' => 'core' ]);
2017-02-22 14:17:55 +03:00
return false ;
} else {
$filePath = $this -> filePath ;
}
2012-01-02 15:09:45 +04:00
}
2014-03-14 14:13:45 +04:00
return $this -> _output ( $filePath , $mimeType );
2012-01-02 15:09:45 +04:00
}
/**
2014-05-19 19:50:53 +04:00
* Outputs / saves the image .
2014-11-05 18:44:19 +03:00
*
2014-03-17 11:17:56 +04:00
* @ param string $filePath
* @ param string $mimeType
* @ return bool
* @ throws Exception
*/
2014-11-05 18:44:19 +03:00
private function _output ( $filePath = null , $mimeType = null ) {
if ( $filePath ) {
2017-02-22 14:17:55 +03:00
if ( ! file_exists ( dirname ( $filePath ))) {
2013-08-06 18:56:50 +04:00
mkdir ( dirname ( $filePath ), 0777 , true );
2017-02-22 14:17:55 +03:00
}
$isWritable = is_writable ( dirname ( $filePath ));
if ( ! $isWritable ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): Directory \'' . dirname ( $filePath ) . '\' is not writable.' , [ 'app' => 'core' ]);
2012-01-02 16:40:23 +04:00
return false ;
2017-02-22 14:17:55 +03:00
} elseif ( $isWritable && file_exists ( $filePath ) && ! is_writable ( $filePath )) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): File \'' . $filePath . '\' is not writable.' , [ 'app' => 'core' ]);
2012-01-02 15:09:45 +04:00
return false ;
}
}
2012-02-08 01:33:01 +04:00
if ( ! $this -> valid ()) {
return false ;
}
2014-03-17 11:17:56 +04:00
$imageType = $this -> imageType ;
2014-11-05 18:44:19 +03:00
if ( $mimeType !== null ) {
switch ( $mimeType ) {
2014-03-14 14:13:45 +04:00
case 'image/gif' :
2014-03-14 14:17:20 +04:00
$imageType = IMAGETYPE_GIF ;
2014-03-14 14:13:45 +04:00
break ;
case 'image/jpeg' :
2014-03-14 14:17:20 +04:00
$imageType = IMAGETYPE_JPEG ;
2014-03-14 14:13:45 +04:00
break ;
case 'image/png' :
2014-03-14 14:17:20 +04:00
$imageType = IMAGETYPE_PNG ;
2014-03-14 14:13:45 +04:00
break ;
case 'image/x-xbitmap' :
2014-03-14 14:17:20 +04:00
$imageType = IMAGETYPE_XBM ;
2014-03-14 14:13:45 +04:00
break ;
case 'image/bmp' :
2016-02-13 23:55:20 +03:00
case 'image/x-ms-bmp' :
2014-03-14 14:17:20 +04:00
$imageType = IMAGETYPE_BMP ;
2014-03-14 14:13:45 +04:00
break ;
default :
2014-03-14 21:19:16 +04:00
throw new Exception ( '\OC_Image::_output(): "' . $mimeType . '" is not supported when forcing a specific output format' );
2014-03-14 14:13:45 +04:00
}
}
2014-11-05 18:44:19 +03:00
switch ( $imageType ) {
2012-01-02 02:26:24 +04:00
case IMAGETYPE_GIF :
2013-08-06 18:56:50 +04:00
$retVal = imagegif ( $this -> resource , $filePath );
2012-01-02 02:26:24 +04:00
break ;
case IMAGETYPE_JPEG :
2017-02-22 14:11:42 +03:00
$retVal = imagejpeg ( $this -> resource , $filePath , $this -> getJpegQuality ());
2012-01-02 02:26:24 +04:00
break ;
case IMAGETYPE_PNG :
2013-08-06 18:56:50 +04:00
$retVal = imagepng ( $this -> resource , $filePath );
2012-01-02 02:26:24 +04:00
break ;
case IMAGETYPE_XBM :
2014-03-17 11:40:59 +04:00
if ( function_exists ( 'imagexbm' )) {
$retVal = imagexbm ( $this -> resource , $filePath );
} else {
throw new Exception ( '\OC_Image::_output(): imagexbm() is not supported.' );
}
2012-01-02 02:26:24 +04:00
break ;
case IMAGETYPE_WBMP :
2013-08-06 18:56:50 +04:00
$retVal = imagewbmp ( $this -> resource , $filePath );
2012-01-02 02:26:24 +04:00
break ;
2012-11-06 13:54:32 +04:00
case IMAGETYPE_BMP :
2013-08-06 18:56:50 +04:00
$retVal = imagebmp ( $this -> resource , $filePath , $this -> bitDepth );
2012-11-06 13:54:32 +04:00
break ;
2012-01-02 02:26:24 +04:00
default :
2013-08-06 18:56:50 +04:00
$retVal = imagepng ( $this -> resource , $filePath );
2012-01-02 02:26:24 +04:00
}
2013-08-06 18:56:50 +04:00
return $retVal ;
2012-01-01 20:57:26 +04:00
}
/**
2014-11-05 18:44:19 +03:00
* Prints the image when called as $image () .
*/
2012-01-01 20:57:26 +04:00
public function __invoke () {
2012-02-10 01:44:26 +04:00
return $this -> show ();
2012-01-01 20:57:26 +04:00
}
2018-01-17 13:46:30 +03:00
/**
* @ param resource Returns the image resource in any .
* @ throws \InvalidArgumentException in case the supplied resource does not have the type " gd "
*/
public function setResource ( $resource ) {
if ( get_resource_type ( $resource ) === 'gd' ) {
$this -> resource = $resource ;
return ;
}
throw new \InvalidArgumentException ( 'Supplied resource is not of type "gd".' );
}
2012-01-01 20:57:26 +04:00
/**
2014-11-05 18:44:19 +03:00
* @ return resource Returns the image resource in any .
*/
2012-01-02 02:26:24 +04:00
public function resource () {
2012-02-10 01:44:26 +04:00
return $this -> resource ;
2012-01-01 20:57:26 +04:00
}
2018-01-04 12:00:07 +03:00
/**
2018-01-07 13:46:24 +03:00
* @ return string Returns the mimetype of the data . Returns the empty string
* if the data is not valid .
2018-01-04 12:00:07 +03:00
*/
public function dataMimeType () {
if ( ! $this -> valid ()) {
2018-01-07 13:46:24 +03:00
return '' ;
2018-01-04 12:00:07 +03:00
}
switch ( $this -> mimeType ) {
case 'image/png' :
case 'image/jpeg' :
case 'image/gif' :
return $this -> mimeType ;
default :
return 'image/png' ;
}
}
2012-01-01 20:57:26 +04:00
/**
2015-03-13 19:23:02 +03:00
* @ return null | string Returns the raw image data .
2014-11-05 18:44:19 +03:00
*/
2015-03-13 12:10:11 +03:00
public function data () {
2015-03-13 19:23:02 +03:00
if ( ! $this -> valid ()) {
return null ;
}
2012-01-01 20:57:26 +04:00
ob_start ();
2013-08-06 18:56:50 +04:00
switch ( $this -> mimeType ) {
case " image/png " :
$res = imagepng ( $this -> resource );
break ;
case " image/jpeg " :
2017-02-22 14:11:42 +03:00
$quality = $this -> getJpegQuality ();
if ( $quality !== null ) {
$res = imagejpeg ( $this -> resource , null , $quality );
} else {
$res = imagejpeg ( $this -> resource );
}
2013-08-06 18:56:50 +04:00
break ;
case " image/gif " :
$res = imagegif ( $this -> resource );
break ;
default :
$res = imagepng ( $this -> resource );
2020-03-26 11:30:18 +03:00
$this -> logger -> info ( 'OC_Image->data. Could not guess mime-type, defaulting to png' , [ 'app' => 'core' ]);
2013-08-06 18:56:50 +04:00
break ;
}
2012-01-01 20:57:26 +04:00
if ( ! $res ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( 'OC_Image->data. Error getting image data.' , [ 'app' => 'core' ]);
2012-01-01 20:57:26 +04:00
}
2012-06-05 22:19:27 +04:00
return ob_get_clean ();
}
/**
2014-02-27 02:56:46 +04:00
* @ return string - base64 encoded , which is suitable for embedding in a VCard .
*/
2017-02-22 14:17:55 +03:00
public function __toString () {
2012-06-05 22:19:27 +04:00
return base64_encode ( $this -> data ());
2012-01-01 20:57:26 +04:00
}
2017-02-22 14:11:42 +03:00
/**
* @ return int | null
*/
protected function getJpegQuality () {
$quality = $this -> config -> getAppValue ( 'preview' , 'jpeg_quality' , 90 );
if ( $quality !== null ) {
$quality = min ( 100 , max ( 10 , ( int ) $quality ));
}
return $quality ;
}
2012-01-05 20:42:40 +04:00
/**
2014-11-05 18:44:19 +03:00
* ( I ' m open for suggestions on better method name ;)
* Get the orientation based on EXIF data .
*
* @ return int The orientation or - 1 if no EXIF data is available .
*/
2012-07-05 23:09:48 +04:00
public function getOrientation () {
2016-10-26 22:36:33 +03:00
if ( $this -> exif !== null ) {
return $this -> exif [ 'Orientation' ];
}
2014-11-24 19:32:53 +03:00
if ( $this -> imageType !== IMAGETYPE_JPEG ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->fixOrientation() Image is not a JPEG.' , [ 'app' => 'core' ]);
2014-11-24 19:32:53 +03:00
return - 1 ;
}
2014-11-05 18:44:19 +03:00
if ( ! is_callable ( 'exif_read_data' )) {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->fixOrientation() Exif module not enabled.' , [ 'app' => 'core' ]);
2012-07-05 23:09:48 +04:00
return - 1 ;
2012-01-20 20:13:49 +04:00
}
2014-11-05 18:44:19 +03:00
if ( ! $this -> valid ()) {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->fixOrientation() No image loaded.' , [ 'app' => 'core' ]);
2012-07-05 23:09:48 +04:00
return - 1 ;
2012-01-05 20:42:40 +04:00
}
2014-11-05 18:44:19 +03:00
if ( is_null ( $this -> filePath ) || ! is_readable ( $this -> filePath )) {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->fixOrientation() No readable file path set.' , [ 'app' => 'core' ]);
2012-07-05 23:09:48 +04:00
return - 1 ;
2012-01-05 20:42:40 +04:00
}
2013-08-06 18:56:50 +04:00
$exif = @ exif_read_data ( $this -> filePath , 'IFD0' );
2014-11-05 18:44:19 +03:00
if ( ! $exif ) {
2012-07-05 23:09:48 +04:00
return - 1 ;
2012-01-05 20:42:40 +04:00
}
2014-11-05 18:44:19 +03:00
if ( ! isset ( $exif [ 'Orientation' ])) {
2012-07-05 23:09:48 +04:00
return - 1 ;
2012-01-05 20:42:40 +04:00
}
2016-10-26 22:36:33 +03:00
$this -> exif = $exif ;
2012-07-05 23:09:48 +04:00
return $exif [ 'Orientation' ];
}
2016-10-26 22:36:33 +03:00
public function readExif ( $data ) {
if ( ! is_callable ( 'exif_read_data' )) {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->fixOrientation() Exif module not enabled.' , [ 'app' => 'core' ]);
2016-10-26 22:36:33 +03:00
return ;
}
if ( ! $this -> valid ()) {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->fixOrientation() No image loaded.' , [ 'app' => 'core' ]);
2016-10-26 22:36:33 +03:00
return ;
}
$exif = @ exif_read_data ( 'data://image/jpeg;base64,' . base64_encode ( $data ));
if ( ! $exif ) {
return ;
}
if ( ! isset ( $exif [ 'Orientation' ])) {
return ;
}
$this -> exif = $exif ;
}
2012-07-05 23:09:48 +04:00
/**
2014-11-05 18:44:19 +03:00
* ( I ' m open for suggestions on better method name ;)
* Fixes orientation based on EXIF data .
*
2017-10-18 15:15:03 +03:00
* @ return bool
2014-11-05 18:44:19 +03:00
*/
2012-07-05 23:09:48 +04:00
public function fixOrientation () {
2012-07-05 23:35:36 +04:00
$o = $this -> getOrientation ();
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->fixOrientation() Orientation: ' . $o , [ 'app' => 'core' ]);
2012-01-05 20:42:40 +04:00
$rotate = 0 ;
2015-01-19 01:15:52 +03:00
$flip = false ;
2014-11-05 18:44:19 +03:00
switch ( $o ) {
2012-07-05 23:09:48 +04:00
case - 1 :
return false ; //Nothing to fix
2012-01-05 20:42:40 +04:00
case 1 :
$rotate = 0 ;
break ;
2015-01-19 01:15:52 +03:00
case 2 :
2012-01-05 20:42:40 +04:00
$rotate = 0 ;
2015-01-19 01:15:52 +03:00
$flip = true ;
2012-01-05 20:42:40 +04:00
break ;
case 3 :
$rotate = 180 ;
break ;
2015-01-19 01:15:52 +03:00
case 4 :
2012-01-05 20:42:40 +04:00
$rotate = 180 ;
2015-01-19 01:15:52 +03:00
$flip = true ;
2012-01-05 20:42:40 +04:00
break ;
2015-01-19 01:15:52 +03:00
case 5 :
2012-01-05 20:42:40 +04:00
$rotate = 90 ;
2015-01-19 01:15:52 +03:00
$flip = true ;
2012-01-05 20:42:40 +04:00
break ;
case 6 :
$rotate = 270 ;
break ;
2015-01-19 01:15:52 +03:00
case 7 :
2012-01-05 20:42:40 +04:00
$rotate = 270 ;
2015-01-19 01:15:52 +03:00
$flip = true ;
2012-01-05 20:42:40 +04:00
break ;
case 8 :
2012-02-08 01:33:01 +04:00
$rotate = 90 ;
2012-01-05 20:42:40 +04:00
break ;
}
2015-02-12 10:59:47 +03:00
if ( $flip && function_exists ( 'imageflip' )) {
2015-01-19 01:15:52 +03:00
imageflip ( $this -> resource , IMG_FLIP_HORIZONTAL );
}
2014-11-05 18:44:19 +03:00
if ( $rotate ) {
2014-02-13 01:35:49 +04:00
$res = imagerotate ( $this -> resource , $rotate , 0 );
2014-11-05 18:44:19 +03:00
if ( $res ) {
if ( imagealphablending ( $res , true )) {
if ( imagesavealpha ( $res , true )) {
2012-03-27 01:53:48 +04:00
imagedestroy ( $this -> resource );
2012-02-10 01:44:26 +04:00
$this -> resource = $res ;
2012-01-05 20:42:40 +04:00
return true ;
} else {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->fixOrientation() Error during alpha-saving' , [ 'app' => 'core' ]);
2012-01-05 20:42:40 +04:00
return false ;
}
} else {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->fixOrientation() Error during alpha-blending' , [ 'app' => 'core' ]);
2012-01-05 20:42:40 +04:00
return false ;
}
} else {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->fixOrientation() Error during orientation fixing' , [ 'app' => 'core' ]);
2012-01-05 20:42:40 +04:00
return false ;
}
}
2014-02-27 02:56:46 +04:00
return false ;
2012-01-05 20:42:40 +04:00
}
2012-02-16 13:35:35 +04:00
/**
2014-11-05 18:44:19 +03:00
* Loads an image from an open file handle .
* It is the responsibility of the caller to position the pointer at the correct place and to close the handle again .
*
* @ param resource $handle
* @ return resource | false An image resource or false on error
*/
2012-02-16 13:35:35 +04:00
public function loadFromFileHandle ( $handle ) {
2012-03-27 00:33:37 +04:00
$contents = stream_get_contents ( $handle );
2014-11-05 18:44:19 +03:00
if ( $this -> loadFromData ( $contents )) {
2012-02-16 13:35:35 +04:00
return $this -> resource ;
}
2014-11-05 18:44:19 +03:00
return false ;
2012-02-16 13:35:35 +04:00
}
2012-01-01 20:57:26 +04:00
/**
2014-11-05 18:44:19 +03:00
* Loads an image from a local file .
*
* @ param bool | string $imagePath The path to a local file .
* @ return bool | resource An image resource or false on error
*/
public function loadFromFile ( $imagePath = false ) {
2013-03-02 13:51:49 +04:00
// exif_imagetype throws "read error!" if file is less than 12 byte
2014-11-05 18:44:19 +03:00
if ( !@ is_file ( $imagePath ) || ! file_exists ( $imagePath ) || filesize ( $imagePath ) < 12 || ! is_readable ( $imagePath )) {
2012-01-01 20:57:26 +04:00
return false ;
}
2013-11-22 21:01:44 +04:00
$iType = exif_imagetype ( $imagePath );
2013-08-06 18:56:50 +04:00
switch ( $iType ) {
2012-01-02 02:26:24 +04:00
case IMAGETYPE_GIF :
if ( imagetypes () & IMG_GIF ) {
2013-11-22 21:01:44 +04:00
$this -> resource = imagecreatefromgif ( $imagePath );
2014-08-12 13:00:00 +04:00
// Preserve transparency
imagealphablending ( $this -> resource , true );
imagesavealpha ( $this -> resource , true );
2012-01-02 16:40:23 +04:00
} else {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->loadFromFile, GIF images not supported: ' . $imagePath , [ 'app' => 'core' ]);
2012-01-02 02:26:24 +04:00
}
break ;
case IMAGETYPE_JPEG :
if ( imagetypes () & IMG_JPG ) {
2017-03-08 23:48:30 +03:00
if ( getimagesize ( $imagePath ) !== false ) {
2017-05-01 15:03:00 +03:00
$this -> resource = @ imagecreatefromjpeg ( $imagePath );
2017-03-08 23:48:30 +03:00
} else {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->loadFromFile, JPG image not valid: ' . $imagePath , [ 'app' => 'core' ]);
2017-03-08 23:48:30 +03:00
}
2012-01-02 16:40:23 +04:00
} else {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->loadFromFile, JPG images not supported: ' . $imagePath , [ 'app' => 'core' ]);
2012-01-02 02:26:24 +04:00
}
break ;
case IMAGETYPE_PNG :
if ( imagetypes () & IMG_PNG ) {
2017-05-01 15:03:00 +03:00
$this -> resource = @ imagecreatefrompng ( $imagePath );
2014-08-12 13:00:00 +04:00
// Preserve transparency
imagealphablending ( $this -> resource , true );
imagesavealpha ( $this -> resource , true );
2012-01-02 16:40:23 +04:00
} else {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->loadFromFile, PNG images not supported: ' . $imagePath , [ 'app' => 'core' ]);
2012-01-02 02:26:24 +04:00
}
break ;
case IMAGETYPE_XBM :
if ( imagetypes () & IMG_XPM ) {
2017-05-01 15:03:00 +03:00
$this -> resource = @ imagecreatefromxbm ( $imagePath );
2012-01-02 16:40:23 +04:00
} else {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->loadFromFile, XBM/XPM images not supported: ' . $imagePath , [ 'app' => 'core' ]);
2012-01-02 02:26:24 +04:00
}
break ;
case IMAGETYPE_WBMP :
if ( imagetypes () & IMG_WBMP ) {
2017-05-01 15:03:00 +03:00
$this -> resource = @ imagecreatefromwbmp ( $imagePath );
2012-01-02 16:40:23 +04:00
} else {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->loadFromFile, WBMP images not supported: ' . $imagePath , [ 'app' => 'core' ]);
2012-01-02 02:26:24 +04:00
}
break ;
2012-11-06 13:54:32 +04:00
case IMAGETYPE_BMP :
2014-11-05 18:44:19 +03:00
$this -> resource = $this -> imagecreatefrombmp ( $imagePath );
2012-11-06 13:54:32 +04:00
break ;
2012-01-02 02:26:24 +04:00
/*
case IMAGETYPE_TIFF_II : // (intel byte order)
break ;
case IMAGETYPE_TIFF_MM : // (motorola byte order)
break ;
case IMAGETYPE_JPC :
break ;
case IMAGETYPE_JP2 :
break ;
case IMAGETYPE_JPX :
break ;
case IMAGETYPE_JB2 :
break ;
case IMAGETYPE_SWC :
break ;
case IMAGETYPE_IFF :
break ;
case IMAGETYPE_ICO :
break ;
case IMAGETYPE_SWF :
break ;
case IMAGETYPE_PSD :
break ;
*/
default :
2012-08-29 10:38:33 +04:00
2012-06-09 17:12:28 +04:00
// this is mostly file created from encrypted file
2013-11-22 21:01:44 +04:00
$this -> resource = imagecreatefromstring ( \OC\Files\Filesystem :: file_get_contents ( \OC\Files\Filesystem :: getLocalPath ( $imagePath )));
2013-08-06 18:56:50 +04:00
$iType = IMAGETYPE_PNG ;
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->loadFromFile, Default' , [ 'app' => 'core' ]);
2012-01-02 02:26:24 +04:00
break ;
}
2014-11-05 18:44:19 +03:00
if ( $this -> valid ()) {
2013-08-06 18:56:50 +04:00
$this -> imageType = $iType ;
$this -> mimeType = image_type_to_mime_type ( $iType );
$this -> filePath = $imagePath ;
2012-01-02 02:26:24 +04:00
}
2012-02-10 01:44:26 +04:00
return $this -> resource ;
2012-01-01 20:57:26 +04:00
}
/**
2014-11-05 18:44:19 +03:00
* Loads an image from a string of data .
*
* @ param string $str A string of image data as read from a file .
* @ return bool | resource An image resource or false on error
*/
2012-01-02 03:43:27 +04:00
public function loadFromData ( $str ) {
2014-11-05 18:44:19 +03:00
if ( is_resource ( $str )) {
2012-01-01 20:57:26 +04:00
return false ;
}
2012-06-02 17:25:50 +04:00
$this -> resource = @ imagecreatefromstring ( $str );
2013-09-01 17:50:58 +04:00
if ( $this -> fileInfo ) {
2013-08-06 18:56:50 +04:00
$this -> mimeType = $this -> fileInfo -> buffer ( $str );
}
2014-11-05 18:44:19 +03:00
if ( is_resource ( $this -> resource )) {
2013-08-15 18:13:01 +04:00
imagealphablending ( $this -> resource , false );
imagesavealpha ( $this -> resource , true );
}
2013-08-15 15:21:35 +04:00
2014-11-05 18:44:19 +03:00
if ( ! $this -> resource ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->loadFromFile, could not load' , [ 'app' => 'core' ]);
2012-01-01 20:57:26 +04:00
return false ;
}
2012-02-10 01:44:26 +04:00
return $this -> resource ;
2012-01-01 20:57:26 +04:00
}
/**
2014-11-05 18:44:19 +03:00
* Loads an image from a base64 encoded string .
*
* @ param string $str A string base64 encoded string of image data .
* @ return bool | resource An image resource or false on error
*/
2012-01-02 03:43:27 +04:00
public function loadFromBase64 ( $str ) {
2014-11-05 18:44:19 +03:00
if ( ! is_string ( $str )) {
2012-01-01 20:57:26 +04:00
return false ;
}
$data = base64_decode ( $str );
2014-11-05 18:44:19 +03:00
if ( $data ) { // try to load from string data
2012-06-02 17:25:50 +04:00
$this -> resource = @ imagecreatefromstring ( $data );
2013-09-01 17:50:58 +04:00
if ( $this -> fileInfo ) {
2013-08-06 18:56:50 +04:00
$this -> mimeType = $this -> fileInfo -> buffer ( $data );
}
2014-11-05 18:44:19 +03:00
if ( ! $this -> resource ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> debug ( 'OC_Image->loadFromBase64, could not load' , [ 'app' => 'core' ]);
2012-01-01 20:57:26 +04:00
return false ;
}
2012-02-10 01:44:26 +04:00
return $this -> resource ;
2012-01-01 20:57:26 +04:00
} else {
return false ;
}
}
2012-11-12 14:39:04 +04:00
/**
* Create a new image from file or URL
2014-11-05 18:44:19 +03:00
*
2012-11-12 14:39:04 +04:00
* @ link http :// www . programmierer - forum . de / function - imagecreatefrombmp - laeuft - mit - allen - bitraten - t143137 . htm
* @ version 1.00
2014-02-06 19:30:58 +04:00
* @ param string $fileName < p >
2012-11-12 14:39:04 +04:00
* Path to the BMP image .
* </ p >
2014-03-17 11:17:56 +04:00
* @ return bool | resource an image resource identifier on success , < b > FALSE </ b > on errors .
2012-11-12 14:39:04 +04:00
*/
2013-08-06 18:56:50 +04:00
private function imagecreatefrombmp ( $fileName ) {
if ( ! ( $fh = fopen ( $fileName , 'rb' ))) {
2020-03-26 11:30:18 +03:00
$this -> logger -> warning ( 'imagecreatefrombmp: Can not open ' . $fileName , [ 'app' => 'core' ]);
2012-11-06 13:54:32 +04:00
return false ;
}
// read file header
$meta = unpack ( 'vtype/Vfilesize/Vreserved/Voffset' , fread ( $fh , 14 ));
// check for bitmap
if ( $meta [ 'type' ] != 19778 ) {
2014-08-13 17:19:58 +04:00
fclose ( $fh );
2020-03-26 11:30:18 +03:00
$this -> logger -> warning ( 'imagecreatefrombmp: Can not open ' . $fileName . ' is not a bitmap!' , [ 'app' => 'core' ]);
2012-11-06 13:54:32 +04:00
return false ;
}
// read image header
$meta += unpack ( 'Vheadersize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vcolors/Vimportant' , fread ( $fh , 40 ));
// read additional 16bit header
if ( $meta [ 'bits' ] == 16 ) {
$meta += unpack ( 'VrMask/VgMask/VbMask' , fread ( $fh , 12 ));
}
// set bytes and padding
$meta [ 'bytes' ] = $meta [ 'bits' ] / 8 ;
2013-08-06 18:56:50 +04:00
$this -> bitDepth = $meta [ 'bits' ]; //remember the bit depth for the imagebmp call
2014-11-05 18:44:19 +03:00
$meta [ 'decal' ] = 4 - ( 4 * (( $meta [ 'width' ] * $meta [ 'bytes' ] / 4 ) - floor ( $meta [ 'width' ] * $meta [ 'bytes' ] / 4 )));
2012-11-06 13:54:32 +04:00
if ( $meta [ 'decal' ] == 4 ) {
$meta [ 'decal' ] = 0 ;
}
// obtain imagesize
if ( $meta [ 'imagesize' ] < 1 ) {
$meta [ 'imagesize' ] = $meta [ 'filesize' ] - $meta [ 'offset' ];
// in rare cases filesize is equal to offset so we need to read physical size
if ( $meta [ 'imagesize' ] < 1 ) {
2014-02-27 02:56:46 +04:00
$meta [ 'imagesize' ] = @ filesize ( $fileName ) - $meta [ 'offset' ];
2012-11-06 13:54:32 +04:00
if ( $meta [ 'imagesize' ] < 1 ) {
2014-08-13 17:19:58 +04:00
fclose ( $fh );
2020-03-26 11:30:18 +03:00
$this -> logger -> warning ( 'imagecreatefrombmp: Can not obtain file size of ' . $fileName . ' is not a bitmap!' , [ 'app' => 'core' ]);
2012-11-06 13:54:32 +04:00
return false ;
}
}
}
// calculate colors
$meta [ 'colors' ] = ! $meta [ 'colors' ] ? pow ( 2 , $meta [ 'bits' ]) : $meta [ 'colors' ];
// read color palette
2020-03-26 11:30:18 +03:00
$palette = [];
2012-11-06 13:54:32 +04:00
if ( $meta [ 'bits' ] < 16 ) {
$palette = unpack ( 'l' . $meta [ 'colors' ], fread ( $fh , $meta [ 'colors' ] * 4 ));
// in rare cases the color value is signed
if ( $palette [ 1 ] < 0 ) {
foreach ( $palette as $i => $color ) {
$palette [ $i ] = $color + 16777216 ;
}
}
}
// create gd image
$im = imagecreatetruecolor ( $meta [ 'width' ], $meta [ 'height' ]);
2014-11-05 18:44:19 +03:00
if ( $im == false ) {
2014-09-16 03:12:07 +04:00
fclose ( $fh );
2014-11-05 18:44:19 +03:00
$this -> logger -> warning (
'imagecreatefrombmp: imagecreatetruecolor failed for file "' . $fileName . '" with dimensions ' . $meta [ 'width' ] . 'x' . $meta [ 'height' ],
2020-03-26 11:30:18 +03:00
[ 'app' => 'core' ]);
2014-11-05 18:44:19 +03:00
return false ;
2014-09-16 03:12:07 +04:00
}
2012-11-06 13:54:32 +04:00
$data = fread ( $fh , $meta [ 'imagesize' ]);
$p = 0 ;
$vide = chr ( 0 );
$y = $meta [ 'height' ] - 1 ;
2013-08-06 18:56:50 +04:00
$error = 'imagecreatefrombmp: ' . $fileName . ' has not enough data!' ;
2012-11-06 13:54:32 +04:00
// loop through the image data beginning with the lower left corner
while ( $y >= 0 ) {
$x = 0 ;
while ( $x < $meta [ 'width' ]) {
switch ( $meta [ 'bits' ]) {
case 32 :
case 24 :
if ( ! ( $part = substr ( $data , $p , 3 ))) {
2020-03-26 11:30:18 +03:00
$this -> logger -> warning ( $error , [ 'app' => 'core' ]);
2012-11-06 13:54:32 +04:00
return $im ;
}
2017-02-10 15:44:16 +03:00
$color = @ unpack ( 'V' , $part . $vide );
2012-11-06 13:54:32 +04:00
break ;
case 16 :
if ( ! ( $part = substr ( $data , $p , 2 ))) {
2014-08-13 17:19:58 +04:00
fclose ( $fh );
2020-03-26 11:30:18 +03:00
$this -> logger -> warning ( $error , [ 'app' => 'core' ]);
2012-11-06 13:54:32 +04:00
return $im ;
}
2017-02-10 15:44:16 +03:00
$color = @ unpack ( 'v' , $part );
2012-11-06 13:54:32 +04:00
$color [ 1 ] = (( $color [ 1 ] & 0xf800 ) >> 8 ) * 65536 + (( $color [ 1 ] & 0x07e0 ) >> 3 ) * 256 + (( $color [ 1 ] & 0x001f ) << 3 );
break ;
case 8 :
2018-01-26 00:26:47 +03:00
$color = @ unpack ( 'n' , $vide . ( $data [ $p ] ? ? '' ));
2018-01-27 01:46:40 +03:00
$color [ 1 ] = isset ( $palette [ $color [ 1 ] + 1 ]) ? $palette [ $color [ 1 ] + 1 ] : $palette [ 1 ];
2012-11-06 13:54:32 +04:00
break ;
case 4 :
2018-01-26 00:26:47 +03:00
$color = @ unpack ( 'n' , $vide . ( $data [ floor ( $p )] ? ? '' ));
2012-11-06 13:54:32 +04:00
$color [ 1 ] = ( $p * 2 ) % 2 == 0 ? $color [ 1 ] >> 4 : $color [ 1 ] & 0x0F ;
2018-01-27 01:46:40 +03:00
$color [ 1 ] = isset ( $palette [ $color [ 1 ] + 1 ]) ? $palette [ $color [ 1 ] + 1 ] : $palette [ 1 ];
2012-11-06 13:54:32 +04:00
break ;
case 1 :
2018-01-26 00:26:47 +03:00
$color = @ unpack ( 'n' , $vide . ( $data [ floor ( $p )] ? ? '' ));
2012-11-06 13:54:32 +04:00
switch (( $p * 8 ) % 8 ) {
case 0 :
$color [ 1 ] = $color [ 1 ] >> 7 ;
break ;
case 1 :
$color [ 1 ] = ( $color [ 1 ] & 0x40 ) >> 6 ;
break ;
case 2 :
$color [ 1 ] = ( $color [ 1 ] & 0x20 ) >> 5 ;
break ;
case 3 :
$color [ 1 ] = ( $color [ 1 ] & 0x10 ) >> 4 ;
break ;
case 4 :
$color [ 1 ] = ( $color [ 1 ] & 0x8 ) >> 3 ;
break ;
case 5 :
$color [ 1 ] = ( $color [ 1 ] & 0x4 ) >> 2 ;
break ;
case 6 :
$color [ 1 ] = ( $color [ 1 ] & 0x2 ) >> 1 ;
break ;
case 7 :
$color [ 1 ] = ( $color [ 1 ] & 0x1 );
break ;
}
2018-01-27 01:46:40 +03:00
$color [ 1 ] = isset ( $palette [ $color [ 1 ] + 1 ]) ? $palette [ $color [ 1 ] + 1 ] : $palette [ 1 ];
2012-11-06 13:54:32 +04:00
break ;
default :
2014-08-13 17:19:58 +04:00
fclose ( $fh );
2020-03-26 11:30:18 +03:00
$this -> logger -> warning ( 'imagecreatefrombmp: ' . $fileName . ' has ' . $meta [ 'bits' ] . ' bits and this is not supported!' , [ 'app' => 'core' ]);
2012-11-06 13:54:32 +04:00
return false ;
}
imagesetpixel ( $im , $x , $y , $color [ 1 ]);
$x ++ ;
$p += $meta [ 'bytes' ];
}
$y -- ;
$p += $meta [ 'decal' ];
}
fclose ( $fh );
return $im ;
}
2013-01-14 23:30:39 +04:00
2012-01-01 20:57:26 +04:00
/**
2014-11-05 18:44:19 +03:00
* Resizes the image preserving ratio .
*
* @ param integer $maxSize The maximum size of either the width or height .
* @ return bool
*/
2013-08-06 18:56:50 +04:00
public function resize ( $maxSize ) {
2014-11-05 18:44:19 +03:00
if ( ! $this -> valid ()) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): No image loaded' , [ 'app' => 'core' ]);
2012-01-01 21:07:46 +04:00
return false ;
2012-01-01 20:57:26 +04:00
}
2016-08-22 21:56:59 +03:00
$widthOrig = imagesx ( $this -> resource );
$heightOrig = imagesy ( $this -> resource );
2014-11-05 18:44:19 +03:00
$ratioOrig = $widthOrig / $heightOrig ;
2012-08-29 10:38:33 +04:00
2013-08-06 18:56:50 +04:00
if ( $ratioOrig > 1 ) {
2014-11-05 18:44:19 +03:00
$newHeight = round ( $maxSize / $ratioOrig );
2013-08-06 18:56:50 +04:00
$newWidth = $maxSize ;
2012-01-01 20:57:26 +04:00
} else {
2014-11-05 18:44:19 +03:00
$newWidth = round ( $maxSize * $ratioOrig );
2013-08-06 18:56:50 +04:00
$newHeight = $maxSize ;
2012-01-01 20:57:26 +04:00
}
2018-01-13 02:34:28 +03:00
$this -> preciseResize (( int ) round ( $newWidth ), ( int ) round ( $newHeight ));
2012-01-01 20:57:26 +04:00
return true ;
}
2014-03-17 11:17:56 +04:00
/**
* @ param int $width
* @ param int $height
* @ return bool
*/
2018-01-13 02:34:28 +03:00
public function preciseResize ( int $width , int $height ) : bool {
2012-06-02 17:25:50 +04:00
if ( ! $this -> valid ()) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): No image loaded' , [ 'app' => 'core' ]);
2012-08-29 10:38:33 +04:00
return false ;
2012-06-02 17:25:50 +04:00
}
2016-08-22 21:56:59 +03:00
$widthOrig = imagesx ( $this -> resource );
$heightOrig = imagesy ( $this -> resource );
2012-06-02 17:25:50 +04:00
$process = imagecreatetruecolor ( $width , $height );
2019-09-01 23:13:25 +03:00
if ( $process === false ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): Error creating true color image' , [ 'app' => 'core' ]);
2012-06-02 17:25:50 +04:00
return false ;
}
2013-02-22 15:42:40 +04:00
// preserve transparency
2014-11-05 18:44:19 +03:00
if ( $this -> imageType == IMAGETYPE_GIF or $this -> imageType == IMAGETYPE_PNG ) {
2013-02-22 15:42:40 +04:00
imagecolortransparent ( $process , imagecolorallocatealpha ( $process , 0 , 0 , 0 , 127 ));
imagealphablending ( $process , false );
imagesavealpha ( $process , true );
}
2019-09-01 23:13:25 +03:00
$res = imagecopyresampled ( $process , $this -> resource , 0 , 0 , 0 , 0 , $width , $height , $widthOrig , $heightOrig );
if ( $res === false ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): Error re-sampling process image' , [ 'app' => 'core' ]);
2012-06-02 17:25:50 +04:00
imagedestroy ( $process );
return false ;
}
imagedestroy ( $this -> resource );
$this -> resource = $process ;
return true ;
}
2012-01-01 20:57:26 +04:00
/**
2014-11-05 18:44:19 +03:00
* Crops the image to the middle square . If the image is already square it just returns .
*
* @ param int $size maximum size for the result ( optional )
* @ return bool for success or failure
*/
public function centerCrop ( $size = 0 ) {
if ( ! $this -> valid ()) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( 'OC_Image->centerCrop, No image loaded' , [ 'app' => 'core' ]);
2012-01-01 20:57:26 +04:00
return false ;
}
2016-08-22 21:56:59 +03:00
$widthOrig = imagesx ( $this -> resource );
$heightOrig = imagesy ( $this -> resource );
2014-11-05 18:44:19 +03:00
if ( $widthOrig === $heightOrig and $size == 0 ) {
2012-01-01 20:57:26 +04:00
return true ;
}
2014-11-05 18:44:19 +03:00
$ratioOrig = $widthOrig / $heightOrig ;
2013-08-06 18:56:50 +04:00
$width = $height = min ( $widthOrig , $heightOrig );
2012-01-01 20:57:26 +04:00
2013-08-06 18:56:50 +04:00
if ( $ratioOrig > 1 ) {
2014-11-05 18:44:19 +03:00
$x = ( $widthOrig / 2 ) - ( $width / 2 );
2012-01-01 20:57:26 +04:00
$y = 0 ;
} else {
2014-11-05 18:44:19 +03:00
$y = ( $heightOrig / 2 ) - ( $height / 2 );
2012-01-01 20:57:26 +04:00
$x = 0 ;
}
2014-11-05 18:44:19 +03:00
if ( $size > 0 ) {
$targetWidth = $size ;
$targetHeight = $size ;
} else {
$targetWidth = $width ;
$targetHeight = $height ;
2012-03-27 01:53:48 +04:00
}
$process = imagecreatetruecolor ( $targetWidth , $targetHeight );
2012-01-01 20:57:26 +04:00
if ( $process == false ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( 'OC_Image->centerCrop, Error creating true color image' , [ 'app' => 'core' ]);
2012-01-01 20:57:26 +04:00
imagedestroy ( $process );
return false ;
}
2013-02-22 15:42:40 +04:00
// preserve transparency
2014-11-05 18:44:19 +03:00
if ( $this -> imageType == IMAGETYPE_GIF or $this -> imageType == IMAGETYPE_PNG ) {
2013-02-22 15:42:40 +04:00
imagecolortransparent ( $process , imagecolorallocatealpha ( $process , 0 , 0 , 0 , 127 ));
imagealphablending ( $process , false );
imagesavealpha ( $process , true );
}
2013-02-22 20:21:57 +04:00
2012-03-27 01:53:48 +04:00
imagecopyresampled ( $process , $this -> resource , 0 , 0 , $x , $y , $targetWidth , $targetHeight , $width , $height );
2012-01-01 20:57:26 +04:00
if ( $process == false ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( 'OC_Image->centerCrop, Error re-sampling process image ' . $width . 'x' . $height , [ 'app' => 'core' ]);
2012-01-01 20:57:26 +04:00
imagedestroy ( $process );
return false ;
}
2012-03-27 00:28:40 +04:00
imagedestroy ( $this -> resource );
2012-02-10 01:44:26 +04:00
$this -> resource = $process ;
2012-01-01 20:57:26 +04:00
return true ;
}
/**
2014-11-05 18:44:19 +03:00
* Crops the image from point $x $y with dimension $wx $h .
*
* @ param int $x Horizontal position
* @ param int $y Vertical position
* @ param int $w Width
* @ param int $h Height
* @ return bool for success or failure
*/
2018-01-13 02:34:28 +03:00
public function crop ( int $x , int $y , int $w , int $h ) : bool {
2014-11-05 18:44:19 +03:00
if ( ! $this -> valid ()) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): No image loaded' , [ 'app' => 'core' ]);
2012-01-01 20:57:26 +04:00
return false ;
}
$process = imagecreatetruecolor ( $w , $h );
if ( $process == false ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): Error creating true color image' , [ 'app' => 'core' ]);
2012-01-01 20:57:26 +04:00
imagedestroy ( $process );
return false ;
}
2014-07-30 14:16:03 +04:00
// preserve transparency
2014-11-05 18:44:19 +03:00
if ( $this -> imageType == IMAGETYPE_GIF or $this -> imageType == IMAGETYPE_PNG ) {
2014-07-30 14:16:03 +04:00
imagecolortransparent ( $process , imagecolorallocatealpha ( $process , 0 , 0 , 0 , 127 ));
imagealphablending ( $process , false );
imagesavealpha ( $process , true );
}
2012-02-10 01:44:26 +04:00
imagecopyresampled ( $process , $this -> resource , 0 , 0 , $x , $y , $w , $h , $w , $h );
2012-01-01 20:57:26 +04:00
if ( $process == false ) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): Error re-sampling process image ' . $w . 'x' . $h , [ 'app' => 'core' ]);
2012-01-01 20:57:26 +04:00
imagedestroy ( $process );
return false ;
}
2012-03-27 00:28:40 +04:00
imagedestroy ( $this -> resource );
2012-02-10 01:44:26 +04:00
$this -> resource = $process ;
2012-01-01 20:57:26 +04:00
return true ;
}
2012-03-27 00:28:40 +04:00
2012-09-09 01:26:19 +04:00
/**
2014-11-05 18:44:19 +03:00
* Resizes the image to fit within a boundary while preserving ratio .
*
2015-06-06 17:21:36 +03:00
* Warning : Images smaller than $maxWidth x $maxHeight will end up being scaled up
*
2014-02-19 12:31:54 +04:00
* @ param integer $maxWidth
* @ param integer $maxHeight
2014-03-17 11:17:56 +04:00
* @ return bool
2012-09-09 01:26:19 +04:00
*/
public function fitIn ( $maxWidth , $maxHeight ) {
2014-11-05 18:44:19 +03:00
if ( ! $this -> valid ()) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): No image loaded' , [ 'app' => 'core' ]);
2012-09-09 01:26:19 +04:00
return false ;
}
2016-08-22 21:56:59 +03:00
$widthOrig = imagesx ( $this -> resource );
$heightOrig = imagesy ( $this -> resource );
2014-11-05 18:44:19 +03:00
$ratio = $widthOrig / $heightOrig ;
2012-09-09 01:26:19 +04:00
2014-11-05 18:44:19 +03:00
$newWidth = min ( $maxWidth , $ratio * $maxHeight );
$newHeight = min ( $maxHeight , $maxWidth / $ratio );
2012-10-14 23:04:08 +04:00
2018-01-13 02:34:28 +03:00
$this -> preciseResize (( int ) round ( $newWidth ), ( int ) round ( $newHeight ));
2012-09-09 01:26:19 +04:00
return true ;
}
2015-06-06 17:21:36 +03:00
/**
* Shrinks larger images to fit within specified boundaries while preserving ratio .
*
* @ param integer $maxWidth
* @ param integer $maxHeight
* @ return bool
*/
public function scaleDownToFit ( $maxWidth , $maxHeight ) {
2015-06-08 16:10:29 +03:00
if ( ! $this -> valid ()) {
2020-03-26 11:30:18 +03:00
$this -> logger -> error ( __METHOD__ . '(): No image loaded' , [ 'app' => 'core' ]);
2015-06-08 16:10:29 +03:00
return false ;
}
2016-08-22 21:56:59 +03:00
$widthOrig = imagesx ( $this -> resource );
$heightOrig = imagesy ( $this -> resource );
2015-06-06 17:21:36 +03:00
2015-06-08 16:10:29 +03:00
if ( $widthOrig > $maxWidth || $heightOrig > $maxHeight ) {
2015-06-06 17:21:36 +03:00
return $this -> fitIn ( $maxWidth , $maxHeight );
}
return false ;
}
2015-03-13 12:10:11 +03:00
/**
* Destroys the current image and resets the object
*/
2012-09-07 17:22:01 +04:00
public function destroy () {
2014-11-05 18:44:19 +03:00
if ( $this -> valid ()) {
2012-03-27 00:28:40 +04:00
imagedestroy ( $this -> resource );
}
2014-11-05 18:44:19 +03:00
$this -> resource = null ;
2012-03-27 01:53:48 +04:00
}
2012-09-07 17:22:01 +04:00
public function __destruct () {
2012-03-27 01:53:48 +04:00
$this -> destroy ();
2012-03-27 00:28:40 +04:00
}
2012-01-01 20:57:26 +04:00
}
2014-11-05 18:44:19 +03:00
if ( ! function_exists ( 'imagebmp' )) {
2012-11-12 16:56:29 +04:00
/**
* Output a BMP image to either the browser or a file
2014-11-05 18:44:19 +03:00
*
2012-11-12 16:56:29 +04:00
* @ link http :// www . ugia . cn / wp - data / imagebmp . php
* @ author legend < legendsky @ hotmail . com >
* @ link http :// www . programmierer - forum . de / imagebmp - gute - funktion - gefunden - t143716 . htm
* @ author mgutt < marc @ gutt . it >
* @ version 1.00
2016-08-22 21:56:59 +03:00
* @ param resource $im
2014-02-06 19:30:58 +04:00
* @ param string $fileName [ optional ] < p > The path to save the file to .</ p >
2012-11-12 16:56:29 +04:00
* @ param int $bit [ optional ] < p > Bit depth , ( default is 24 ) .</ p >
* @ param int $compression [ optional ]
* @ return bool < b > TRUE </ b > on success or < b > FALSE </ b > on failure .
*/
2014-11-05 18:44:19 +03:00
function imagebmp ( $im , $fileName = '' , $bit = 24 , $compression = 0 ) {
2020-03-26 11:30:18 +03:00
if ( ! in_array ( $bit , [ 1 , 4 , 8 , 16 , 24 , 32 ])) {
2012-11-12 16:56:29 +04:00
$bit = 24 ;
2014-11-05 18:44:19 +03:00
} else if ( $bit == 32 ) {
2012-11-12 16:56:29 +04:00
$bit = 24 ;
}
$bits = pow ( 2 , $bit );
imagetruecolortopalette ( $im , true , $bits );
$width = imagesx ( $im );
$height = imagesy ( $im );
2013-08-06 18:56:50 +04:00
$colorsNum = imagecolorstotal ( $im );
$rgbQuad = '' ;
2012-11-12 16:56:29 +04:00
if ( $bit <= 8 ) {
2013-08-06 18:56:50 +04:00
for ( $i = 0 ; $i < $colorsNum ; $i ++ ) {
2012-11-12 16:56:29 +04:00
$colors = imagecolorsforindex ( $im , $i );
2013-08-06 18:56:50 +04:00
$rgbQuad .= chr ( $colors [ 'blue' ]) . chr ( $colors [ 'green' ]) . chr ( $colors [ 'red' ]) . " \0 " ;
2012-11-12 16:56:29 +04:00
}
2013-08-06 18:56:50 +04:00
$bmpData = '' ;
2012-11-12 16:56:29 +04:00
if ( $compression == 0 || $bit < 8 ) {
$compression = 0 ;
$extra = '' ;
$padding = 4 - ceil ( $width / ( 8 / $bit )) % 4 ;
if ( $padding % 4 != 0 ) {
$extra = str_repeat ( " \0 " , $padding );
}
2014-11-05 18:44:19 +03:00
for ( $j = $height - 1 ; $j >= 0 ; $j -- ) {
2012-11-12 16:56:29 +04:00
$i = 0 ;
while ( $i < $width ) {
$bin = 0 ;
$limit = $width - $i < 8 / $bit ? ( 8 / $bit - $width + $i ) * $bit : 0 ;
for ( $k = 8 - $bit ; $k >= $limit ; $k -= $bit ) {
$index = imagecolorat ( $im , $i , $j );
$bin |= $index << $k ;
$i ++ ;
}
2013-08-06 18:56:50 +04:00
$bmpData .= chr ( $bin );
2012-11-12 16:56:29 +04:00
}
2013-08-06 18:56:50 +04:00
$bmpData .= $extra ;
2012-11-12 16:56:29 +04:00
}
2014-11-05 18:44:19 +03:00
} // RLE8
2012-11-12 16:56:29 +04:00
else if ( $compression == 1 && $bit == 8 ) {
for ( $j = $height - 1 ; $j >= 0 ; $j -- ) {
2013-08-06 18:56:50 +04:00
$lastIndex = " \0 " ;
$sameNum = 0 ;
2012-11-12 16:56:29 +04:00
for ( $i = 0 ; $i <= $width ; $i ++ ) {
$index = imagecolorat ( $im , $i , $j );
2013-08-06 18:56:50 +04:00
if ( $index !== $lastIndex || $sameNum > 255 ) {
if ( $sameNum != 0 ) {
2014-02-27 02:56:46 +04:00
$bmpData .= chr ( $sameNum ) . chr ( $lastIndex );
2012-11-12 16:56:29 +04:00
}
2013-08-06 18:56:50 +04:00
$lastIndex = $index ;
$sameNum = 1 ;
2014-11-05 18:44:19 +03:00
} else {
2013-08-06 18:56:50 +04:00
$sameNum ++ ;
2012-11-12 16:56:29 +04:00
}
}
2013-08-06 18:56:50 +04:00
$bmpData .= " \0 \0 " ;
2012-11-12 16:56:29 +04:00
}
2013-08-06 18:56:50 +04:00
$bmpData .= " \0 \1 " ;
2012-11-12 16:56:29 +04:00
}
2013-08-06 18:56:50 +04:00
$sizeQuad = strlen ( $rgbQuad );
$sizeData = strlen ( $bmpData );
2014-11-05 18:44:19 +03:00
} else {
2012-11-12 16:56:29 +04:00
$extra = '' ;
$padding = 4 - ( $width * ( $bit / 8 )) % 4 ;
if ( $padding % 4 != 0 ) {
$extra = str_repeat ( " \0 " , $padding );
}
2013-08-06 18:56:50 +04:00
$bmpData = '' ;
2012-11-12 16:56:29 +04:00
for ( $j = $height - 1 ; $j >= 0 ; $j -- ) {
for ( $i = 0 ; $i < $width ; $i ++ ) {
2014-11-05 18:44:19 +03:00
$index = imagecolorat ( $im , $i , $j );
2012-11-12 16:56:29 +04:00
$colors = imagecolorsforindex ( $im , $index );
if ( $bit == 16 ) {
$bin = 0 << $bit ;
$bin |= ( $colors [ 'red' ] >> 3 ) << 10 ;
$bin |= ( $colors [ 'green' ] >> 3 ) << 5 ;
$bin |= $colors [ 'blue' ] >> 3 ;
2013-08-06 18:56:50 +04:00
$bmpData .= pack ( " v " , $bin );
2014-11-05 18:44:19 +03:00
} else {
2013-08-06 18:56:50 +04:00
$bmpData .= pack ( " c* " , $colors [ 'blue' ], $colors [ 'green' ], $colors [ 'red' ]);
2012-11-12 16:56:29 +04:00
}
}
2013-08-06 18:56:50 +04:00
$bmpData .= $extra ;
2012-11-12 16:56:29 +04:00
}
2013-08-06 18:56:50 +04:00
$sizeQuad = 0 ;
$sizeData = strlen ( $bmpData );
$colorsNum = 0 ;
}
$fileHeader = 'BM' . pack ( 'V3' , 54 + $sizeQuad + $sizeData , 0 , 54 + $sizeQuad );
$infoHeader = pack ( 'V3v2V*' , 0x28 , $width , $height , 1 , $bit , $compression , $sizeData , 0 , 0 , $colorsNum , 0 );
if ( $fileName != '' ) {
$fp = fopen ( $fileName , 'wb' );
fwrite ( $fp , $fileHeader . $infoHeader . $rgbQuad . $bmpData );
2012-11-12 16:56:29 +04:00
fclose ( $fp );
return true ;
}
2014-11-05 18:44:19 +03:00
echo $fileHeader . $infoHeader . $rgbQuad . $bmpData ;
2012-11-12 16:56:29 +04:00
return true ;
}
}
2014-11-05 18:44:19 +03:00
if ( ! function_exists ( 'exif_imagetype' )) {
2012-11-12 16:56:29 +04:00
/**
* Workaround if exif_imagetype does not exist
2014-11-05 18:44:19 +03:00
*
2012-11-12 16:56:29 +04:00
* @ link http :// www . php . net / manual / en / function . exif - imagetype . php #80383
2014-02-06 19:30:58 +04:00
* @ param string $fileName
2012-11-12 16:56:29 +04:00
* @ return string | boolean
*/
2014-11-05 18:44:19 +03:00
function exif_imagetype ( $fileName ) {
if (( $info = getimagesize ( $fileName )) !== false ) {
2012-11-12 16:56:29 +04:00
return $info [ 2 ];
}
return false ;
}
}