diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5fd3ff0..dcd640b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,4 +14,4 @@ Comments in the code should be written in English. Please follow ImageTools principles: * `Image` object is immutable. -* In case of error methods should always throw exceptions, not errors or warnings. +* Methods should always throw exceptions in case of error. Methods mustn't trigger errors or warnings. diff --git a/README.MD b/README.MD index 30a0128..fb89b10 100644 --- a/README.MD +++ b/README.MD @@ -12,7 +12,7 @@ Add this to the `composer.json` file: ```json "require": { - "aiger-team/image-tools": "1.0.*" + "aiger-team/image-tools": "~1.0.7" } ``` @@ -107,7 +107,7 @@ $resource = imagecreatetruecolor( 100, 150 ); $image = new Image( $resource ); ``` -The resource passed to the constructor become an `Image` object own. So the resource can be modified inside the +The resource passed to the constructor becomes an `Image` object own. So the resource can be modified inside the constructor and the resource will be automatically destroyed on the `Image` object destruction. ### Processing an image @@ -142,7 +142,7 @@ details and the list of all methods. Versions are backward compatible within minor versions. For example versions `1.1.3` and `1.1.5` are backward compatible, but versions `1.1.3` and `1.2.1` may be not compatible. So we advice you to set specific minor version in the composer -configuration, for example `1.0.*`. +configuration, for example `~1.0.7`. ## License diff --git a/src/Image.php b/src/Image.php index 7fe192a..3cd4df9 100755 --- a/src/Image.php +++ b/src/Image.php @@ -4,7 +4,7 @@ use AigerTeam\ImageTools\Exceptions\FileException; -if ( !defined( 'IMAGETYPE_WEBP' ) ) define( 'IMAGETYPE_WEBP', 117 ); +if ( !defined( 'IMAGETYPE_WEBP' )) define( 'IMAGETYPE_WEBP', 117 ); /** * Class Image @@ -17,7 +17,7 @@ * - passing DG resource to the class constructor; * - calling a method of an ImageFactory object. * - * @version 1.0.6 + * @version 1.0.7 * @author Finesse * @author maindefine * @package AigerTeam\ImageTools @@ -60,7 +60,7 @@ class Image protected $isTransparent = false; /** - * @param resource $bitmap Image DG resource. It becomes this object own. So the resource can be modified and it + * @param resource $bitmap Image DG resource. It becomes this object own. So the resource can be modified here. It * will be automatically destroyed on this object destruction. * @param bool $isTransparent Whether image resource has transparent pixels. Not significant argument, it's used * only when output file format is selected. @@ -387,39 +387,30 @@ function rotate( $angle, Array $underlay = null ) */ function setOpacity( $opacity ) { - if ( !is_numeric( $opacity ) ) + if ( !is_numeric( $opacity )) { throw new \InvalidArgumentException( 'Argument $opacity expected to be number, ' . gettype( $opacity ) . ' given.' ); + } $opacity = max( 0, $opacity ); - if ( $opacity == 1 ) + if ( $opacity == 1 ) { return $this; + } - $width = $this->getWidth(); - $height = $this->getHeight(); - $bitmap = static::copyBitmap( $this->bitmap ); - - for ( $x = 0; $x < $width; ++$x ) - for ( $y = 0; $y < $height; ++$y ) { - $color = imagecolorat( $bitmap, $x, $y ); - $transparency = ( $color >> 24 ) & 0x7F; - - if ( $transparency == 127 || $opacity > 1 && $transparency == 0 ) - continue; - - $transparency /= 127; - - if ( $opacity < 1 ) - $transparency = 1 - (1 - $transparency) * $opacity; - else - $transparency = pow( $transparency, $opacity ); + $restLayersOpacity = ceil( $opacity ) - 1; + $firstLayerOpacity = $opacity - $restLayersOpacity; - $color = ( $color & 0xFFFFFF ) | ( (int)round( $transparency * 127 ) << 24 ); - imagesetpixel( $bitmap, $x, $y, $color ); - } + $bitmap = static::copyBitmap( $this->bitmap ); + $transparency = 1 - $firstLayerOpacity; + imagefilter( $bitmap, IMG_FILTER_COLORIZE, 0, 0, 0, 127 * $transparency ); $newImage = static::construct( $bitmap ); $newImage->isTransparent = true; + + for ( $i = 0; $i < $restLayersOpacity; ++$i ) { + $newImage = $newImage->insertImage( $this ); + } + return $newImage; } @@ -1095,11 +1086,13 @@ protected static function imageType2extension( $type, $includeDot = false ) */ protected static function copyBitmap( $bitmap ) { - if ( !is_resource( $bitmap ) ) + if ( !is_resource( $bitmap )) { throw new \InvalidArgumentException( 'Argument $bitmap expected to be resource, ' . gettype( $bitmap ) . 'given.' ); + } - if ( get_resource_type( $bitmap ) !== 'gd' ) + if ( get_resource_type( $bitmap ) !== 'gd' ) { throw new \InvalidArgumentException( 'The resource from the $bitmap argument is not image resource.' ); + } $width = @imagesx( $bitmap ); $height = @imagesy( $bitmap ); @@ -1114,8 +1107,9 @@ protected static function copyBitmap( $bitmap ) @imagealphablending( $bitmap2, false ); $result = @imagecopy( $bitmap2, $bitmap, 0, 0, 0, 0, $width, $height ); - if ( !$bitmap2 || !$result ) + if ( !$bitmap2 || !$result ) { throw new \Exception( 'Can\'t copy image resource. Perhaps not enough RAM.' ); + } return $bitmap2; } diff --git a/src/ImageFactory.php b/src/ImageFactory.php index 7ff4a11..444d310 100644 --- a/src/ImageFactory.php +++ b/src/ImageFactory.php @@ -10,7 +10,7 @@ * * Image factory. Creates images by various ways. * - * @version 1.0.6 + * @version 1.0.7 * @author Finesse * @package AigerTeam\ImageTools */ @@ -75,43 +75,43 @@ public function openFile( $file ) @clearstatcache( true, $file ); // Does file exist? - if ( !file_exists( $file ) || !is_file( $file ) ) + if ( !file_exists( $file ) || !is_file( $file )) throw new FileException( 'Given file doesn\'t exist or not a file.', $file ); // Is it readable? - if ( !is_readable( $file ) ) + if ( !is_readable( $file )) throw new FileException( 'Given file isn\'t readable.', $file ); // Is it image? $size = getimagesize( $file ); - if( $size === false ) - throw new ImageFileException( 'Given file isn\'t image.', $file ); + if ( $size === false ) + throw new ImageFileException( 'Given file isn\'t an image.', $file ); // Retrieve image type $format = strtolower( substr( $size['mime'], strpos( $size['mime'], '/' ) + 1 ) ); - if($format === 'x-ms-bmp') + if ($format === 'x-ms-bmp') $format = 'wbmp'; // Does function that opens this type exist? $func = 'imagecreatefrom' . $format; - if( !function_exists( $func ) ) + if ( !function_exists( $func ) ) throw new ImageFileException( 'Unknown image type.', $file ); // Open image file $bitmap = @$func( $file ); - if( !$bitmap ) + if ( !$bitmap ) throw new ImageFileException( 'Can\'t open image file. Perhaps not enough RAM.', $file ); // Create image object $image = new Image( $bitmap, in_array( $format, Array( 'png', 'gif' ) ) ); // Rotate non-default oriended JPEG - if( + if ( function_exists( 'exif_read_data' ) && - is_array( $exif = @exif_read_data( $file, 0, true ) ) && - isset( $exif[ 'IFD0' ][ 'Orientation' ] ) + is_array( $exif = @exif_read_data( $file, 0, true )) && + isset( $exif[ 'IFD0' ][ 'Orientation' ]) ) { - switch( $exif[ 'IFD0' ][ 'Orientation' ] ) { + switch( $exif[ 'IFD0' ][ 'Orientation' ]) { case 8: $image = $image->rotate( 90 ); break; case 3: $image = $image->rotate( 180 ); break; case 6: $image = $image->rotate( -90 ); break;