| 
<?php
/**
 * Image compression ran tru command line using pngcrush and jpegtran
 *
 * @author Mitchelle Pascual
 */
 class ImageCrusher {
 
 private $imageType;
 private $source;
 private $destination;
 private $crushedFilename;
 
 const TMP_FILENAME_APPEND = '_tmp';
 
 /**
 * pngcrush command statement
 *
 * options:
 * -rem alla
 *     removes all chunks except transparency
 * -brute
 *    tries more than 100 different methods for optimization
 * -reduce
 *    tries to reduce the number of colors if possible
 *
 * @var const
 */
 const PNGCRUSH_CMD = 'pngcrush -rem alla -brute -reduce %s %s';
 
 /**
 * jpegtran command statement
 *
 * options:
 * -rem alla
 * removes all chunks except transparency
 * -brute
 * tries more than 100 different methods for optimization
 * -reduce
 * tries to reduce the number of colors if possible
 *
 * @var const
 */
 const JPEGTRAN_CMD = 'jpegtran -copy none -optimize %s > %s';
 
 /**
 * Constructor
 *
 * @param string $source
 * @param string $destination Empty string will create the temporary optimized image then delete the orginal file and rename it back.
 * @param string $type Empty string will check for the extension filename from $source or $destination.
 */
 public function __construct( $source, $destination = '', $type = '' ) {
 $this->source = $source;
 if( !empty( $destination ) ) {
 $this->destination = $destination;
 }  else {
 $this->crushedFilename = $source . self::TMP_FILENAME_APPEND;
 }
 $this->setImageType( $type );
 }
 
 /**
 * Executes the legitimate image to optimize
 */
 public function crush() {
 self::checkRequirements();
 
 switch( $this->imageType ) {
 case 'png':
 shell_exec( $this->command( self::PNGCRUSH_CMD ) );
 break;
 case 'jpg':
 shell_exec( $this->command( self::JPEGTRAN_CMD ) );
 break;
 default:
 // no image compression for gif images
 break;
 }
 $this->renameTmpToOrigFilename();
 }
 
 /**
 * Renames the temporary compressed image to it's original filename
 */
 protected function renameTmpToOrigFilename() {
 if( !empty( $this->crushedFilename ) ) {
 @unlink(  $this->source );
 @rename( $this->crushedFilename,  $this->source );
 }
 }
 
 /**
 * Set the suitable command line statement
 *
 * @param string $cmdStr
 */
 protected function command( $cmdStr ) {
 if( !empty( $this->crushedFilename ) ) {
 return sprintf( $cmdStr, $this->source, $this->crushedFilename );
 } else {
 return sprintf( $cmdStr, $this->source, $this->destination );
 }
 }
 
 /**
 * Sets the image type or get the extension filename from source or destination
 *
 * @param string $imageType
 */
 protected function setImageType( $imageType ) {
 $type = '';
 if( !empty( $imageType ) ) {
 $type = $imageType;
 } else {
 if( !empty( $this->destination ) ) {
 $filename = $this->destination;
 } else {
 $filename = $this->source;
 }
 $type = strtolower( end( explode( '.' , $filename ) ) );
 }
 $this->imageType = $type;
 }
 
 /**
 * Checks if pngcrush and jpegtran are installed
 *
 * @throws Exception
 */
 public function checkRequirements() {
 //jpegtran is skipped since it always return null
 if( is_null( shell_exec( 'pngcrush ' ) ) ) {
 throw new Exception( 'Please install pngcrush and jpegtran first!' );
 }
 }
 
 /**
 * Boolean requirements check
 */
 public function isRequirementsInstalled() {
 try {
 self::checkRequirements();
 } catch( Exception $e ) {
 return false;
 }
 return true;
 }
 
 /**
 * Batch images compression
 *
 * @param string $directory
 * @param boolean $isRecursive
 */
 public static function batch( $directory, $isRecursive = false ) {
 if( !is_dir( $directory ) ) {
 throw new Exception( 'Directory "' . $directory . '" doesn\'t exist.' );
 }
 self::batchCompress( self::fetchImages( $directory, $isRecursive ) );
 }
 
 /**
 * Gets all png|jpg images from defined directory
 *
 * @param string $directory
 * @param boolean $isRecursive
 */
 protected function fetchImages( $directory, $isRecursive ) {
 $images = array();
 if( $isRecursive === false ) {
 $iterator = new DirectoryIterator( $directory );
 foreach ( $iterator as $fileinfo ) {
 if ( $fileinfo->isFile() && preg_match( '/\.(png|jpg)$/i', $fileinfo->getFilename() ) ) {
 array_push($images, $fileinfo->getPathname() );
 }
 }
 } else {
 $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $directory ) );
 while( $iterator->valid() ) {
 if (!$iterator->isDot() && preg_match( '/\.(png|jpg)$/i', $iterator->current()->getFilename() ) ) {
 array_push($images, $iterator->current()->getPathname() );
 }
 $iterator->next();
 }
 }
 return $images;
 }
 
 /**
 * Does the compression of images
 *
 * @param array $images
 */
 protected function batchCompress( $images ) {
 foreach( $images as $image ) {
 $crusher = new self( $image );
 $crusher->crush();
 }
 }
 
 
 
 
 
 
 
 
 
 
 }
 
 |