EZ-Components

This commit is contained in:
Andreas Österreicher
2009-02-17 15:27:43 +00:00
parent 359c3c55c9
commit 0a8e90a8b3
572 changed files with 64490 additions and 0 deletions
@@ -0,0 +1,354 @@
<?php
/**
* File containing the ezcImageAnalyzer class.
*
* @package ImageAnalysis
* @version 1.1.3
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @filesource
*/
/**
* Class to retreive information about a given image file.
* This class scans the specified image file and leaves the information
* available through the public property {@link ezcImageAnalyzer::$data}.
* The information available depends on the handlers used by the
* ezcImageAnalyzer and the type of image you select. In case the
* ezcImageAnalyzer does not find a suitable handler to analyze an image,
* it will throw a {@link ezcImageAnalyzerFileNotProcessableException}.
*
* In this package the following handlers are available (in their priority
* order):
* - {@link ezcImageAnalyzerImagemagickHandler}, which uses the ImageMagick
* binary "identify" to collect information about an image.
* - {@link ezcImageAnalyzerPhpHandler}, which relies on the GD extension and
* is capable of using the exif extension to determine additional data.
*
* For detailed information on the data provided by these handlers,
* their capabilities on analyzing images and their speciallties, please
* take a look at their documentation. For general information on handlers,
* look at {@link ezcImageAnalyzerHandler},
* {@link ezcImageAnalyzer::getHandlerClasses()} and
* {@link ezcImageAnalyzer::setHandlerClasses()}.
*
* A simple example.
* <code>
* // Analyzation of the MIME type is done during creation.
* $image = new ezcImageAnalyzer( dirname( __FILE__ ).'/toby.jpg' );
*
* if ( $image->mime == 'image/tiff' || $image->mime == 'image/jpeg' )
* {
* // Analyzation of further image data is done during access of the data
* echo 'Photo taken on '.date( 'Y/m/d, H:i', $image->data->date ).".\n";
* }
* elseif ( $mime !== false )
* {
* echo "Format was detected as {$mime}.\n";
* }
* else
* {
* echo "Unknown photo format.\n";
* }
* </code>
*
* If you want to manipulate the handlers used by ezcImageAnalyzer, you can do
* this globally like this:
* <code>
* // Retreive the predefined handler classes
* $originalHandlers = ezcImageAnalyzer::getHandlerClasses();
* foreach ( $handlerClasses as $id => $handlerClass )
* {
* // Unset the ezcImageAnalyzerPhpHandler (do not use that anymore!)
* if ( $handlerClass === 'ezcImageAnalyzerPhpHandler' )
* {
* unset( $handlerClasses[$id] );
* }
* }
* // Set the new collection of handler classes.
* ezcImageAnalyzer::setHandlerClasses( $handlerClasses );
*
* // Somewhere else in the code... This now tries to use your handler in the
* // first place
* $image = new ezcImageAnalyzer( '/var/cache/images/toby.jpg' );
* </code>
*
* Or you can define your own handler classes to be used (beware, those must
* either be already loaded or load automatically on access).
* <code>
* // Define your onw handler class to be used in the first place and fall back on
* // ImageMagick, if necessary.
* $handlerClasses = array( 'MyOwnHandlerClass', 'ezcImageAnalyzerImagemagickHandler' );
* ezcImageAnalyzer::setHandlerClasses( $handlerClasses );
*
* // Somewehre else in the code... This now tries to use your handler in the
* // first place
* $image = new ezcImageAnalyzer( '/var/cache/images/toby.jpg' );
* </code>
*
* @property-read string $mime
* The MIME type of the image.
* @property-read ezcImageAnalyzerData $data
* Extended data about the image.
*
* @package ImageAnalysis
* @version 1.1.3
*/
class ezcImageAnalyzer
{
/**
* The path of the file to analyze.
*
* @var string
*/
protected $filePath;
/**
* Determines whether the image file has been analyzed or not.
* This is used internally.
*
* @var bool
*/
protected $isAnalyzed;
/**
* Container to hold the properties
*
* @var array(string=>mixed)
*/
protected $properties;
/**
* Collection of known handler classes. Classes are ordered by priority.
*
* @var array(string=>mixed)
*/
protected static $knownHandlers = array(
'ezcImageAnalyzerPhpHandler' => array(),
'ezcImageAnalyzerImagemagickHandler' => array(),
);
/**
* Available handler classes and their options.
*
* @var array
*/
protected static $availableHandlers;
/**
* Create an image analyzer for the specified file.
*
* @throws ezcBaseFilePermissionException
* If image file is not readable.
* @throws ezcBaseFileNotFoundException
* If image file does not exist.
* @throws ezcImageAnalyzerFileNotProcessableException
* If the file could not be processed.
* @param string $file The file to analyze.
*/
public function __construct( $file )
{
if ( !file_exists( $file ) || !is_file( $file ) )
{
throw new ezcBaseFileNotFoundException( $file );
}
if ( !is_readable( $file ) )
{
throw new ezcBaseFilePermissionException( $file, ezcBaseFileException::READ );
}
$this->filePath = $file;
$this->isAnalyzed = false;
$this->checkHandlers();
$this->analyzeType();
}
/**
* Check all known handlers for availability.
*
* This method checks all registered handler classes for if the they are
* available (using {@link ezcImageAnalyzerHandler::isAvailable()}).
*
* @throws ezcImageAnalyzerInvalidHandlerException
* If a registered handler class does not exist
* or does not inherit from {@link ezcImageAnalyzerHandler}.
*/
protected function checkHandlers()
{
if ( isset( ezcImageAnalyzer::$availableHandlers ) && is_array( ezcImageAnalyzer::$availableHandlers ) )
{
return;
}
ezcImageAnalyzer::$availableHandlers = array();
foreach ( ezcImageAnalyzer::$knownHandlers as $handlerClass => $options )
{
if ( !ezcBaseFeatures::classExists( $handlerClass ) || !is_subclass_of( $handlerClass, 'ezcImageAnalyzerHandler' ) )
{
throw new ezcImageAnalyzerInvalidHandlerException( $handlerClass );
}
$handler = new $handlerClass( $options );
if ( $handler->isAvailable() )
{
ezcImageAnalyzer::$availableHandlers[] = clone( $handler );
}
}
}
/**
* Returns an array of known handler classes.
*
* This method returns an array of available handler classes. The array is
* indexed by the handler names, which are assigned to an array of options
* set for this handler.
*
* @return array(string=>array(string=>string)) Handlers and options.
*/
public static function getHandlerClasses()
{
return ezcImageAnalyzer::$knownHandlers;
}
/**
* Set the array of known handlers.
*
* Sets the available handlers. The array submitted must be indexed by
* the handler classes names (attention: handler classes must extend
* ezcImageAnalyzerHandler), assigned to an array of options for this
* handler. Most handlers don't have any options. Which options a handler
* may accept depends on the handler implementation.
*
* @param array(string=>array(string=>string)) $handlerClasses Handlers
* and options.
*/
public static function setHandlerClasses( array $handlerClasses )
{
ezcImageAnalyzer::$knownHandlers = $handlerClasses;
ezcImageAnalyzer::$availableHandlers = null;
}
/**
* Sets the property $name to $value.
*
* @throws ezcBasePropertyNotFoundException
* If the property does not exist.
* @throws ezcBasePropertyPermissionException
* If the property cannot be modified.
* @param string $name
* @param mixed $value
* @ignore
*/
public function __set( $name, $value )
{
switch ( $name )
{
case 'mime':
case 'data':
throw new ezcBasePropertyPermissionException( $name, ezcBasePropertyPermissionException::READ );
default:
throw new ezcBasePropertyNotFoundException( $name );
}
}
/**
* Returns the property $name.
*
* @throws ezcBasePropertyNotFoundException
* If the property does not exist.
* @param string $name Name of the property to access.
* @return mixed Value of the desired property.
* @ignore
*/
public function __get( $name )
{
switch ( $name )
{
case 'mime':
return $this->properties['mime'];
case 'data':
if ( !$this->isAnalyzed )
{
$this->analyzeImage();
}
return $this->properties[$name];
default:
throw new ezcBasePropertyNotFoundException( $name );
}
}
/**
* Checks if the property $name exist and returns the result.
*
* @param string $name
* @return bool
* @ignore
*/
public function __isset( $name )
{
switch ( $name )
{
case 'mime':
case 'data':
return true;
default:
return false;
}
}
/**
* Analyze the image file's MIME type.
* This method triggers a handler to analyze the MIME type of the given image file.
*
* @throws ezcImageAnalyzerFileNotProcessableException
* If the no handler is capable to analyze the given image file.
*/
public function analyzeType()
{
if ( !is_array( ezcImageAnalyzer::$availableHandlers ) )
{
$this->checkHandlers();
}
foreach ( ezcImageAnalyzer::$availableHandlers as $handler )
{
if ( ( $mime = $handler->analyzeType( $this->filePath ) ) !== false )
{
$this->properties['mime'] = $mime;
return;
}
}
throw new ezcImageAnalyzerFileNotProcessableException( $this->filePath, "Could not determine MIME type of file." );
}
/**
* Analyze the image file.
*
* This method triggers a handler to analyze the given image file for more data.
*
* @throws ezcImageAnalyzerFileNotProcessableException
* If the no handler is capable to analyze the given image file.
* @throws ezcBaseFileIoException
* If an error occurs while the file is read.
*/
public function analyzeImage()
{
if ( !is_array( ezcImageAnalyzer::$availableHandlers ) )
{
$this->checkHandlers();
}
if ( !isset( $this->properties['mime'] ) )
{
$this->analyzeType();
}
foreach ( ezcImageAnalyzer::$availableHandlers as $handler )
{
if ( $handler->canAnalyze( $this->properties['mime'] ) )
{
$this->properties['data'] = $handler->analyzeImage( $this->filePath );
$this->isAnalyzed = true;
return;
}
}
throw new ezcImageAnalyzerFileNotProcessableException( $this->filePath, "No handler found to analyze MIME type '{$this->mime}'." );
}
}
?>
@@ -0,0 +1,20 @@
<?php
/**
* Base exception for the ImageAnalysis package.
*
* @package ImageAnalysis
* @version 1.1.3
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* General exception container for the ImageAnalysis component.
*
* @package ImageAnalysis
* @version 1.1.3
*/
abstract class ezcImageAnalyzerException extends ezcBaseException
{
}
?>
@@ -0,0 +1,37 @@
<?php
/**
* File containing the ezcImageAnalyzerFileNotProcessableException.
*
* @package ImageAnalysis
* @version 1.1.3
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* The option name you tried to register is already in use.
*
* @package ImageAnalysis
* @version 1.1.3
*/
class ezcImageAnalyzerFileNotProcessableException extends ezcImageAnalyzerException
{
/**
* Creates a new ezcImageAnalyzerFileNotProcessableException.
*
* @param string $file Not processable file.
* @param string $reason Reason that the file is not processable.
* @return void
*/
function __construct( $file, $reason = null )
{
$reasonPart = '';
if ( $reason )
{
$reasonPart = " Reason: $reason.";
}
parent::__construct( "Could not process file '{$file}'.{$reasonPart}" );
}
}
?>
@@ -0,0 +1,31 @@
<?php
/**
* File containing the ezcImageAnalyzerInvalidHandlerException.
*
* @package ImageAnalysis
* @version 1.1.3
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
*/
/**
* A registered handler class does not exist or does not inherit from ezcImageAnalyzerHandler.
*
* @package ImageAnalysis
* @version 1.1.3
*/
class ezcImageAnalyzerInvalidHandlerException extends ezcImageAnalyzerException
{
/**
* Creates a new ezcImageAnalyzerInvalidHandlerException.
*
* @param string $handlerClass Invalid class name.
* @return void
*/
function __construct( $handlerClass )
{
parent::__construct( "The registered handler class '{$handlerClass}' does not exist or does not inherit from ezcImageAnalyzerHandler." );
}
}
?>
@@ -0,0 +1,637 @@
<?php
/**
* File containing the ezcImageAnalyzerImagemagickHandler class.
*
* @package ImageAnalysis
* @version 1.1.3
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @filesource
*/
/**
* Class to retrieve information about a given image file.
* This is an ezcImageAnalyzerHandler that utilizes ImageMagick to analyze
* image files.
*
* This ezcImageAnalyzerHandler can be configured using the
* Option 'binary', which must be set to the full path of the ImageMagick
* "identify" binary. If this option is not submitted to the
* {@link ezcImageAnalyzerHandler::__construct()} method, the handler will
* use just the name of the binary ("identify" on Unix, "identify.exe" on
* Windows).
*
* You can provide the options of the ezcImageAnalyzerImagemagickHandler to
* the {@link ezcImageAnalyzer::setHandlerClasses()}.
*
* @package ImageAnalysis
* @version 1.1.3
*/
class ezcImageAnalyzerImagemagickHandler extends ezcImageAnalyzerHandler
{
/**
* The ImageMagick binary to utilize.
*
* This variable is set during call to
* {@link ezcImageAnalyzerImagemagickHandler::checkImagemagick()}.
*
* @var string
*/
protected $binary;
/**
* Indicates if this handler is available.
*
* The first call to
* {@link ezcImageAnalyzerImagemagickHandler::isAvailable()}
* determines this variable, which is then used as a cache for the call to
* {@link ezcImageAnalyzerImagemagickHandler::checkImagemagick()}.
*
* @var bool
*/
protected $isAvailable;
/**
* Mapping between ImageMagick identification strings and MIME types.
*
* ImageMagick's "identify" command returns an identification string to
* indicate the file type examined.
*
* This map has been handcrafted, because ImageMagick misses the
* possibility to determine MIME types. It misses some identification
* strings (mostly for file types which are absolutely rare in use
* or which ImageMagick is only capable to read or write, but not both.).
*
* @var array(string=>string)
*/
protected $mimeMap = array(
'bmp' => 'image/bmp',
'bmp2' => 'image/bmp',
'bmp3' => 'image/bmp',
'cur' => 'image/x-win-bitmap',
'dcx' => 'image/dcx',
'epdf' => 'application/pdf',
'epi' => 'application/postscript',
'eps' => 'application/postscript',
'eps2' => 'application/postscript',
'eps3' => 'application/postscript',
'epsf' => 'application/postscript',
'epsi' => 'application/postscript',
'ept' => 'application/postscript',
'ept2' => 'application/postscript',
'ept3' => 'application/postscript',
'fax' => 'image/g3fax',
'fits' => 'image/x-fits',
'g3' => 'image/g3fax',
'gif' => 'image/gif',
'gif87' => 'image/gif',
'icb' => 'application/x-icb',
'ico' => 'image/x-win-bitmap',
'icon' => 'image/x-win-bitmap',
'jng' => 'image/jng',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'm2v' => 'video/mpeg2',
'miff' => 'application/x-mif',
'mng' => 'video/mng',
'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg',
'otb' => 'image/x-otb',
'p7' => 'image/x-xv',
'palm' => 'image/x-palm',
'pbm' => 'image/pbm',
'pcd' => 'image/pcd',
'pcds' => 'image/pcd',
'pcl' => 'application/pcl',
'pct' => 'image/pict',
'pcx' => 'image/x-pcx',
'pdb' => 'application/vnd.palm',
'pdf' => 'application/pdf',
'pgm' => 'image/x-pgm',
'picon' => 'image/xpm',
'pict' => 'image/pict',
'pjpeg' => 'image/pjpeg',
'png' => 'image/png',
'png24' => 'image/png',
'png32' => 'image/png',
'png8' => 'image/png',
'pnm' => 'image/pbm',
'ppm' => 'image/x-ppm',
'ps' => 'application/postscript',
'psd' => 'image/x-photoshop',
'ptif' => 'image/x-ptiff',
'ras' => 'image/ras',
'sgi' => 'image/sgi',
'sun' => 'image/ras',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg',
'text' => 'text/plain',
'tga' => 'image/tga',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'txt' => 'text/plain',
'vda' => 'image/vda',
'viff' => 'image/x-viff',
'vst' => 'image/vst',
'wbmp' => 'image/vnd.wap.wbmp',
'xbm' => 'image/x-xbitmap',
'xpm' => 'image/x-xbitmap',
'xv' => 'image/x-viff',
'xwd' => 'image/xwd',
);
/**
* MIME types this handler is capable to read.
*
* This array holds an extract of the
* {@link ezcImageAnalyzerHandler::$mimeMap}, listing all MIME types this
* handler is capable to analyze. The map is indexed by the MIME type,
* assigned to boolean true, to speed up hash lookups.
*
* @var array(string=>bool)
*/
protected $mimeTypes = array(
'application/pcl' => true,
'application/pdf' => true,
'application/postscript' => true,
'application/vnd.palm' => true,
'application/x-icb' => true,
'application/x-mif' => true,
'image/dcx' => true,
'image/g3fax' => true,
'image/gif' => true,
'image/jng' => true,
'image/jpeg' => true,
'image/pbm' => true,
'image/pcd' => true,
'image/pict' => true,
'image/pjpeg' => true,
'image/png' => true,
'image/ras' => true,
'image/sgi' => true,
'image/svg' => true,
'image/tga' => true,
'image/tiff' => true,
'image/vda' => true,
'image/vnd.wap.wbmp' => true,
'image/vst' => true,
'image/x-fits' => true,
'image/x-ms-bmp' => true,
'image/x-otb' => true,
'image/x-palm' => true,
'image/x-pcx' => true,
'image/x-pgm' => true,
'image/x-photoshop' => true,
'image/x-ppm' => true,
'image/x-ptiff' => true,
'image/x-viff' => true,
'image/x-win-bitmap' => true,
'image/x-xbitmap' => true,
'image/x-xv' => true,
'image/xpm' => true,
'image/xwd' => true,
'text/plain' => true,
'video/mng' => true,
'video/mpeg' => true,
'video/mpeg2' => true,
);
/**
* Analyzes the image type.
* This method analyzes image data to determine the MIME type. This method
* returns the MIME type of the file to analyze in lowercase letters (e.g.
* "image/jpeg") or false, if the images MIME type could not be determined.
*
* For a list of image types this handler will be able to analyze, see
* {@link ezcImageAnalyzerImagemagickHandler}.
*
* @param string $file The file to analyze.
* @return string|bool The MIME type if analyzation suceeded or false.
*/
public function analyzeType( $file )
{
$parameters = '-format ' . escapeshellarg( '%m|' ) . ' ' . escapeshellarg( $file );
$res = ezcImageAnalyzerImagemagickHandler::runCommand( $parameters, $outputString, $errorString );
if ( $res !== 0 || $errorString !== '' )
{
return false;
}
$identifiers = explode( '|', strtolower( $outputString ), 2 );
if ( !isset( $this->mimeMap[$identifiers[0]] ) )
{
return false;
}
return $this->mimeMap[$identifiers[0]];
}
/**
* Analyze the image for detailed information.
*
* This may return various information about the image, depending on it's
* type. All information is collected in the struct
* {@link ezcImageAnalyzerData}. At least the
* {@link ezcImageAnalyzerData::$mime} attribute is always available, if the
* image type can be analyzed at all. Additionally this handler will always
* set the {@link ezcImageAnalyzerData::$width},
* {@link ezcImageAnalyzerData::$height} and
* {@link ezcImageAnalyzerData::$size} attributes. For detailes information
* on the additional data returned, see {@link ezcImageAnalyzerImagemagickHandler}.
*
* @todo Why does ImageMagick return the wrong file size on TIFF with comments?
* @todo Check for translucent transparency.
*
* @throws ezcImageAnalyzerFileNotProcessableException
* If image file can not be processed.
* @param string $file The file to analyze.
* @return ezcImageAnalyzerData
*/
public function analyzeImage( $file )
{
// Example strings returned here:
// JPEG (Exif without comment):
// string(45) "[JPEG|76383|399|600|8|59428|DirectClassRGB|]*"
// --------------------------------
// TIFF (Exif with comment):
// string(79) "[TIFF|108125|399|600|8|113524|DirectClassRGB|A simple comment in a TIFF file.]*"
// --------------------------------
// PNG:
// string(46) "[PNG|5420|160|120|8|254|DirectClassRGBMatte|]*"
// --------------------------------
// GIF (Animated):
// string(168) "[GIF|4100|80|50|8|38|PseudoClassRGB|]*[GIF|4100|80|50|8|21|PseudoClassRGB|]*[GIF|4100|80|50|8|17|PseudoClassRGB|Copyright 1996 DeMorgan Industries Corp.
//
// Animated Cog]*"
// --------------------------------
$command = '-format ' . escapeshellarg( '[%m|%b|%w|%h|%k|%r|%c]*' ) . ' ' . escapeshellarg( $file );
// Execute ImageMagick
$return = $this->runCommand( $command, $outputString, $errorString );
if ( $return !== 0 || $errorString !== '' )
{
throw new ezcImageAnalyzerFileNotProcessableException( $file, "ImageMagick error: '{$errorString}'." );
}
$dataStruct = new ezcImageAnalyzerData();
$rawDataArr = explode( '*', $outputString );
if ( sizeof( $rawDataArr ) === 1 )
{
throw new ezcImageAnalyzerFileNotProcessableException( $file, "ImageMagick did not return correct formated string." );
}
// Unset last (empty) element
unset( $rawDataArr[count( $rawDataArr ) - 1] );
if ( sizeof( $rawDataArr ) > 1 )
{
$dataStruct->isAnimated = true;
}
foreach ( $rawDataArr as $id => $rawData )
{
$parsedData = explode( '|', substr( $rawData, 1, -1 ) );
$dataStruct->mime = $this->mimeMap[strtolower( $parsedData[0] )];
$dataStruct->size = filesize( $file );
$dataStruct->width = max( (int) $parsedData[2], $dataStruct->width );
$dataStruct->height = max( (int) $parsedData[3], $dataStruct->height );
$dataStruct->isColor = $parsedData[4] > 2 ? true : false;
$dataStruct->transparencyType = self::TRANSPARENCY_OPAQUE;
if ( strpos( $parsedData[5], 'RGBMatte' ) !== FALSE )
{
$dataStruct->transparencyType = self::TRANSPARENCY_TRANSPARENT;
}
if ( $parsedData[6] !== '' )
{
if ( $dataStruct->isAnimated && $id > 0 )
{
$dataStruct->commentList[] = $parsedData[6];
}
else
{
$dataStruct->comment = $parsedData[6];
$dataStruct->commentList = array( $parsedData[6] );
}
}
if ( $dataStruct->mime === 'image/jpeg' || $dataStruct->mime === 'image/tiff' )
{
$this->analyzeExif( $dataStruct, $file );
}
}
return $dataStruct;
}
/**
* Analyze Exif data contained in JPEG and TIFF images.
*
* This method analyzes the Exif data contained in JPEG and TIFF images,
* using ImageMagick's "identify" binary.
*
* This method tries to provide the EXIF data in a format as close as
* possible to the format returned by ext/EXIF {@link http://php.net/exif}.
*
* @param ezcImageAnalyzerData $data The data object to fill.
* @param string $file The file to analyze.
*/
protected function analyzeExif( ezcImageAnalyzerData $data, $file )
{
$tagMap = array(
"IFD0" => array(
"ImageDescription",
"Make",
"Model",
"Orientation",
"XResolution",
"YResolution",
"ResolutionUnit",
"Software",
"DateTime",
"YCbCrPositioning",
"Exif_IFD_Pointer",
"Copyright",
"UserComment",
),
"EXIF" => array(
"ExposureTime",
"FNumber",
"ExposureProgram",
"ISOSpeedRatings",
"ExifVersion",
"DateTimeOriginal",
"DateTimeDigitized",
"ComponentsConfiguration",
"BrightnessValue",
"ExposureBiasValue",
"MaxApertureValue",
"MeteringMode",
"LightSource",
"Flash",
"FocalLength",
// ImageMagick does not grab this correct, therefore not supported
// "SubjectLocation",
"MakerNote",
"UserComment",
"FlashPixVersion",
"ColorSpace",
"ExifImageWidth",
"ExifImageLength",
"InteroperabilityOffset",
"FileSource",
"SceneType",
"CustomRendered",
"ExposureMode",
"WhiteBalance",
"DigitalZoomRatio",
"FocalLengthIn35mmFilm",
"SceneCaptureType",
"GainControl",
"Contrast",
"Saturation",
"Sharpness",
"SubjectDistanceRange",
),
"INTEROP" => array(
"InterOperabilityIndex",
"InterOperabilityVersion"
)
);
// Retreive exif data
$command = '-format ' . escapeshellarg( "%[EXIF:*]" ) . ' ' . escapeshellarg( $file );
$return = $this->runCommand( $command, $outputString, $errorString, false );
if ( $return !== 0 || $errorString !== '' )
{
throw new ezcImageAnalyzerFileNotProcessableException( $file, "ImageMagick error: '{$errorString}'." );
}
// The following is done in 2 steps to ensure the same array order as ext/exif provides.
// Pre-process data
$rawData = explode( "\n", $outputString );
$dataArr = array();
foreach ( $rawData as $dataString )
{
$dataParts = explode( "=", $dataString, 2 );
if ( sizeof( $dataParts ) === 2 )
{
$dataArr[$dataParts[0]] = substr( $dataParts[1], -1, 1 ) === "." ? substr( $dataParts[1], 0, -1 ) : $dataParts[1];
}
}
// Some post-processing is needed because ext/exif has some different tag names
if ( isset( $dataArr["ExifOffset"] ) )
{
$dataArr["Exif_IFD_Pointer"] = $dataArr["ExifOffset"];
}
if ( isset( $dataArr["InteroperabilityIndex"] ) )
{
$dataArr["InterOperabilityIndex"] = $dataArr["InteroperabilityIndex"];
}
if ( isset( $dataArr["InteroperabilityVersion"] ) )
{
$dataArr["InterOperabilityVersion"] = $dataArr["InteroperabilityVersion"];
}
if ( isset( $dataArr["Artist"] ) )
{
$dataArr["Author"] = $dataArr["Artist"];
}
// Assign data to tags
$exifArr = array();
foreach ( $tagMap as $section => $tags )
{
foreach ( $tags as $tag )
{
if ( isset( $dataArr[$tag] ) )
{
// Correct types
switch ( true )
{
case ( ctype_digit( $dataArr[$tag] ) && stripos( $tag, "version" ) === false ):
$exifArr[$section][$tag] = (int)$dataArr[$tag];
break;
case ( is_numeric( $dataArr[$tag] ) && stripos( $tag, "version" ) === false ):
$exifArr[$section][$tag] = (float)$dataArr[$tag];
break;
default:
$exifArr[$section][$tag] = $dataArr[$tag];
break;
}
}
}
}
// Retreive additional data for computation
$imageData = getimagesize( $file );
$colorCount = 0;
$command = '-format ' . escapeshellarg( '%k' ) . ' ' . escapeshellarg( $file );
$return = $this->runCommand( $command, $colorCount, $errorString );
if ( $return !== 0 || $errorString !== '' )
{
throw new ezcImageAnalyzerFileNotProcessableException( $file, "ImageMagick error: '{$errorString}'." );
}
// Compute additional section ext/EXIF provides
$additionsArr = array();
$addtionsArr["FILE"]["FileName"] = basename( $file );
$addtionsArr["FILE"]["FileDateTime"] = filemtime( $file );
$addtionsArr["FILE"]["FileSize"] = filesize( $file );
$addtionsArr["FILE"]["FileType"] = $imageData[2];
$addtionsArr["FILE"]["MimeType"] = $data->mime;
$addtionsArr["FILE"]["SectionsFound"] =
( isset( $exifArr["EXIF"] ) || isset( $exifArr["IFD0"] ) ? "ANY_TAG, " : "" )
. implode( ", ", array_keys( $exifArr ) );
$addtionsArr["COMPUTED"]["html"] = "width=\"{$data->width}\" height=\"{$data->height}\"";
$addtionsArr["COMPUTED"]["Height"] = $data->height;
$addtionsArr["COMPUTED"]["Width"] = $data->width;
$addtionsArr["COMPUTED"]["IsColor"] = ( $colorCount < 3 ) ? 0 : 1;
// @todo Implement if possible!
// $addtionsArr["COMPUTED"]["ByteOrderMotorola"] = null;
$fNumberParts = isset( $exifArr["EXIF"]["FNumber"] ) ? explode( "/", $exifArr["EXIF"]["FNumber"] ) : null;
if ( sizeof( $fNumberParts ) === 2 )
{
$addtionsArr["COMPUTED"]["ApertureFNumber"] = sprintf( "f/%.1f", $fNumberParts[0] / $fNumberParts[1] );
}
// ImageMagick resturns "..." for not set comments
if ( isset( $exifArr["EXIF"]["UserComment"] ) )
{
$addtionsArr["COMPUTED"]["UserComment"] = preg_match( "/^\.*$/", $exifArr["EXIF"]["UserComment"] ) === false ? $exifArr["EXIF"]["UserComment"] : null;
// @todo Maybe we can determine that somehow?
// $addtionsArr["COMPUTED"]["UserCommentEncoding"] = "UNDEFINED";
}
// Not available through ImageMagick
// $addtionsArr["COMPUTED"]["Thumbnail.FileType"] = null
// $addtionsArr["COMPUTED"]["Thumbnail.MimeType"] = null
// Merge arrays (done here, to have consistent key order)
$data->exif = array_merge( $addtionsArr, $exifArr );
}
/**
* Returns if the handler can analyze a given MIME type.
*
* This method returns if the driver is capable of analyzing a given MIME
* type. This method should be called before trying to actually analyze an
* image using the drivers {@link ezcImageAnalyzerHandler::analyzeImage()}
* method.
*
* @param string $mime The MIME type to check for.
* @return bool True if the handler is able to analyze the MIME type.
*/
public function canAnalyze( $mime )
{
return isset( $this->mimeTypes[strtolower( $mime )] );
}
/**
* Checks wether the GD handler is available on the system.
*
* Returns if PHP's {@link getimagesize()} function is available.
*
* @return bool True is the handler is available.
*/
public function isAvailable()
{
if ( !isset( $this->isAvailable ) )
{
$this->isAvailable = $this->checkImagemagick();
}
return $this->isAvailable;
}
/**
* Checks the availability of ImageMagick on the system.
*
* @return bool
*/
protected function checkImagemagick()
{
if ( !isset( $this->options['binary'] ) )
{
switch ( PHP_OS )
{
case 'Linux':
case 'Unix':
case 'FreeBSD':
case 'MacOS':
case 'Darwin':
case 'SunOS':
$this->binary = 'identify';
break;
case 'Windows':
case 'WINNT':
case 'WIN32':
$this->binary = 'identify.exe';
break;
default:
throw new ezcImageAnalyzerInvalidHandlerException( 'ezcImageAnalyzerImagemagickHandler' );
break;
}
}
else
{
$this->binary = $this->options['binary'];
}
return ezcBaseFeatures::hasImageIdentify();
}
/**
* Run the binary registered in ezcImageAnalyzerImagemagickHandler::$binary.
*
* This method executes the ImageMagick binary using the applied parameter
* string. It returns the return value of the command. The output printed
* to STDOUT and ERROUT is available through the $stdOut and $errOut
* parameters.
*
* @param string $parameters The parameters for the binary to execute.
* @param string $stdOut The standard output.
* @param string $errOut The error output.
* @param bool $stripNewlines Wether to strip the newlines from STDOUT.
* @return int The return value of the command (0 on success).
*/
protected function runCommand( $parameters, &$stdOut, &$errOut, $stripNewlines = true )
{
$command = escapeshellcmd( $this->binary ) . ( $parameters !== '' ? ' ' . $parameters : '' );
// Prepare to run ImageMagick command
$descriptors = array(
array( 'pipe', 'r' ),
array( 'pipe', 'w' ),
array( 'pipe', 'w' ),
);
// Open ImageMagick process
$process = proc_open( $command, $descriptors, $pipes );
// Close STDIN pipe
fclose( $pipes[0] );
// Read STDOUT
$stdOut = '';
do
{
$stdOut .= ( $stripNewlines === true ) ? rtrim( fgets( $pipes[1], 1024), "\n" ) : fgets( $pipes[1], 1024 );
} while ( !feof( $pipes[1] ) );
// Read STDERR
$errOut = '';
do
{
$errOut .= rtrim( fgets( $pipes[2], 1024), "\n" );
} while ( !feof( $pipes[2] ) );
// Wait for process to terminate and store return value
return proc_close( $process );
}
}
?>
@@ -0,0 +1,458 @@
<?php
/**
* File containing the ezcImageAnalyzerPhpHandler class.
*
* @package ImageAnalysis
* @version 1.1.3
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @filesource
*/
/**
* Class to retrieve information about a given image file.
* This handler implements image analyzation using direct PHP functionality,
* mainly the {@link getimagesize()} function and, if available, the EXIF
* extension {@link exif_read_data()}. The driver is capable of determining
* the type the following file formats:
*
* - GIF
* - JPG
* - PNG
* - SWF
* - SWC
* - PSD
* - TIFF
* - BMP
* - IFF
* - JP2
* - JPX
* - JB2
* - JPC
* - XBM
* - WBMP
*
* The driver determines the MIME type of these images (using the
* {@link ezcImageAnalyzerPhpHandler::analyzeType()} method). The width,
* height and size of the given image are always available after analyzing a
* file, if the file in general can be analyzed
* {@link ezcImageAnalyzerPhpHandler::canAnalyze()}.
*
* For JPEG and TIFF images this driver will try to read in information using
* the EXIF extension in PHP and fills in the following properties of the
* {@link ezcImageAnalyzerData} struct, returned by the
* {@link ezcImageAnalyzerPhpHandler::analyzeImage()} method:
* - exif
* - isColor
* - comment
* - copyright
* - date
* - hasThumbnail
* - isAnimated
*
* For GIF (also animated) it finds information by scanning the file manually
* and fills in the following properties of the
* {@link ezcImageAnalyzerData} struct, returned by the
* {@link ezcImageAnalyzerPhpHandler::analyzeImage()} method:
* - mode
* - transparencyType
* - comment
* - commentList
* - colorCount
* - isAnimated
*
* @package ImageAnalysis
* @version 1.1.3
*/
class ezcImageAnalyzerPhpHandler extends ezcImageAnalyzerHandler
{
/**
* Analyzes the image type.
*
* This method analyzes image data to determine the MIME type. This method
* returns the MIME type of the file to analyze in lowercase letters (e.g.
* "image/jpeg") or false, if the images MIME type could not be determined.
*
* For a list of image types this handler will be able to analyze, see
* {@link ezcImageAnalyzerPhpHandler}.
*
* @param string $file The file to analyze.
* @return string|bool The MIME type if analyzation suceeded or false.
*/
public function analyzeType( $file )
{
$data = getimagesize( $file );
if ( $data === false )
{
return false;
}
return image_type_to_mime_type( $data[2] );
}
/**
* Analyze the image for detailed information.
*
* This may return various information about the image, depending on it's
* type. All information is collected in the struct
* {@link ezcImageAnalyzerData}. At least the
* {@link ezcImageAnalyzerData::$mime} attribute is always available, if the
* image type can be analyzed at all. Additionally this handler will always
* set the {@link ezcImageAnalyzerData::$width},
* {@link ezcImageAnalyzerData::$height} and
* {@link ezcImageAnalyzerData::$size} attributes. For detailes information
* on the additional data returned, see {@link ezcImageAnalyzerPhpHandler}.
*
* @throws ezcImageAnalyzerFileNotProcessableException
* If image file can not be processed.
* @param string $file The file to analyze.
* @return ezcImageAnalyzerData
*/
public function analyzeImage( $file )
{
$data = getimagesize( $file );
if ( $data === false )
{
throw new ezcImageAnalyzerFileNotProcessableException( $file, 'getimagesize() returned false.' );
}
$dataStruct = new ezcImageAnalyzerData();
$dataStruct->width = $data[0];
$dataStruct->height = $data[1];
$dataStruct->mime = image_type_to_mime_type( $data[2] );
$dataStruct->size = filesize( $file );
if ( ( $dataStruct->mime === 'image/jpeg' || $dataStruct->mime === 'image/tiff' )
&& ezcBaseFeatures::hasFunction( 'exif_read_data')
)
{
$this->analyzeExif( $file, $dataStruct );
}
elseif ( $dataStruct->mime === 'image/gif' )
{
$this->analyzeGif( $file, $dataStruct );
}
return $dataStruct;
}
/**
* Returns if the handler can analyze a given MIME type.
*
* This method returns if the driver is capable of analyzing a given MIME
* type. This method should be called before trying to actually analyze an
* image using the drivers {@link self::analyzeImage()} method.
*
* @param string $mime The MIME type to check for.
* @return bool True if the handler is able to analyze the MIME type.
*/
public function canAnalyze( $mime )
{
switch ( $mime )
{
case 'image/gif':
case 'image/jpeg':
case 'image/png':
case 'image/psd':
case 'image/bmp':
case 'image/tiff':
case 'image/tiff':
case 'image/jp2':
case 'application/x-shockwave-flash':
case 'image/iff':
case 'image/vnd.wap.wbmp':
case 'image/xbm':
return true;
}
return false;
}
/**
* Checks wether the GD handler is available on the system.
*
* Returns if PHP's {@link getimagesize()} function is available.
*
* @return bool True is the handler is available.
*/
public function isAvailable()
{
return ezcBaseFeatures::hasFunction( 'getimagesize' );
}
/**
* Analyze EXIF enabled file format for EXIF data entries.
*
* The image file is analyzed by calling exif_read_data and placing the
* result in self::exif. In addition it fills in extra properties from
* the EXIF data for easy and uniform access.
*
* @param string $file The file to analyze.
* @param ezcImageAnalyzerData $dataStruct The data struct to fill.
* @return ezcImageAnalyzerData The filled data struct.
*/
private function analyzeExif( $file, ezcImageAnalyzerData $dataStruct )
{
$dataStruct->exif = exif_read_data( $file, "COMPUTED,FILE", true, false );
// Section "COMPUTED"
if ( isset( $dataStruct->exif['COMPUTED']['Width'] ) && isset( $dataStruct->exif['COMPUTED']['Height'] ) )
{
$dataStruct->width = $dataStruct->exif['COMPUTED']['Width'];
$dataStruct->height = $dataStruct->exif['COMPUTED']['Height'];
}
if ( isset( $dataStruct->exif['COMPUTED']['IsColor'] ) )
{
$dataStruct->isColor = $dataStruct->exif['COMPUTED']['IsColor'] == 1;
}
if ( isset( $dataStruct->exif['COMPUTED']['UserComment'] ) )
{
$dataStruct->comment = $dataStruct->exif['COMPUTED']['UserComment'];
$dataStruct->commentList = array( $dataStruct->comment );
}
if ( isset( $dataStruct->exif['COMPUTED']['Copyright'] ) )
{
$dataStruct->copyright = $dataStruct->exif['COMPUTED']['Copyright'];
}
// Section THUMBNAIL
$dataStruct->hasThumbnail = isset( $dataStruct->exif['THUMBNAIL'] );
// Section "FILE"
if ( isset( $dataStruct->exif['FILE']['FileSize'] ) )
{
$dataStruct->size = $dataStruct->exif['FILE']['FileSize'];
}
if ( isset( $dataStruct->exif['FILE']['FileDateTime'] ) )
{
$dataStruct->date = $dataStruct->exif['FILE']['FileDateTime'];
}
// EXIF based image are never animated.
$dataStruct->isAnimated = false;
return $dataStruct;
}
/**
* Analyze GIF files for detailed information.
*
* The GIF file is analyzed by scanning for frame entries, if more than one
* is found it is assumed to be animated.
* It also extracts other information such as image width and height, color
* count, image mode, transparency type and comments.
*
* @throws ezcBaseFileIoException
* If image file could not be read.
* @throws ezcImageAnalyzerFileNotProcessableException
* If image file can not be processed.
* @param string $file The file to analyze.
* @param ezcImageAnalyzerData $dataStruct The data struct to fill.
* @return ezcImageAnalyzerData The filled data struct.
*/
private function analyzeGif( $file, ezcImageAnalyzerData $dataStruct )
{
if ( ( $fp = fopen( $file, 'rb' ) ) === false )
{
throw new ezcBaseFileIoException( $file, ezcBaseFileException::READ );
}
// Read GIF header
$magic = fread( $fp, 6 );
$offset = 6;
if ( $magic != 'GIF87a' &&
$magic != 'GIF89a' )
{
throw new ezcImageAnalyzerFileNotProcessableException( $file, 'Not a valid GIF image file' );
}
$info = array();
$version = substr( $magic, 3 );
$frames = 0;
// Gifs are always indexed
$dataStruct->mode = self::MODE_INDEXED;
$dataStruct->commentList = array();
$dataStruct->transparencyType = self::TRANSPARENCY_OPAQUE;
// Read Logical Screen Descriptor
$data = unpack( "v1width/v1height/C1bitfield/C1index/C1ration", fread( $fp, 7 ) );
$offset += 7;
$lsdFields = $data['bitfield'];
$globalColorCount = 0;
$globalColorTableSize = 0;
if ( $lsdFields >> 7 )
{
// Extract 3 bits for color count
$globalColorCount = ( 1 << ( ( $lsdFields & 0x07 ) + 1) );
// Each color entry is RGB ie. 3 bytes
$globalColorTableSize = $globalColorCount * 3;
}
$dataStruct->colorCount = $globalColorCount;
$dataStruct->width = $data['width'];
$dataStruct->height = $data['height'];
if ( $globalColorTableSize )
{
// Skip the color table, we don't need the data
fseek( $fp, $globalColorTableSize, SEEK_CUR );
$offset += $globalColorTableSize;
}
$done = false;
// Iterate over all blocks and extract information
while ( !$done )
{
$data = fread( $fp, 1 );
$offset += 1;
$blockType = ord( $data[0] );
if ( $blockType == 0x21 ) // Extension Introducer
{
$data .= fread( $fp, 1 );
$offset += 1;
$extensionLabel = ord( $data[1] );
if ( $extensionLabel == 0xf9 ) // Graphical Control Extension
{
$data = unpack( "C1blocksize/C1bitfield/v1delay/C1index/C1term", fread( $fp, 5 + 1 ) );
$gceFlags = $data['bitfield'];//ord( $data[1] );
// $animationTimer is currently not in use.
/* $animationTimer = $data['delay']; */
// Check bit 0
if ( $gceFlags & 0x01 )
{
$dataStruct->transparencyType = self::TRANSPARENCY_TRANSPARENT;
}
$offset += 5 + 1;
}
else if ( $extensionLabel == 0xff ) // Application Extension
{
$data = fread( $fp, 12 );
$offset += 12;
$dataBlockDone = false;
while ( !$dataBlockDone )
{
$data = unpack( "C1blocksize", fread( $fp, 1 ) );
$offset += 1;
$blockBytes = $data['blocksize'];
if ( $blockBytes )
{
// Skip application data, we don't need the data
fseek( $fp, $blockBytes, SEEK_CUR );
$offset += $blockBytes;
}
else
{
$dataBlockDone = true;
}
}
}
else if ( $extensionLabel == 0xfe ) // Comment Extension
{
$commentBlockDone = false;
$comment = false;
while ( !$commentBlockDone )
{
$data = unpack( "C1blocksize", fread( $fp, 1 ) );
$offset += 1;
$blockBytes = $data['blocksize'];
if ( $blockBytes )
{
// Append current block to comment
$data = fread( $fp, $blockBytes );
$comment .= $data;
$offset += $blockBytes;
}
else
{
$commentBlockDone = true;
}
}
if ( $comment )
{
if ( $dataStruct->comment === null )
{
$dataStruct->comment = $comment;
}
$dataStruct->commentList[] = $comment;
}
}
else
{
throw new ezcImageAnalyzerFileNotProcessableException( $file, "Invalid extension label 0x" . hexdec( $extensionLabel ) . " in GIF image." );
}
}
else if ( $blockType == 0x2c ) // Image Descriptor
{
++$frames;
$data .= fread( $fp, 9 );
$data = unpack( "C1separator/v1leftpos/v1toppos/v1width/v1height/C1bitfield", $data );
$localColorTableSize = 0;
$localColorCount = 0;
$idFields = $data['bitfield'];
if ( $idFields >> 7 ) // Local Color Table
{
// Extract 3 bits for color count
$localColorCount = ( 1 << ( ( $idFields & 0x07 ) + 1) );
// Each color entry is RGB ie. 3 bytes
$localColorTableSize = $localColorCount * 3;
}
if ( $localColorCount > $globalColorCount )
{
$dataStruct->colorCount = $localColorCount;
}
if ( $localColorTableSize )
{
// Skip the color table, we don't need the data
fseek( $fp, $localColorTableSize, SEEK_CUR );
$offset += $localColorTableSize;
}
$lzwCodeSize = fread( $fp, 1 ); // LZW Minimum Code Size, currently unused
$offset += 1;
$dataBlockDone = false;
while ( !$dataBlockDone )
{
$data = unpack( "C1blocksize", fread( $fp, 1 ) );
$offset += 1;
$blockBytes = $data['blocksize'];
if ( $blockBytes )
{
// Skip image data, we don't need the data
fseek( $fp, $blockBytes, SEEK_CUR );
$offset += $blockBytes;
}
else
{
$dataBlockDone = true;
}
}
}
else if ( $blockType == 0x3b ) // Trailer, end of stream
{
$done = true;
}
else
{
throw new ezcImageAnalyzerFileNotProcessableException( $file, "Invalid block type 0x" . hexdec( $blockType ) . " in GIF image." );
}
if ( feof( $fp ) )
{
break;
}
}
$dataStruct->isAnimated = $frames > 1;
return $dataStruct;
}
}
?>
@@ -0,0 +1,131 @@
<?php
/**
* File containing the ezcImageAnalyzerHandler class.
*
* @package ImageAnalysis
* @version 1.1.3
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @filesource
*/
/**
* This base class has to be extended by all ezcImageAnalyzerHandler classes.
* An object of an ezcImageAnalyzerHandler class must implement this interface
* to work properly as a handler for ezcImageAnalyzer.
*
* @package ImageAnalysis
* @version 1.1.3
*/
abstract class ezcImageAnalyzerHandler
{
/**
* Image is built with a palette and consists of indexed values per pixel.
*/
const MODE_INDEXED = 1;
/**
* Image consists of RGB value per pixel.
*/
const MODE_TRUECOLOR = 2;
/**
* No parts of image is transparent.
*/
const TRANSPARENCY_OPAQUE = 1;
/*
* Selected palette entries are completely see-through.
*/
const TRANSPARENCY_TRANSPARENT = 2;
/**
* Transparency determined pixel per pixel with a fuzzy value.
*/
const TRANSPARENCY_TRANSLUCENT = 3;
/**
* Options for the handler.
*
* Usually this is empty, but some handlers need special options
* e.g. {@link ezcImageAnalyzerImagemagickHandler}.
*
* @var array(string=>mixed)
*/
protected $options = array();
/**
* Create an ezcImageAnalyzerHandler to analyze a file.
*
* The constructor can optionally receive an array of options. Which
* options are utilized by the handler depends on it's implementation.
* To determine this, please refer to the specific handler.
*
* @throws ezcImageAnalyzerException
* If the handler is not able to work.
* @param array $options Possible options for the handler.
*/
public function __construct( array $options = array() )
{
$this->options = $options;
}
/**
* Checks wether the given handler is available for analyzing images.
*
* Each ezcImageAnalyzerHandler must implement this method in order to
* check if the handler is available on the system. The method has to
* return true, if the handle is currently available to analyze images
* (e.g. if the GD extension is available, for the
* {@link ezcImageAnalyzerPhpHandler}).
*
* @return bool True if the handler is available.
*/
abstract public function isAvailable();
/**
* Analyzes the image type.
*
* This method analyzes image data to determine the MIME type. Each
* ezcImageAnalyzerHandler must at least be capable of performing this
* operation on a file. This method has to return the MIME type of the
* file to analyze in lowercase letters (e.g. "image/jpeg") or false, if
* the images MIME type could not be determined.
*
* @param string $file The file to analyze.
* @return string|bool The MIME type if analyzation suceeded or false.
*/
abstract public function analyzeType( $file );
/**
* Analyze the image for detailed information.
*
* This may return various information about the image, depending on it's
* type and the implemented facilities of the handler. All information is
* collected in the struct {@link ezcImageAnalyzerData}. Which information
* is set about an image in the returned data struct, depends on the image
* type and the capabilities of the handler. At least the
* {@link ezcImageAnalyzerData::$mime} attribute must be set. Most handlers
* also provide additional information like the image dimensions and the size
* of the image file.
*
* @throws ezcImageAnalyzerFileNotProcessableException
* If image file can not be processed.
* @param string $file The file to analyze.
* @return ezcImageAnalyzerData
*/
abstract public function analyzeImage( $file );
/**
* Returns if the handler can analyze a given MIME type.
*
* This method returns if the driver is capable of analyzing a given MIME
* type. This method should be called before trying to actually analyze an
* image using the drivers {@link self::analyzeImage()} method.
*
* @param string $mime The MIME type to check for.
* @return bool True if the handler is able to analyze the MIME type.
*/
abstract public function canAnalyze( $mime );
}
?>
@@ -0,0 +1,221 @@
<?php
/**
* File containing the ezcImageAnalyzerData struct.
*
* @package ImageAnalysis
* @version 1.1.3
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
* @license http://ez.no/licenses/new_bsd New BSD License
* @filesource
*/
/**
* Struct to store the data retrieved from an image analysis.
*
* This class is used as a struct for the data retrieved from
* an {@link ezcImageAnalyzerHandler}. It stores various information about
* an analyzed image and pre-fills it's attributes with sensible default
* values, to make the usage as easy as possible.
*
* Ths struct class should not be accessed directly (except form
* {@link ezcImageAnalyzerHandler} classes, where it is created). From a
* users view it is transparently accessable through
* {@link ezcImageAnalyzer::$data}, more specific using
* <code>
* $analyzer = new ezcImageAnalyzer( 'myfile.jpg' );
* echo $analyzer->data->size;
* </code>
*
* @see ezcImageAnalyzer
* @see ezcImageAnalyzerHandler
*
* @package ImageAnalysis
* @version 1.1.3
*/
class ezcImageAnalyzerData extends ezcBaseStruct
{
/**
* Detected MIME type for the image.
*
* @var string
*/
public $mime;
/**
* EXIF information retrieved from image.
*
* This will only be filled in for images which supports EXIF entries,
* currently they are:
* - image/jpeg
* - image/tiff
*
* @link http://php.net/manual/en/function.exif-read-data.php
*
* @var array(string=>string)
*/
public $exif = array();
/**
* Width of image in pixels.
*
* @var int
*/
public $width = 0;
/**
* Height of image in pixels.
*
* @var int
*/
public $height = 0;
/**
* Size of image file in bytes.
*
* @var int
*/
public $size = 0;
/**
* The image mode.
*
* Can be one of:
* - ezcImageAnalyzerHandler::MODE_INDEXED - Image is built with a palette and consists of
* indexed values per pixel.
* - ezcImageAnalyzerHandler::MODE_TRUECOLOR - Image consists of RGB value per pixel.
*
* @var int
*/
public $mode = ezcImageAnalyzerHandler::MODE_TRUECOLOR;
/**
* Type of transparency in image.
*
* Can be one of:
* - ezcImageAnalyzerHandler::TRANSPARENCY_OPAQUE - No parts of image is transparent.
* - ezcImageAnalyzerHandler::TRANSPARENCY_TRANSPARENT - Selected palette entries are
* completely see-through.
* - ezcImageAnalyzerHandler::TRANSPARENCY_TRANSLUCENT - Transparency determined pixel per
* pixel with a fuzzy value.
*
* @var int
*/
public $transparencyType;
/**
* Does the image have colors?
*
* @var bool
*/
public $isColor = true;
/**
* Number of colors in image.
*
* @var int
*/
public $colorCount = 0;
/**
* First inline comment for the image.
*
* @var string
*/
public $comment = null;
/**
* List of inline comments for the image.
*
* @var array(string)
*/
public $commentList = array();
/**
* Copyright text for the image.
*
* @var string
*/
public $copyright = null;
/**
* The date when the picture was taken as UNIX timestamp.
*
* @var int
*/
public $date;
/**
* Does the image have a thumbnail?
*
* @var bool
*/
public $hasThumbnail = false;
/**
* Is the image animated?
*
* @var bool
*/
public $isAnimated = false;
/**
* Create a new instance of ezcImageAnalyzerData.
*
* Create a new instance of ezcImageAnalyzerData to be used with
* {@link ezcImageAnalyzer} objects.
*
* @see ezcImageAnalyzer::analyzeImage()
* @see ezcImageAnalyzerHandler::analyzeImage()
*
* @param string $mime {@link ezcImageAnalyzerData::$mime}
* @param array $exif {@link ezcImageAnalyzerData::$exif}
* @param int $width {@link ezcImageAnalyzerData::$width}
* @param int $height {@link ezcImageAnalyzerData::$height}
* @param int $size {@link ezcImageAnalyzerData::$size}
* @param int $mode {@link ezcImageAnalyzerData::$mode}
* @param int $transparencyType {@link ezcImageAnalyzerData::$transparencyType}
* @param bool $isColor {@link ezcImageAnalyzerData::$isColor}
* @param int $colorCount {@link ezcImageAnalyzerData::$colorCount}
* @param string $comment {@link ezcImageAnalyzerData::$comment}
* @param array $commentList {@link ezcImageAnalyzerData::$commentList}
* @param string $copyright {@link ezcImageAnalyzerData::$copyright}
* @param int $date {@link ezcImageAnalyzerData::$date}
* @param bool $hasThumbnail {@link ezcImageAnalyzerData::$hasThumbnail}
* @param bool $isAnimated {@link ezcImageAnalyzerData::$isAnimated}
*/
public function __construct(
$mime = null,
$exif = array(),
$width = 0,
$height = 0,
$size = 0,
$mode = ezcImageAnalyzerHandler::MODE_TRUECOLOR,
$transparencyType = null,
$isColor = true,
$colorCount = 0,
$comment = null,
$commentList = array(),
$copyright = null,
$date = null,
$hasThumbnail = false,
$isAnimated = false
)
{
$this->mime = $mime;
$this->exif = $exif;
$this->width = $width;
$this->height = $height;
$this->size = $size;
$this->mode = $mode;
$this->transparencyType = $transparencyType;
$this->isColor = $isColor;
$this->colorCount = $colorCount;
$this->comment = $comment;
$this->commentList = $commentList;
$this->copyright = $copyright;
$this->date = $date;
$this->hasThumbnail = $hasThumbnail;
$this->isAnimated = $isAnimated;
}
}
?>