Apache Zeta Components Manual :: File Source for gd.php
Source for file gd.php
Documentation is available at gd.php
* This file contains the ezcImageGdHandler class.
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* @package ImageConversion
* @version //autogentag//
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* ezcImageHandler implementation for the GD2 extension of PHP, including filters.
* This ezcImageHandler is used when you want to manipulate images using ext/GD
* Note: If you experience problems with loading some JPEG files that work in
* your image viewer, please set the php.ini directive 'gd.jpeg_ignore_warning'
* to true (possible via {@link ini_set()}).
* @package ImageConversion
* @version //autogentag//
* General scale filter. Scales the image to fit into a given box size,
* determined by a given width and height value, measured in pixel. This
* method maintains the aspect ratio of the given image. Depending on the
* given direction value, this method performs the following scales:
* - ezcImageGeometryFilters::SCALE_BOTH:
* The image will be scaled to fit exactly into the given box
* dimensions, no matter if it was smaller or larger as the box
* - ezcImageGeometryFilters::SCALE_DOWN:
* The image will be scaled to fit exactly into the given box
* only if it was larger than the given box dimensions before. If it
* is smaller, the image will not be scaled at all.
* - ezcImageGeometryFilters::SCALE_UP:
* The image will be scaled to fit exactly into the given box
* only if it was smaller than the given box dimensions before. If it
* is larger, the image will not be scaled at all. ATTENTION:
* In this case, the image does not necessarily fit into the given box
* ATTENTION: Using this filter method directly results in the filter being
* applied to the image which is internally marked as "active" (most
* commonly this is the last recently loaded one). It is highly recommended
* to apply filters through the {@link ezcImageGdHandler::applyFilter()} method,
* which enables you to specify the image a filter is applied to.
* @param int $width Scale to width
* @param int $height Scale to height
* @param int $direction Scale to which direction.
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcImageFilterFailedException
* If the operation performed by the the filter failed.
* @throws ezcBaseValueException
* If a submitted parameter was out of range or type.
public function scale( $width, $height, $direction =
ezcImageGeometryFilters::SCALE_BOTH )
if ( !is_int( $width ) ||
$width <
1 )
if ( !is_int( $height ) ||
$height <
1 )
$resource =
$this->getActiveResource();
$oldDim =
array( 'x' =>
imagesx( $resource ), 'y' =>
imagesy( $resource ) );
$widthRatio =
$width /
$oldDim['x'];
$heighRatio =
$height /
$oldDim['y'];
$ratio =
min( $widthRatio, $heighRatio );
$ratio =
$ratio <
1 ?
$ratio :
1;
$ratio =
$ratio >
1 ?
$ratio :
1;
throw
new ezcBaseValueException( 'direction', $direction, 'self::SCALE_BOTH, self::SCALE_UP, self::SCALE_DOWN' );
* Scale after width filter.
* Scales the image to a give width, measured in pixel. Scales the height
* automatically while keeping the ratio. The direction dictates, if an
* image may only be scaled {@link self::SCALE_UP}, {@link self::SCALE_DOWN}
* or if the scale may work in {@link self::SCALE_BOTH} directions.
* ATTENTION: Using this filter method directly results in the filter being
* applied to the image which is internally marked as "active" (most
* commonly this is the last recently loaded one). It is highly recommended
* to apply filters through the {@link ezcImageGdHandler::applyFilter()} method,
* which enables you to specify the image a filter is applied to.
* @param int $width Scale to width
* @param int $direction Scale to which direction
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcImageFilterFailedException
* If the operation performed by the the filter failed.
* @throws ezcBaseValueException
* If a submitted parameter was out of range or type.
if ( !is_int( $width ) ||
$width <
1 )
$resource =
$this->getActiveResource();
'y' =>
$width /
$oldDim['x'] *
$oldDim['y']
'x' =>
max( $width, $oldDim['x'] ),
'y' =>
$width >
$oldDim['x'] ?
round( $width /
$oldDim['x'] *
$oldDim['y'] ) :
$oldDim['y'],
'x' =>
min( $width, $oldDim['x'] ),
'y' =>
$width <
$oldDim['x'] ?
round( $width /
$oldDim['x'] *
$oldDim['y'] ) :
$oldDim['y'],
throw
new ezcBaseValueException( 'direction', $direction, 'self::SCALE_BOTH, self::SCALE_UP, self::SCALE_DOWN' );
* Scale after height filter.
* Scales the image to a give height, measured in pixel. Scales the width
* automatically while keeping the ratio. The direction dictates, if an
* image may only be scaled {@link self::SCALE_UP}, {@link self::SCALE_DOWN}
* or if the scale may work in {@link self::SCALE_BOTH} directions.
* ATTENTION: Using this filter method directly results in the filter being
* applied to the image which is internally marked as "active" (most
* commonly this is the last recently loaded one). It is highly recommended
* to apply filters through the {@link ezcImageGdHandler::applyFilter()} method,
* which enables you to specify the image a filter is applied to.
* @param int $height Scale to height
* @param int $direction Scale to which direction
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcImageFilterFailedException
* If the operation performed by the the filter failed.
* @throws ezcBaseValueException
* If a submitted parameter was out of range or type.
if ( !is_int( $height ) ||
$height <
1 )
$resource =
$this->getActiveResource();
'x' =>
$height /
$oldDim['y'] *
$oldDim['x'],
'x' =>
$height >
$oldDim['y'] ?
round( $height /
$oldDim['y'] *
$oldDim['x'] ) :
$oldDim['x'],
'y' =>
max( $height, $oldDim['y'] ),
'x' =>
$height <
$oldDim['y'] ?
round( $height /
$oldDim['y'] *
$oldDim['x'] ) :
$oldDim['x'],
'y' =>
min( $height, $oldDim['y'] ),
throw
new ezcBaseValueException( 'direction', $direction, 'self::SCALE_BOTH, self::SCALE_UP, self::SCALE_DOWN' );
* Scale percent measures filter.
* Scale an image to a given percentage value size.
* ATTENTION: Using this filter method directly results in the filter being
* applied to the image which is internally marked as "active" (most
* commonly this is the last recently loaded one). It is highly recommended
* to apply filters through the {@link ezcImageGdHandler::applyFilter()} method,
* which enables you to specify the image a filter is applied to.
* @param int $width Scale to width
* @param int $height Scale to height
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcImageFilterFailedException
* If the operation performed by the the filter failed.
* @throws ezcBaseValueException
* If a submitted parameter was out of range or type.
if ( !is_int( $height ) ||
$height <
1 )
if ( !is_int( $width ) ||
$width <
1 )
$resource =
$this->getActiveResource();
* Scale the image to a fixed given pixel size, no matter to which
* ATTENTION: Using this filter method directly results in the filter being
* applied to the image which is internally marked as "active" (most
* commonly this is the last recently loaded one). It is highly recommended
* to apply filters through the {@link ezcImageGdHandler::applyFilter()} method,
* which enables you to specify the image a filter is applied to.
* @param int $width Scale to width
* @param int $height Scale to height
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcBaseValueException
* If a submitted parameter was out of range or type.
if ( !is_int( $height ) ||
$height <
1 )
if ( !is_int( $width ) ||
$width <
1 )
* Crop an image to a given size. This takes cartesian coordinates of a
* rect area to crop from the image. The cropped area will replace the old
* image resource (not the input image immediately, if you use the
* {@link ezcImageConverter}). Coordinates are given as integer values and
* are measured from the top left corner.
* ATTENTION: Using this filter method directly results in the filter being
* applied to the image which is internally marked as "active" (most
* commonly this is the last recently loaded one). It is highly recommended
* to apply filters through the {@link ezcImageGdHandler::applyFilter()} method,
* which enables you to specify the image a filter is applied to.
* @param int $x X offset of the cropping area.
* @param int $y Y offset of the cropping area.
* @param int $width Width of cropping area.
* @param int $height Height of cropping area.
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcImageFilterFailedException
* If the operation performed by the the filter failed.
* @throws ezcBaseValueException
* If a submitted parameter was out of range or type.
public function crop( $x, $y, $width, $height )
$oldResource =
$this->getActiveResource();
$sourceWidth =
imagesx( $oldResource );
$sourceHeight =
imagesy( $oldResource );
$x =
( $x >=
0 ) ?
$x :
$sourceWidth +
$x;
$y =
( $y >=
0 ) ?
$y :
$sourceHeight +
$y;
$x =
abs( min( $x, $x +
$width ) );
$y =
abs( min( $y, $y +
$height ) );
$height =
abs( $height );
if ( $x +
$width >
$sourceWidth )
$width =
$sourceWidth -
$x;
if ( $y +
$height >
$sourceHeight )
$height =
$sourceHeight -
$y;
$this->performCrop( $x, $y, $width, $height );
* Transform the colorspace of the picture. The following colorspaces are
* - {@link self::COLORSPACE_GREY} - 255 grey colors
* - {@link self::COLORSPACE_SEPIA} - Sepia colors
* - {@link self::COLORSPACE_MONOCHROME} - 2 colors black and white
* ATTENTION: Using this filter method directly results in the filter being
* applied to the image which is internally marked as "active" (most
* commonly this is the last recently loaded one). It is highly recommended
* to apply filters through the {@link ezcImageGdHandler::applyFilter()} method,
* which enables you to specify the image a filter is applied to.
* @param int $space Colorspace, one of self::COLORSPACE_* constants.
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcBaseValueException
* If the parameter submitted as the colorspace was not within the
* self::COLORSPACE_* constants.
* @throws ezcImageFilterFailedException
* If the operation performed by the the filter failed.
case self::COLORSPACE_GREY:
case self::COLORSPACE_MONOCHROME:
255 =>
array( 255, 255, 255 ),
case self::COLORSPACE_SEPIA:
throw
new ezcBaseValueException( 'space', $space, 'self::COLORSPACE_GREY, self::COLORSPACE_SEPIA, self::COLORSPACE_MONOCHROME' );
* Places a watermark on the image. The file to use as the watermark image
* is given as $image. The $posX, $posY and $size values are given in
* percent, related to the destination image. A $size value of 10 will make
* the watermark appear in 10% of the destination image size.
* $posX = $posY = 10 will make the watermark appear in the top left corner
* of the destination image, 10% of its size away from its borders. If
* $size is ommitted, the watermark image will not be resized.
* @param string $image The image file to use as the watermark
* @param int $posX X position in the destination image in percent.
* @param int $posY Y position in the destination image in percent.
* @param int|bool$size Percentage size of the watermark, false for none.
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcImageFilterFailedException
* If the operation performed by the the filter failed.
* @throws ezcBaseValueException
* If a submitted parameter was out of range or type.
if ( !is_int( $posX ) ||
$posX <
0 ||
$posX >
100 )
if ( !is_int( $posY ) ||
$posY <
0 ||
$posY >
100 )
if ( !is_bool( $size ) &&
( !is_int( $size ) ||
$size <
0 ||
$size >
100 ) )
$imgWidth =
imagesx( $this->getActiveResource() );
$imgHeight =
imagesy( $this->getActiveResource() );
$watermarkHeight =
false;
$watermarkWidth = (int)
round( $imgWidth *
$size /
100 );
$watermarkHeight = (int)
round( $imgHeight *
$size /
100 );
$watermarkPosX = (int)
round( $imgWidth *
$posX /
100 );
$watermarkPosY = (int)
round( $imgHeight *
$posY /
100 );
$this->watermarkAbsolute( $image, $watermarkPosX, $watermarkPosY, $watermarkWidth, $watermarkHeight );
* Places a watermark on the image. The file to use as the watermark image
* is given as $image. The $posX, $posY and $size values are given in
* pixel. The watermark appear at $posX, $posY in the destination image
* with a size of $size pixel. If $size is ommitted, the watermark image
* @param string $image The image file to use as the watermark
* @param int $posX X position in the destination image in pixel.
* @param int $posY Y position in the destination image in pixel.
* @param int|bool$width Pixel size of the watermark, false to keep size.
* @param int|bool$height Pixel size of the watermark, false to keep size.
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcImageFilterFailedException
* If the operation performed by the the filter failed.
* @throws ezcBaseValueException
* If a submitted parameter was out of range or type.
* @throws ezcImageFileNotProcessableException
* If the given watermark image could not be loaded.
public function watermarkAbsolute( $image, $posX, $posY, $width =
false, $height =
false )
// Backup original image reference
$originalRef =
$this->getActiveReference();
$originalWidth =
imagesx( $this->getActiveResource() );
$originalHeight =
imagesy( $this->getActiveResource() );
$watermarkRef =
$this->load( $image );
if ( $width !==
false &&
$height !==
false &&
( $originalWidth !==
$width ||
$originalHeight !==
$height ) )
$posX =
( $posX >=
0 ) ?
$posX :
$originalWidth +
$posX;
$posY =
( $posY >=
0 ) ?
$posY :
$originalHeight +
$posY;
$this->getReferenceData( $originalRef, "resource" ), // resource $dst_im
$this->getReferenceData( $watermarkRef, "resource" ), // resource $src_im
imagesx( $this->getReferenceData( $watermarkRef, "resource" ) ), // int $src_w
imagesy( $this->getReferenceData( $watermarkRef, "resource" ) ) // int $src_h
$this->close( $watermarkRef );
// 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
* If you are looking for a filter that just resizes your image to
* thumbnail size, you should consider the {@link }
* ezcImageGdHandler::scale()} filter.
* @param int $width Width of the thumbnail.
* @param int $height Height of the thumbnail.
if ( !is_int( $width ) ||
$width <
1 )
if ( !is_int( $height ) ||
$height <
1 )
$resource =
$this->getActiveResource();
$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->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):
* If you are looking for a filter that just resizes your image to
* thumbnail size, you should consider the {@link }
* ezcImageGdHandler::scale()} filter.
* @param int $width Width of the thumbnail.
* @param int $height Height of the thumbnail.
* @param array $color Fill color.
foreach ( $color as $id =>
$colorVal )
if ( !is_int( $colorVal ) ||
$colorVal <
0 ||
$colorVal >
255 )
// Sanity checks for $width and $height performed by scale() method.
$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;
$bgColor =
$this->getColor( $newResource, $color[0], $color[1], $color[2] );
if ( imagefill( $newResource, 0, 0, $bgColor ) ===
false )
$this->setActiveResource( $newResource );
* Retrieve luminance value for a specific pixel.
* @param resource(GD) $resource Image resource
* @param int $x Pixel x coordinate.
* @param int $y Pixel y coordinate.
* @return float Luminance value.
private function getLuminanceAt( $resource, $x, $y )
'r' =>
( $currentColor >>
16 ) & 0xff,
'g' =>
( $currentColor >>
8 ) & 0xff,
'b' =>
$currentColor & 0xff,
return $rgbValues['r'] *
0.299 +
$rgbValues['g'] *
0.587 +
$rgbValues['b'] *
0.114;
* Scale colors by threshold values.
* Thresholds are defined by the following array structures:
* <int threshold value> => array(
* 1 => <int green value>,
* @param array $thresholds
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcImageFilterFailedException
* If the operation performed by the the filter failed.
* @todo Optimization as described here: http://lists.ez.no/pipermail/components/2005-November/000566.html
$resource =
$this->getActiveResource();
$dimensions =
array( 'x' =>
imagesx( $resource ), 'y' =>
imagesy( $resource ) );
// Check for GIFs and convert them to work properly here.
foreach ( $thresholds as $threshold =>
$colors )
array( 'color' =>
$this->getColor( $resource, $colors[0], $colors[1], $colors[2] ) )
if ( !isset
( $thresholds[255] ) )
$thresholds[255] =
end( $thresholds );
for ( $x =
0; $x <
$dimensions['x']; $x++
)
for ( $y =
0; $y <
$dimensions['y']; $y++
)
$luminance =
$this->getLuminanceAt( $resource, $x, $y );
$color =
end( $thresholds );
foreach ( $thresholds as $threshold =>
$colorValues )
if ( $luminance <=
$threshold )
$this->setActiveResource( $resource );
* Perform luminance color scale.
* @param array $scale Array of RGB values (numeric index).
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcImageFilterFailedException
* If the operation performed by the the filter failed
* @todo Optimization as described here: http://lists.ez.no/pipermail/components/2005-November/000566.html
$resource =
$this->getActiveResource();
$dimensions =
array( 'x' =>
imagesx( $resource ), 'y' =>
imagesy( $resource ) );
// Check for GIFs and convert them to work properly here.
for ( $x =
0; $x <
$dimensions['x']; $x++
)
for ( $y =
0; $y <
$dimensions['y']; $y++
)
$luminance =
$this->getLuminanceAt( $resource, $x, $y );
'r' =>
$luminance *
$scale[0],
'g' =>
$luminance *
$scale[1],
'b' =>
$luminance *
$scale[2],
$color =
$this->getColor( $resource, $newRgbValues['r'], $newRgbValues['g'], $newRgbValues['b'] );
$this->setActiveResource( $resource );
* Convert a palette based image resource to a true color one.
* Takes a GD resource that does not represent a true color image and
* converts it to a true color based resource. Do not forget, to replace
* the actual resource in the handler, if you use this ,method!
* @param resource(GD) $resource The image resource to convert
* @param array(string=>int) $dimensions X and Y dimensions.
* @return resource(GD) The converted resource.
imagecopy( $newResource, $resource, 0, 0, 0, 0, $dimensions['x'], $dimensions['y'] );
* Common color determination method.
* Returns a color identifier for an RGB value. Avoids problems with palette images.
* @param reource(GD) $resource The image resource to get a color for.
* @param int $r Red value.
* @param int $g Green value.
* @param int $b Blue value.
* @return int The color identifier.
* @throws ezcImageFilterFailedException
* If the operation performed by the the filter failed.
protected function getColor( $resource, $r, $g, $b )
* General scaling method to perform actual scale to new dimensions.
* @param int $width Width.
* @param int $height Height.
* @throws ezcImageInvalidReferenceException
* If no valid resource for the active reference could be found.
* @throws ezcImageFilterFailedException.
* If the operation performed by the the filter failed.
$oldResource =
$this->getActiveResource();
// Save transparency, if image has it
imagesx( $this->getActiveResource() ),
imagesy( $this->getActiveResource() )
$this->setActiveResource( $newResource );
* General method to perform a crop operation.
private function performCrop( $x, $y, $width, $height )
$oldResource =
$this->getActiveResource();
// Save transparency, if image has it
$newResource, // destination resource
$oldResource, // source resource
0, // destination x coord
0, // destination y coord
$width, // destination width
$height, // destination height
$this->setActiveResource( $newResource );