Author: Tobias Schlitt
Date: 2007-02-26 10:08:15 +0100 (Mon, 26 Feb 2007)
New Revision: 4682

Log:
- Implemented issue #9565: Add a thumbnail filter.

Added:
   
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testCropThumbnailHorizontal
   
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testCropThumbnailVertical
   
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testFillThumbnailHorizontal
   
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testFillThumbnailVertical
   
trunk/ImageConversion/tests/data/compare/ezcImageConversionHandlerGdTest_testSaveOldfileNoconvert
   
trunk/ImageConversion/tests/data/compare/ezcImageConversionHandlerTest_testSaveOldfileNoconvert
Modified:
   trunk/ImageConversion/src/handlers/gd.php
   trunk/ImageConversion/tests/filtersgd_test.php

Modified: trunk/ImageConversion/src/handlers/gd.php
===================================================================
--- trunk/ImageConversion/src/handlers/gd.php   2007-02-25 07:30:38 UTC (rev 
4681)
+++ trunk/ImageConversion/src/handlers/gd.php   2007-02-26 09:08:15 UTC (rev 
4682)
@@ -21,7 +21,7 @@
  * @package ImageConversion
  * @access private
  */
-class ezcImageGdHandler extends ezcImageGdBaseHandler implements 
ezcImageGeometryFilters, ezcImageColorspaceFilters, ezcImageWatermarkFilters
+class ezcImageGdHandler extends ezcImageGdBaseHandler implements 
ezcImageGeometryFilters, ezcImageColorspaceFilters, ezcImageWatermarkFilters, 
ezcImageThumbnailFilters
 {
     /**
      * Scale filter.
@@ -369,39 +369,8 @@
             $height = $sourceHeight - $y;
         }
 
-        if ( imageistruecolor( $oldResource ) )
-        {
-            $newResource = imagecreatetruecolor( $width, $height  );
-        }
-        else
-        {
-            $newResource = imagecreate( $width, $height );
-        }
-        
-        // Save transparency, if image has it
-        $bgColor = imagecolorallocatealpha(  $newResource, 255, 255, 255, 127 
);
-        imagealphablending(  $newResource, true );
-        imagesavealpha(  $newResource, true );
-        imagefill(  $newResource, 1, 1, $bgColor );
-        
-        $res = imagecopyresampled(
-            $newResource,           // destination resource 
-            $oldResource,           // source resource
-            0,                      // destination x coord
-            0,                      // destination y coord
-            $x,                     // source x coord
-            $y,                     // source y coord
-            $width,                 // destination width
-            $height,                // destination height
-            $width,                 // source witdh
-            $height                 // source height
-        );
-        if ( $res === false )
-        {
-            throw new ezcImageFilterFailedException( 'crop', 'Resampling of 
image failed.' );
-        }
-        imagedestroy( $oldResource );
-        $this->setActiveResource( $newResource );
+        $this->performCrop( $x, $y, $width, $height );
+
     }
 
     /**
@@ -585,7 +554,112 @@
         // Restore original image reference
         $this->setActiveReference( $originalRef );
     }
+    
+    /**
+     * Creates a thumbnail, and crops parts of the given image to fit the 
range best.
+     * This filter creates a thumbnail of the given image. The image is scaled
+     * down, keeping the original ratio and keeping the image larger as the
+     * given range, if necessary. Overhead for the target range is cropped from
+     * both sides equally.
+     * 
+     * @param int $width  Width of the thumbnail.
+     * @param int $height Height of the thumbnail.
+     */
+    public function croppedThumbnail( $width, $height )
+    {
+        if ( !is_int( $width )  || $width < 1 )
+        {
+            throw new ezcBaseValueException( 'width', $width, 'int > 0' );
+        }
+        if ( !is_int( $height )  || $height < 1 )
+        {
+            throw new ezcBaseValueException( 'height', $height, 'int > 0' );
+        }
+        $resource = $this->getActiveResource();
+        $data[0] = imagesx( $resource );
+        $data[1] = imagesy( $resource );
+        
+        $scaleRatio  = max( $width / $data[0], $height / $data[1] );
+        $scaleWidth  = round( $data[0] * $scaleRatio );
+        $scaleHeight = round( $data[1] * $scaleRatio );
+        
+        $cropOffsetX = ( $scaleWidth > $width )   ? round( ( $scaleWidth - 
$width ) / 2 )   : 0;
+        $cropOffsetY = ( $scaleHeight > $height ) ? round( ( $scaleHeight - 
$height ) / 2 ) : 0;
 
+        $this->performScale( array( "x" => $scaleWidth, "y" => $scaleHeight ) 
);
+        $this->performCrop( $cropOffsetX, $cropOffsetY, $width, $height );
+    }
+
+    /**
+     * Creates a thumbnail, and fills up the image to fit the given range.
+     * This filter creates a thumbnail of the given image. The image is scaled
+     * down, keeping the original ratio and scaling the image smaller as the
+     * given range, if necessary. Overhead for the target range is filled with 
the given
+     * color on both sides equally.
+     *
+     * The color is defined by the following array format (integer values 
0-255):
+     *
+     * <code>
+     * array( 
+     *      0 => <red value>,
+     *      1 => <green value>,
+     *      2 => <blue value>,
+     * );
+     * </code>
+     * 
+     * @param int $width  Width of the thumbnail.
+     * @param int $height Height of the thumbnail.
+     * @param array $color Fill color.
+     *
+     * @return void
+     */
+    public function filledThumbnail( $width, $height, $color = array() )
+    {
+        $i = 0;
+        foreach ( $color as $id => $colorVal )
+        {
+            if ( $i++ > 2 )
+            {
+                break;
+            }
+            if ( !is_int( $colorVal )  || $colorVal < 0 || $colorVal > 255 )
+            {
+                throw new ezcBaseValueException( "color[$id]", $color[$id], 
'int > 0 and < 256' );
+            }
+        }
+        
+        // Sanity checks for $width and $height performed by scale() method.
+        $this->scale( $width, $height, ezcImageGeometryFilters::SCALE_BOTH );
+        
+        $oldResource = $this->getActiveResource();
+
+        $realWidth   = imagesx( $oldResource );
+        $realHeight  = imagesy( $oldResource );
+        $xOffset     = ( $width > $realWidth )   ? round( ( $width - 
$realWidth ) / 2 )   : 0;
+        $yOffset     = ( $height > $realHeight ) ? round( ( $height - 
$realHeight ) / 2 ) : 0;
+
+        $newResource = imagecreatetruecolor( $width, $height );
+        $bgColor     = $this->getColor( $newResource, $color[0], $color[1], 
$color[2] );
+        if ( imagefill( $newResource, 0, 0, $bgColor ) === false )
+        {
+            throw new ezcImageFilterFailedException( "filledThumbnail", "Color 
fill failed." );
+        }
+
+        imagecopy(
+            $newResource,
+            $oldResource,
+            $xOffset,
+            $yOffset,
+            0,
+            0,
+            $realWidth,
+            $realHeight
+        );
+
+        $this->setActiveResource( $newResource );
+        imagedestroy( $oldResource );
+    }
+
     // private
 
     /**
@@ -764,6 +838,7 @@
         {
             return $res;
         }
+        // @TODO Fix filter name to be generic
         throw new ezcImageFilterFailedException( 'colorspace', "Color 
allocation failed for color r: '{$r}', g: '{$g}', b: '{$b}'." );
     }
 
@@ -777,6 +852,8 @@
      *         If no valid resource for the active reference could be found.
      * @throws ezcImageFilterFailedException.
      *         If the operation performed by the the filter failed.
+     *
+     * @todo Change signature, should be ( $width, $height )
      */
     protected function performScale( $dimensions )
     {
@@ -812,5 +889,52 @@
         imagedestroy( $oldResource );
         $this->setActiveResource( $newResource );
     }
+
+    /**
+     * General method to perform a crop operation. 
+     * 
+     * @param int $x 
+     * @param int $y 
+     * @param int $width 
+     * @param int $height 
+     * @return void
+     */
+    private function performCrop( $x, $y, $width, $height )
+    {
+        $oldResource = $this->getActiveResource();
+        if ( imageistruecolor( $oldResource ) )
+        {
+            $newResource = imagecreatetruecolor( $width, $height  );
+        }
+        else
+        {
+            $newResource = imagecreate( $width, $height );
+        }
+        
+        // Save transparency, if image has it
+        $bgColor = imagecolorallocatealpha(  $newResource, 255, 255, 255, 127 
);
+        imagealphablending(  $newResource, true );
+        imagesavealpha(  $newResource, true );
+        imagefill(  $newResource, 1, 1, $bgColor );
+        
+        $res = imagecopyresampled(
+            $newResource,           // destination resource 
+            $oldResource,           // source resource
+            0,                      // destination x coord
+            0,                      // destination y coord
+            $x,                     // source x coord
+            $y,                     // source y coord
+            $width,                 // destination width
+            $height,                // destination height
+            $width,                 // source witdh
+            $height                 // source height
+        );
+        if ( $res === false )
+        {
+            throw new ezcImageFilterFailedException( 'crop', 'Resampling of 
image failed.' );
+        }
+        imagedestroy( $oldResource );
+        $this->setActiveResource( $newResource );
+    }
 }
 ?>

Added: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testCropThumbnailHorizontal
===================================================================
(Binary files differ)


Property changes on: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testCropThumbnailHorizontal
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testCropThumbnailVertical
===================================================================
(Binary files differ)


Property changes on: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testCropThumbnailVertical
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testFillThumbnailHorizontal
===================================================================
(Binary files differ)


Property changes on: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testFillThumbnailHorizontal
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testFillThumbnailVertical
===================================================================
(Binary files differ)


Property changes on: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionFiltersGdTest_testFillThumbnailVertical
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionHandlerGdTest_testSaveOldfileNoconvert
===================================================================
(Binary files differ)


Property changes on: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionHandlerGdTest_testSaveOldfileNoconvert
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionHandlerTest_testSaveOldfileNoconvert
===================================================================
(Binary files differ)


Property changes on: 
trunk/ImageConversion/tests/data/compare/ezcImageConversionHandlerTest_testSaveOldfileNoconvert
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Modified: trunk/ImageConversion/tests/filtersgd_test.php
===================================================================
--- trunk/ImageConversion/tests/filtersgd_test.php      2007-02-25 07:30:38 UTC 
(rev 4681)
+++ trunk/ImageConversion/tests/filtersgd_test.php      2007-02-26 09:08:15 UTC 
(rev 4682)
@@ -606,5 +606,131 @@
             20
         );
     }
+    
+    public function testCropThumbnailVertical()
+    {
+        $this->handler->croppedThumbnail( 50, 50 );
+        $this->handler->save( $this->imageReference, $this->getTempPath() );
+        $this->assertImageSimilar(
+            $this->getReferencePath(),
+            $this->getTempPath(),
+            "Image not rendered as expected.",
+            ezcImageConversionTestCase::DEFAULT_SIMILARITY_GAP
+        );
+    }
+    
+    public function testCropThumbnailHorizontal()
+    {
+        $this->handler->croppedThumbnail( 100, 50 );
+        $this->handler->save( $this->imageReference, $this->getTempPath() );
+        $this->assertImageSimilar(
+            $this->getReferencePath(),
+            $this->getTempPath(),
+            "Image not rendered as expected.",
+            ezcImageConversionTestCase::DEFAULT_SIMILARITY_GAP
+        );
+    }
+    
+    public function testCroppedThumbnailFailures()
+    {
+        try
+        {
+            $this->handler->croppedThumbnail( -10, 50 );
+            $this->fail( "CroppedThumbnail filter accepted incorrect value." );
+        }
+        catch ( ezcBaseValueException $e )
+        {}
+        try
+        {
+            $this->handler->croppedThumbnail( "foo", 50 );
+            $this->fail( "CroppedThumbnail filter accepted incorrect value." );
+        }
+        catch ( ezcBaseValueException $e )
+        {}
+        try
+        {
+            $this->handler->croppedThumbnail( 50, -10 );
+            $this->fail( "CroppedThumbnail filter accepted incorrect value." );
+        }
+        catch ( ezcBaseValueException $e )
+        {}
+        try
+        {
+            $this->handler->croppedThumbnail( 50, false );
+            $this->fail( "CroppedThumbnail filter accepted incorrect value." );
+        }
+        catch ( ezcBaseValueException $e )
+        {}
+    }
+    
+    public function testFillThumbnailVertical()
+    {
+        $this->handler->filledThumbnail( 50, 50, array( 255, 0, 0 ) );
+        $this->handler->save( $this->imageReference, $this->getTempPath() );
+        $this->assertImageSimilar(
+            $this->getReferencePath(),
+            $this->getTempPath(),
+            "Image not rendered as expected.",
+            ezcImageConversionTestCase::DEFAULT_SIMILARITY_GAP
+        );
+    }
+    
+    public function testFillThumbnailHorizontal()
+    {
+        $this->handler->filledThumbnail( 100, 50, array( 255, 0, 0 ) );
+        $this->handler->save( $this->imageReference, $this->getTempPath() );
+        $this->assertImageSimilar(
+            $this->getReferencePath(),
+            $this->getTempPath(),
+            "Image not rendered as expected.",
+            ezcImageConversionTestCase::DEFAULT_SIMILARITY_GAP
+        );
+    }
+    
+    public function testFilledThumbnailFailures()
+    {
+        try
+        {
+            $this->handler->filledThumbnail( -10, 50, array( 255, 0, 0 ) );
+            $this->fail( "FilledThumbnail filter accepted incorrect value." );
+        }
+        catch ( ezcBaseValueException $e )
+        {}
+        try
+        {
+            $this->handler->filledThumbnail( "foo", 50, array( 255, 0, 0 ) );
+            $this->fail( "FilledThumbnail filter accepted incorrect value." );
+        }
+        catch ( ezcBaseValueException $e )
+        {}
+        try
+        {
+            $this->handler->filledThumbnail( 50, -10, array( 255, 0, 0 ) );
+            $this->fail( "FilledThumbnail filter accepted incorrect value." );
+        }
+        catch ( ezcBaseValueException $e )
+        {}
+        try
+        {
+            $this->handler->filledThumbnail( 50, false, array( 255, 0, 0 ) );
+            $this->fail( "FilledThumbnail filter accepted incorrect value." );
+        }
+        catch ( ezcBaseValueException $e )
+        {}
+        try
+        {
+            $this->handler->filledThumbnail( 50, 50, array( 255, false, 0 ) );
+            $this->fail( "FilledThumbnail filter accepted incorrect value." );
+        }
+        catch ( ezcBaseValueException $e )
+        {}
+        try
+        {
+            $this->handler->filledThumbnail( 50, 50, array( "bar", 0, 0 ) );
+            $this->fail( "FilledThumbnail filter accepted incorrect value." );
+        }
+        catch ( ezcBaseValueException $e )
+        {}
+    }
 }
 ?>

-- 
svn-components mailing list
svn-components@lists.ez.no
http://lists.ez.no/mailman/listinfo/svn-components

Reply via email to