Friday, August 7, 2015

Image Thumbnail Library - This class is used to create thumbnails

<?php

/**
 * Image Thumbnail Library
 * This class is used to create thumbnails
 *
 * @package Pravin
 * @subpackage thumbnail
 *
 * @since 1.0.0
 */
class Thumbnail {

    /**
     * Is enlargement allowed
     *
     * @var bool
     */
    private $allowEnlargement = false;

    /**
     * The horizontal crop position
     *
     * @var string
     */
    private $cropPositionHorizontal = 'center';

    /**
     * The vertical crop position
     *
     * @var string
     */
    private $cropPositionVertical = 'middle';

    /**
     * The path for the original image
     *
     * @var string
     */
    private $filename;

    /**
     * Should we respect the original aspect ratio?
     *
     * @var bool
     */
    private $forceOriginalAspectRatio = true;

    /**
     * The height for the thumbnail
     *
     * @var int
     */
    private $height;

    /**
     * The image resource
     *
     * @var resource
     */
    private $image;

    /**
     * The width for the thumbnail
     *
     * @var int
     */
    private $width;

    /**
     * The strict setting
     *
     * @var bool
     */
    private $strict = false;

    /**
     * Default set.
     *
     * @return void
     * @param string $filename The path to the source-image.
     * @param int[optional] $width The required width, if not provided it will be calculated based on the height.
     * @param int[optional] $height The required height, if not provided it will be calculated based on the width.
     * @param bool[optional] $strict Should strict-mode be activated?
     */
    public function set($filename, $width = null, $height = null, $strict = true) {
        // check if gd is available
        if (!extension_loaded('gd'))
            return false;

        // redefine vars
        $filename = (string) $filename;
        if ($width != null)
            $width = (int) $width;
        if ($height != null)
            $height = (int) $height;

        // set strict
        $this->strict = (bool) $strict;

        // validate
        if (!self::exists($filename))
            return false;

        // set properties
        $this->filename = $filename;
        $this->width = $width;
        $this->height = $height;
    }

    /**
     * Return the bytes based off the shorthand notation
     * @param int $size
     * @param string $return
     * @return string
     */
    public static function bytes($size, $return = '') {
        if (!is_numeric($size)) {
            $byte = preg_replace('/[^0-9]/i', '', $size);
            $last = strtolower(preg_replace('/[^a-zA-Z]/i', '', $size));

            if ($return == 'byte') {
                return $last;
            }

            switch ($last) {
                case 't': case 'tb': $byte *= 1024;
                case 'g': case 'gb': $byte *= 1024;
                case 'm': case 'mb': $byte *= 1024;
                case 'k': case 'kb': $byte *= 1024;
            }

            $size = $byte;
        }

        if ($return == 'size') {
            return $size;
        }

        $sizes = array('YB', 'ZB', 'EB', 'PB', 'TB', 'GB', 'MB', 'KB', 'B');
        $total = count($sizes);

        while ($total-- && $size > 1024) {
            $size /= 1024;
        }

        $bytes = round($size, 0) . ' ' . $sizes[$total];
        return $bytes;
    }

    /**
     * Check if file is supported.
     *
     * @return bool True if the file is supported, false if not.
     * @param string $filename The path to the file tp check.
     */
    public static function isSupportedFileType($filename) {
        // get watermarkfile properties
        list($width, $height, $type) = @getimagesize($filename);

        // create image from sourcefile
        switch ($type) {
            // gif
            case IMG_GIF:

            // jpg
            case IMG_JPG:

            // png
            case 3:
            case IMG_PNG:
                return true;
                break;

            default:
                return false;
        }
    }

    /**
     * Outputs the image to the browser.
     *
     * @return void
     * @param bool[optional] $headers Should the headers be send? This is a usefull when you're debugging.
     */
    public function parse($headers = true) {
        // get current dimensions
        $imageProperties = @getimagesize($this->filename);

        // validate imageProperties
        if ($imageProperties === false)
            return false;

        // set current dimensions
        $currentWidth = (int) $imageProperties[0];
        $currentHeight = (int) $imageProperties[1];
        $currentType = (int) $imageProperties[2];
        $currentMime = (string) $imageProperties['mime'];

        //get image name
        $x = explode('/', $this->filename);
        $image_name = end($x);

        // set headers
        if ($headers) {
            header("Content-Disposition: filename={$image_name};");
            header("Content-Type: {$currentMime}");
            header('Content-Transfer-Encoding: binary');
            header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT');
        }


        // resize image
        $this->resizeImage($currentWidth, $currentHeight, $currentType, $currentMime);

        // output image
        switch ($currentType) {
            case IMG_GIF:
                imagegif($this->image);
                break;

            case IMG_JPG:
                imagejpeg($this->image, '', 90);
                break;

            case 3:
            case IMG_PNG:
                imagepng($this->image);
                break;

            default:
                break;
        }

        // cleanup the memory
        @imagedestroy($this->image);
    }

    /**
     * Saves the image to a file (quality is only used for jpg images).
     *
     * @return bool True if the image was saved, false if not.
     * @param string $filename The path where the image should be saved.
     * @param int[optional] $quality The quality to use (only applies on jpg-images).
     * @param int[optional] $chmod Mode that should be applied on the file.
     */
    public function parseToFile($filename, $quality = 100, $chmod = 0777) {
        // redefine vars
        $filename = (string) $filename;
        $quality = (int) $quality;

        // get extension
        $extension = self::getExtension($filename);

        // invalid quality
        if (!self::isBetween(1, 100, $quality)) {
            // strict?
            if ($this->strict)
                exit('The quality should be between 1 - 100');
            return false;
        }

        // invalid extension
        if (in_array($extension, array('gif', 'jpeg', 'jpg', 'png')) == false) {
            if ($this->strict)
                exit('Only gif, jpeg, jpg or png are allowed types.');
            return false;
        }

        // get current dimensions
        $imageProperties = @getimagesize($this->filename);

        // validate imageProperties
        if ($imageProperties === false) {
            // strict?
            if ($this->strict)
                exit('The sourcefile "' . $this->filename . '" could not be found.');
            return false;
        }

        // set current dimensions
        $currentWidth = (int) $imageProperties[0];
        $currentHeight = (int) $imageProperties[1];
        $currentType = (int) $imageProperties[2];
        $currentMime = (string) $imageProperties['mime'];

        // file is the same?
        if ($extension == self::getExtension($this->filename) && $currentWidth == $this->width && $currentHeight == $this->height) {
            //copy file
            @copy($this->filename, $filename);
            // chmod
            @chmod($filename, $chmod);
            return true;
        }

        // resize image
        $this->resizeImage($currentWidth, $currentHeight, $currentType, $currentMime);

        // output to file
        switch (strtolower($extension)) {
            case 'gif':
                $return = @imagegif($this->image, $filename);
                break;

            case 'jpeg':
            case 'jpg':
                $return = @imagejpeg($this->image, $filename, $quality);
                break;

            case 'png':
                $return = @imagepng($this->image, $filename);
                break;
        }

        // chmod
        @chmod($filename, $chmod);

        // cleanup memory
        @imagedestroy($this->image);

        // return success
        return (bool) $return;
    }

    /**
     * This internal function will resize/crop the image.
     *
     * @return void
     * @param int $currentWidth Original width.
     * @param int $currentHeight Original height.
     * @param int $currentType Current type of image
     * @param string $currentMime Current mime-type
     */
    private function resizeImage($currentWidth, $currentHeight, $currentType, $currentMime) {
        // check if needed dimensions are present
        if (!$this->forceOriginalAspectRatio)
            $this->resizeImageWithoutForceAspectRatio($currentWidth, $currentHeight, $currentType, $currentMime);

        // FAR is on
        else
            $this->resizeImageWithForceAspectRatio($currentWidth, $currentHeight, $currentType, $currentMime);
    }

    /**
     * Resize the image with Force Aspect Ratio.
     *
     * @return void
     * @param int $currentWidth Original width.
     * @param int $currentHeight Original height.
     * @param int $currentType Current type of image
     * @param string $currentMime Current mime-type
     */
    private function resizeImageWithForceAspectRatio($currentWidth, $currentHeight, $currentType, $currentMime) {
        // current width is larger then current height
        if ($currentWidth > $currentHeight) {
            // width is specified
            if ($this->width !== null) {
                // width is specified
                $newWidth = $this->width;

                // calculate new height
                $newHeight = (int) floor($currentHeight * ($this->width / $currentWidth));
            }

            // height is specified
            elseif ($this->height !== null) {
                // height is specified
                $newHeight = $this->height;

                // calculate new width
                $newWidth = (int) floor($currentWidth * ($this->height / $currentHeight));
            }

            // no dimensions
            else
                return false;
        }

        // current width equals current height
        if ($currentWidth == $currentHeight) {
            // width is specified
            if ($this->width !== null) {
                $newWidth = $this->width;
                $newHeight = $this->width;
            }

            // height is specified
            elseif ($this->height !== null) {
                $newWidth = $this->height;
                $newHeight = $this->height;
            }

            // no dimensions
            else
                return false;
        }

        // current width is smaller then current height
        if ($currentWidth < $currentHeight) {
            // height is specified
            if ($this->height !== null) {
                // height is specified
                $newHeight = $this->height;

                // calculate new width
                $newWidth = (int) floor($currentWidth * ($this->height / $currentHeight));
            }

            // width is specified
            elseif ($this->width !== null) {
                // width is specified
                $newWidth = $this->width;

                // calculate new height
                $newHeight = (int) floor($currentHeight * ($this->width / $currentWidth));
            }

            // no dimensions
            else
                return false;
        }

        // check if we stay within the borders
        if ($this->width !== null && $this->height !== null) {
            if ($newWidth > $this->width) {
                // width is specified
                $newWidth = $this->width;

                // calculate new height
                $newHeight = (int) floor($currentHeight * ($this->width / $currentWidth));
            }

            if ($newHeight > $this->height) {
                // height is specified
                $newHeight = $this->height;

                // calculate new width
                $newWidth = (int) floor($currentWidth * ($this->height / $currentHeight));
            }
        }

        // read current image
        switch ($currentType) {
            case IMG_GIF:
                $currentImage = @imagecreatefromgif($this->filename);
                break;

            case IMG_JPG:
                $currentImage = @imagecreatefromjpeg($this->filename);
                break;

            case 3:
            case IMG_PNG:
                $currentImage = @imagecreatefrompng($this->filename);
                break;

            default:
                break;
        }

        // validate image
        if ($currentImage === false)
            return false;

        // create image resource
        $this->image = @imagecreatetruecolor($newWidth, $newHeight);

        // validate
        if ($this->image === false)
            return false;

        // set transparent
        @imagealphablending($this->image, false);

        // transparency supported
        if (in_array($currentType, array(IMG_GIF, 3, IMG_PNG))) {
            // get transparent color
            $colorTransparent = @imagecolorallocatealpha($this->image, 0, 0, 0, 127);

            // any color found?
            if ($colorTransparent !== false) {
                @imagefill($this->image, 0, 0, $colorTransparent);
                @imagesavealpha($this->image, true);
            }
        }

        // resize
        $success = @imagecopyresampled($this->image, $currentImage, 0, 0, 0, 0, $newWidth, $newHeight, $currentWidth, $currentHeight);

        // image creation fail
        if (!$success) {
            if ($this->strict)
                exit('Something went wrong while trying to resize the image.');
            return false;
        }

        // reset if needed
        if (!$this->allowEnlargement && $currentWidth <= $newWidth && $currentHeight <= $newHeight)
            $this->image = $currentImage;

        // set transparency for GIF, or try to
        if ($currentType == IMG_GIF) {
            // get transparent index
            $transparentIndex = @imagecolortransparent($currentImage);

            // valid index
            if ($transparentIndex > 0) {
                // magic
                $transparentColor = @imagecolorsforindex($currentImage, $transparentIndex);

                // validate transparent color
                if ($transparentColor !== false) {
                    // get color
                    $transparentIndex = @imagecolorallocate($this->image, $transparentColor['red'], $transparentColor['green'], $transparentColor['blue']);

                    // fill
                    if ($transparentIndex !== false) {
                        @imagefill($this->image, 0, 0, $transparentIndex);
                        @imagecolortransparent($this->image, $transparentIndex);
                    }
                }
            }
        }
    }

    /**
     * Resize the image without Force Aspect Ratio.
     *
     * @return void
     * @param int $currentWidth Original width.
     * @param int $currentHeight Original height.
     * @param int $currentType Current type of image
     * @param string $currentMime Current mime-type
     */
    private function resizeImageWithoutForceAspectRatio($currentWidth, $currentHeight, $currentType, $currentMime) {
        // validate
        if ($this->width === null || $this->height === null)
            return false;

        // set new size
        $newWidth = $this->width;
        $newHeight = $this->height;

        // read current image
        switch ($currentType) {
            case IMG_GIF:
                $currentImage = @imagecreatefromgif($this->filename);
                break;

            case IMG_JPG:
                $currentImage = @imagecreatefromjpeg($this->filename);
                break;

            case 3:
            case IMG_PNG:
                $currentImage = @imagecreatefrompng($this->filename);
                break;

            default:
                break;
        }

        // current width is larger then current height
        if ($currentWidth > $currentHeight) {
            $tempHeight = $this->height;
            $tempWidth = (int) floor($currentWidth * ($this->height / $currentHeight));
        }

        // current width equals current height
        if ($currentWidth == $currentHeight) {
            $tempWidth = $this->width;
            $tempHeight = $this->width;
        }

        // current width is smaller then current height
        if ($currentWidth < $currentHeight) {
            $tempWidth = $this->width;
            $tempHeight = (int) floor($currentHeight * ($this->width / $currentWidth));
        }

        // recalculate
        if ($tempWidth < $this->width || $tempHeight < $this->height) {
            // current width is smaller than the current height
            if ($currentWidth < $currentHeight) {
                $tempHeight = $this->height;
                $tempWidth = (int) floor($currentWidth * ($this->height / $currentHeight));
            }

            // current width is greater than the current height
            if ($currentWidth > $currentHeight) {
                $tempWidth = $this->width;
                $tempHeight = (int) floor($currentHeight * ($this->width / $currentWidth));
            }
        }

        // create image resource
        $tempImage = @imagecreatetruecolor($tempWidth, $tempHeight);

        // set transparent
        @imagealphablending($tempImage, false);
        @imagesavealpha($tempImage, true);

        // resize
        $success = @imagecopyresampled($tempImage, $currentImage, 0, 0, 0, 0, $tempWidth, $tempHeight, $currentWidth, $currentHeight);

        // destroy original image
        imagedestroy($currentImage);

        // image creation fail
        if (!$success) {
            if ($this->strict)
                exit('Something went wrong while resizing the image.');
            return false;
        }

        // calculate horizontal crop position
        switch ($this->cropPositionHorizontal) {
            case 'left':
                $x = 0;
                break;

            case 'center':
                $x = (int) floor(($tempWidth - $this->width) / 2);
                break;

            case 'right':
                $x = (int) $tempWidth - $this->width;
                break;
        }

        // calculate vertical crop position
        switch ($this->cropPositionVertical) {
            case 'top':
                $y = 0;
                break;

            case 'middle':
                $y = (int) floor(($tempHeight - $this->height) / 2);
                break;

            case 'bottom':
                $y = (int) $tempHeight - $this->height;
                break;
        }

        // init vars
        $newWidth = $this->width;
        $newHeight = $this->height;

        // validate
        if (!$this->allowEnlargement && ($newWidth > $currentWidth || $newHeight > $currentHeight)) {
            if ($this->strict)
                exit('The specified width/height is larger then the original width/height. Please enable allowEnlargement.');
            return false;
        }

        // create image resource
        $this->image = @imagecreatetruecolor($this->width, $this->height);

        // set transparent
        @imagealphablending($this->image, false);
        $colorTransparent = @imagecolorallocatealpha($this->image, 0, 0, 0, 127);
        @imagefill($this->image, 0, 0, $colorTransparent);
        @imagesavealpha($this->image, true);

        // resize
        $success = @imagecopyresampled($this->image, $tempImage, 0, 0, $x, $y, $newWidth, $newHeight, $newWidth, $newHeight);

        // destroy temp
        @imagedestroy($tempImage);

        // image creation fail
        if (!$success) {
            if ($this->strict)
                exit('Something went wrong while resizing the image.');
            return false;
        }

        // set transparent for GIF
        if ($currentType == IMG_GIF) {
            // get transparent index
            $transparentIndex = @imagecolortransparent($currentImage);

            // valid index
            if ($transparentIndex > 0) {
                // magic
                $transparentColor = @imagecolorsforindex($currentImage, $transparentIndex);
                $transparentIndex = @imagecolorallocate($this->image, $transparentColor['red'], $transparentColor['green'], $transparentColor['blue']);

                // fill
                @imagefill($this->image, 0, 0, $transparentIndex);
                @imagecolortransparent($this->image, $transparentIndex);
            }
        }
    }

    /**
     * set the allowEnlargement, default is false.
     *
     * @return void
     * @param bool[optional] $on May the original image be enlarged.
     */
    public function setAllowEnlargement($on = false) {
        $this->allowEnlargement = (bool) $on;
    }

    /**
     * Sets the horizontal and vertical cropposition.
     *
     * @return mixed In strict-mode it wil return false on errors.
     * @param string[optional] $horizontal The horizontal crop position, possible values are: left, center, right.
     * @param string[optional] $vertical The vertical crop position, possible values are: top, middle, bottom.
     */
    public function setCropPosition($horizontal = 'center', $vertical = 'middle') {
        // redefine vars
        $horizontal = (string) $horizontal;
        $vertical = (string) $vertical;

        // validate horizontal
        if (in_array($horizontal, array('left', 'center', 'right')) == false) {
            if ($this->strict)
                exit('The horizontal crop-position "' . $horizontal . '" isn\'t valid.');
            return false;
        }

        // validte vertical
        if (in_array($vertical, array('top', 'middle', 'bottom')) == false) {
            if ($this->strict)
                exit('The vertical crop-position "' . $vertical . '" isn\'t valid.');
            return false;
        }

        // set properties
        $this->cropPositionHorizontal = $horizontal;
        $this->cropPositionVertical = $vertical;
    }

    /**
     * Enables the Force aspect ratio.
     *
     * @return void
     * @param bool[optional] $on Should the original aspect ratio be respected?
     */
    public function setForceOriginalAspectRatio($on = true) {
        $this->forceOriginalAspectRatio = (bool) $on;
    }

    /**
     * Set the strict option.
     *
     * @return void
     * @param bool[optional] $on Should strict-mode be enabled?
     */
    public function setStrict($on = true) {
        $this->strict = (bool) $on;
    }

    /**
     * Does this file exist.
     *
     * @return bool True if the file exists, false if not.
     * @param string $filename The full path of the file to check for existance.
     */
    public static function exists($filename) {
        return (@file_exists((string) $filename) && is_file((string) $filename));
    }

    /**
     * Fetch the extension for a filename.
     *
     * @return string The extension.
     * @param string $filename The full path of the file.
     * @param bool[optional] $lowercase Should the extension be returned in lowercase or in its original form.
     */
    public static function getExtension($filename, $lowercase = true) {
        // init var
        $filename = ($lowercase) ? strtolower((string) $filename) : (string) $filename;

        // fetch extension
        $aExtension = explode('.', $filename);

        // count the chunks
        $count = count($aExtension);

        // has an extension
        if ($count != 0)
            return $aExtension[$count - 1];

        // no extension
        return '';
    }

    /**
     * Checks if the value is between the minimum and maximum (min & max included).
     *
     * @return bool true if the integer is between the given values, false if not.
     * @param float $minimum The minimum.
     * @param float $maximum The maximum.
     * @param float $value The value to validate.
     */
    public static function isBetween($minimum, $maximum, $value) {
        return ((float) $value >= (float) $minimum && (float) $value <= (float) $maximum);
    }

}

?>

No comments:

Post a Comment