<?php
/**
 * Defines Image manipulation for blended Themes.
 *
 * Php GD Image Library.
 *
 * @blended
 */

namespace Blended\hostlib;

use Blended\hostlib\Backend;

if(class_exists('Backend', false)) {
    // Current active user account.
    $backend      = new Backend();
    $account_slug = $backend->getCurrentAccount();
    if (strpos($ACTIVE_THEME, '/')) {
        $theme_slug = explode('/', $ACTIVE_THEME);
        $theme_slug = $theme_slug[count($theme_slug) - 1];
        $src_path = $THEME_DIRECTORY . '/' . $ROOT_DIRECTORY . '/' . $account_slug . '/' . $SOURCE_DIRECTORY . '/' . $theme_slug;
    } else {
        $src_path = '';
    }
}

$lib_path = $THEME_DIRECTORY . '/' . $ROOT_DIRECTORY . '/' . $account_slug . '/' . $DEPENDENCY_PATH . '/' . $ACTIVE_THEME;

file_exists($src_path) ? $image_specif_path = $src_path : $image_specif_path = $lib_path;

class TransformImage
{   
    var $width;
    var $height;
    var $orig_w;
    var $orig_h;
    var $img;
    var $FILTER_MAP;
    var $filter;
    var $backend;
    
    function __construct($image, $width, $height)
    {
        $this->FILTER_MAP = array(
            'monochrome' => function () {
                return $this->monochrome();
            },
            'alphachrome' => function () {
                return $this->alphachrome();
            },
            'warp' => function () {
                return $this->warp();
            },
            'fit' => function () {
                return $this->fit();
            },
            'fill' => function () {
                return $this->fill();
            },
            'resize' => function () {
                return $this->resize();
            },
            'crop' => function ($crop_type = 'center') {
                return $this->crop($crop_type);
            },
            'series' => function () {
                return $this->series();
            }
        );
        
        $this->width  = $width;
        $this->height = $height;
        $this->backend = BD()->backend($image);
        $this->img    = $this->backend->load_image($image);
        if(isset($this->img)) {
            $this->orig_w = imagesx($this->img);
            $this->orig_h = imagesy($this->img);
        }
        if ($width == 0) {
            $this->width = $this->orig_w;
        }
        if ($height == 0) {
            $this->height = $this->orig_h;
        }
    }    
    
    // Applying transformation to image in series.
    function series($filter_series)
    {
        $filter_list = explode(',', $filter_series);
        foreach ($filter_list as $filter) {
            $this->filter = $this->filter . '_' . $filter;
            $value        = $this->preg_grep_keys($filter, $this->FILTER_MAP, $flags = 0);
            if ($value['filter'] === $value['filter_arg']) {
                call_user_func(array($this, $value['filter']));
            } else {
                call_user_func(array($this, $value['filter']), $value['filter_arg']);
            }
            
        }
        
        return $this->img;
    }
    
    // Applying single transformation to image.
    function apply_filter($filter)
    {
        $this->filter = $filter;
        $value        = $this->preg_grep_keys($filter, $this->FILTER_MAP, $flags = 0);

        if ($value['filter'] === $value['filter_arg']) {
            $modified_image = $this->$value['filter']();
        } else {
            $modified_image = $this->$value['filter']($value['filter_arg']);
        }
        
        return $this->img;
    }
    
    // Replacing extra characters from filter list.
    function preg_grep_keys($pattern, $input, $flags = 0)
    {
        $filter = preg_replace('/[^a-zA-Z ][(a-zA-Z0-9#)]+/', '', $pattern);
        
        $filter_arg_tmp = preg_replace('/' . $filter . '[(]+/', '', $pattern);
        $filter_arg     = preg_replace("/[)]/", "", $filter_arg_tmp);
        
        $filter_and_type = array(
            'filter' => trim($filter),
            'filter_arg' => trim($filter_arg)
        );
        return $filter_and_type;
    }
    
    function monochrome($hex = '#FFF0C0')
    {

        $hex = str_replace("#", "", $hex);
        if (strlen($hex) == 3) {
            $hex_r = hexdec(substr($hex, 0, 1) . substr($hex, 0, 1));
            $hex_g = hexdec(substr($hex, 1, 1) . substr($hex, 1, 1));
            $hex_b = hexdec(substr($hex, 2, 1) . substr($hex, 2, 1));
        } else {
            $hex_r = hexdec(substr($hex, 0, 2));
            $hex_g = hexdec(substr($hex, 2, 2));
            $hex_b = hexdec(substr($hex, 4, 2));
        }
        
        $newColor = array(
            $hex_r,
            $hex_g,
            $hex_b
        );
       
        imagefilter($this->img, true, IMG_FILTER_GRAYSCALE);
        imagefilter($this->img, IMG_FILTER_CONTRAST, 255);
        $this->orig_w = imagesx($this->img);
        $this->orig_h = imagesy($this->img);
    }
    
    function alphachrome($hex = '#3377FF')
    {   
        $hex = str_replace("#", "", $hex);
        if (strlen($hex) == 3) {
            $hex_r = hexdec(substr($hex, 0, 1) . substr($hex, 0, 1));
            $hex_g = hexdec(substr($hex, 1, 1) . substr($hex, 1, 1));
            $hex_b = hexdec(substr($hex, 2, 1) . substr($hex, 2, 1));
        } else {
            $hex_r = hexdec(substr($hex, 0, 2));
            $hex_g = hexdec(substr($hex, 2, 2));
            $hex_b = hexdec(substr($hex, 4, 2));
        }
        
        $newColor = array(
            $hex_r,
            $hex_g,
            $hex_b
        );
        
        // Work through pixels
        for ($y = 0; $y < $this->orig_h; $y++) {
            for ($x = 0; $x < $this->orig_w; $x++) {
                // Apply new color + Alpha
                $rgb = imagecolorsforindex($this->img, imagecolorat($this->img, $x, $y));
                
                $transparent = imagecolorallocatealpha($this->img, 0, 0, 0, 127);
                imagesetpixel($this->img, $x, $y, $transparent);
                
                
                // Here, you would make your color transformation.
                $red_set   = $newColor[0];
                $green_set = $newColor[1];
                $blue_set  = $newColor[2];
                if ($red_set > 255) {
                    $red_set = 255;
                }
                if ($green_set > 255) {
                    $green_set = 255;
                }
                if ($blue_set > 255) {
                    $blue_set = 255;
                }
                
                $pixelColor = imagecolorallocatealpha($this->img, $red_set, $green_set, $blue_set, $rgb['alpha']);
                imagesetpixel($this->img, $x, $y, $pixelColor);
            }
        }
        
        // Restore Alpha
        imageAlphaBlending($this->img, true);
        imageSaveAlpha($this->img, true);
        
        /*** thumb updation starts here  ***/
        
        $bottom = false;
        $width  = imagesx($this->img);
        $height = imagesy($this->img);
        
        $thumbHeight = $bottom != false ? $height * 2 : $height;
        
        // Create Transparent PNG
        $thumb       = imagecreatetruecolor($width, $thumbHeight);
        $transparent = imagecolorallocatealpha($thumb, 0, 0, 0, 127);
        imagefill($thumb, 0, 0, $transparent);
        
        // Copy Top Image
        imagecopy($thumb, $this->img, 0, 0, 0, 0, $width, $height);
        
        // Copy Bottom Image
        if ($bottom != false) {
            imagecopy($thumb, $bottom, 0, $height, 0, 0, $width, $height);
        }
        
        // Save Image with Alpha
        imageAlphaBlending($thumb, true);
        imageSaveAlpha($thumb, true);
        
        $this->img = $thumb;
        $this->orig_w = imagesx($this->img);
        $this->orig_h = imagesy($this->img);
    }
    
    // applies wrap effect to image.
    function warp()
    {
        $ratio_w = ($this->width)/($this->orig_w);
        $ratio_h = ($this->height)/($this->orig_h);
        $thumb = imagecreatetruecolor($this->orig_w*$ratio_w, $this->orig_h*$ratio_h);
        imagecopyresized($thumb, $this->img, 0, 0, 0, 0, $this->orig_w*$ratio_w, $this->orig_h*$ratio_h, $this->orig_w, $this->orig_h);
        $this->img = $thumb;
        $this->orig_w = imagesx($this->img);
        $this->orig_h = imagesy($this->img);
    }
 
    // fit image with the given canvas.
    function fit()
    {
        if ($this->orig_w / $this->width > $this->orig_h / $this->height) {
            $ratio = $this->width / $this->orig_w;
        } else {
            $ratio = $this->height / $this->orig_h;
        }
        $thumb = imagecreatetruecolor($this->orig_w * $ratio, $this->orig_h * $ratio);
        imagecopyresized($thumb, $this->img, 0, 0, 0, 0, $this->orig_w * $ratio, $this->orig_h * $ratio, $this->orig_w, $this->orig_h);
        $this->img = $thumb;
        $this->orig_w = imagesx($this->img);
        $this->orig_h = imagesy($this->img);
    }

    // fill image with the given canvas.
    function fill()
    {
        if ($this->orig_w / $this->width < $this->orig_h / $this->height) {
            $ratio = $this->width / $this->orig_w;
        } else {
            $ratio = $this->height / $this->orig_h;
        }
        $thumb = imagecreatetruecolor($this->orig_w * $ratio, $this->orig_h * $ratio);
        imagecopyresized($thumb, $this->img, 0, 0, 0, 0, $this->orig_w * $ratio, $this->orig_h * $ratio, $this->orig_w, $this->orig_h);
        $this->img = $thumb;
        $this->orig_w = imagesx($this->img);
        $this->orig_h = imagesy($this->img);
    }

    // resize height, width of image with the new canvas size.
    function resize($percent = 100)
    {
        
        /*
                    if (self.w/self.width < self.h/self.height):
                        diff = abs(self.width-self.w)*percent/100.0
                        ratio = (self.width+diff)/self.w
                    else:
                        diff = abs(self.height-self.h)*percent/100.0
                        ratio = (1.0*self.height+diff)/(self.h*1.0)

                    self.image = self.image.resize((int(self.w*ratio),int(self.h*ratio),))
                    self.w, self.h = self.image.size[0]*1.0, self.image.size[1]*1.0
        */
        
        if ($this->orig_w / $this->width < $this->orig_h / $this->height) {
            $diff  = abs($this->width - $this->orig_w) * $percent / 100.0;
            $ratio = ($this->width + $diff) / $this->orig_w;
        } else {
            $diff  = abs($this->height - $this->orig_h) * $percent / 100.0;
            $ratio = ($this->height + $diff) / $this->orig_h;
        }
        
        $thumb = imagecreatetruecolor($this->orig_w * $ratio, $this->orig_h * $ratio);
        // imagecopyresized($thumb, $this->img, 0, 0, 0, 0, $this->orig_w * $ratio, $this->orig_h * $ratio, $this->orig_w, $this->orig_h);
        $this->img = $thumb;
        $this->orig_w = imagesx($this->img);
        $this->orig_h = imagesy($this->img);
    }

    // crop a portion of the image.
    function crop($crop_type = 'center')
    {
        global $CUT_SIZE;
        // builds cropbox size of bounding box in center of image
        if ($crop_type == 'center') {            

            $thumb_im = imagecreatetruecolor($this->width, $this->height);
            if($this->orig_w > $this->width) {             
                $crop_w   = ($this->orig_w - $this->width) / 2;
                $crop_h   = ($this->orig_h - $this->height) / 2;

                if($this->orig_h < $this->height) {
                    $crop_h   = ($this->height - $this->orig_h) / 2;
                }

                $cropbox  = array(
                    'x' => $crop_w,
                    'y' => $crop_h,
                    'width' => ($crop_w + $this->width),
                    'height' => ($crop_h + $this->height)
                );

                imagecopy($thumb_im, $this->img, 0, 0, $crop_w, $crop_h, $cropbox['width'], $cropbox['height']);

            } else {
                $crop_w   = ($this->width - $this->orig_w) / 2;
                $crop_h   = ($this->height - $this->orig_h) / 2;

                if($this->orig_h > $this->height) {
                    $crop_h   = ($this->orig_h - $this->height) / 2;
                }

                $cropbox  = array(
                    'x' => $crop_w,
                    'y' => $crop_h,
                    'width' => ($crop_w + $this->width),
                    'height' => ($crop_h + $this->height)
                );
                imagecopy($thumb_im, $this->img, 0, 0, 0, $cropbox['height'], $cropbox['width'], $cropbox['height']);
            }
        


        }
        // builds cropbox size of bounding box on top left of image
        else if ($crop_type == 'top-left') {
            $cropbox  = array(
                'x' => 0,
                'y' => 0,
                'width' => $this->width,
                'height' => $this->height
            );
            $thumb_im = imagecreatetruecolor($this->width, $this->height);
            imagecopy($thumb_im, $this->img, 0, 0, 0, 0, $this->width, $this->height);
        }
        // builds cropbox size of bounding box on bottom right of image
        else if ($crop_type == 'bottom-right') {

            $thumb_im = imagecreatetruecolor($this->width, $this->height);


            if($this->orig_w > $this->width) {
                $cropbox  = array(
                    'x' => $this->orig_w - $this->width,
                    'y' => $this->orig_h - $this->height,
                    'width' => $this->width,
                    'height' => $this->height
                );
                if($this->orig_h < $this->height) {
                    // $cropbox['y']   = ($this->height - $this->orig_h);
                }
                imagecopy($thumb_im, $this->img, 0, 0, $cropbox['x'], $cropbox['y'], $cropbox['width'], $cropbox['height']);

            } else {
                $cropbox  = array(
                    'x' => $this->width - $this->orig_w,
                    'y' => $this->height - $this->orig_h,
                    'width' => $this->width,
                    'height' => $this->height
                );
                imagecopy($thumb_im, $this->img, 0, 0, 0, $cropbox['width']-$cropbox['height'], $cropbox['width'], $cropbox['height']);
            }
            
        }
        // does a smart crop
        else if ($crop_type == 'smart') {

            $wdiff = $this->orig_w - $this->width;
            $hdiff = $this->orig_h - $this->height;
            $CUT_SIZE = 10;
           
            $thumb_im = imagecreatetruecolor($this->width, $this->height);
            while ($wdiff > 0 || $hdiff > 0) {

                if ($wdiff >= $hdiff) {
                    $slice_width =  (int) min($wdiff, $CUT_SIZE);
                    $thumb_im1 = imagecreatetruecolor($slice_width, $this->orig_h);
                    $thumb_im2 = imagecreatetruecolor($slice_width, $this->orig_h);
                    $thumb_im  = imagecreatetruecolor(($this->orig_w - $slice_width), $this->orig_h);

                    $left =  imagecopy($thumb_im1, $this->img, 0, 0, 0, 0, $slice_width, $this->orig_h);
                    $right =  imagecopy($thumb_im2, $this->img, 0, 0, ($this->orig_w - $slice_width), 0, $this->orig_w,  $this->orig_h);
                    if ($this->__entropy($thumb_im1) > $this->__entropy($thumb_im2) ) {
                         $cropbox  = array(
                                            'x' => 0,
                                            'y' => 0,
                                            'width' => $this->orig_w - $slice_width,
                                            'height' => $this->orig_h
                                        );
                          imagecopy($thumb_im, $this->img, 0, 0, $cropbox ['x'], $cropbox ['y'], $cropbox ['width'], $cropbox ['height']);
                    } else {
                         $cropbox  = array(
                                            'x' => $slice_width,
                                            'y' => 0,
                                            'width' => $this->orig_w,
                                            'height' => $this->orig_h
                                        );
                          imagecopy($thumb_im, $this->img, 0, 0, $cropbox ['x'], $cropbox ['y'], $cropbox ['width'], $cropbox ['height']);
                    }                    
                } else {
                    $slice_height =  (int) min($hdiff, $CUT_SIZE);
                    $thumb_im1 = imagecreatetruecolor($this->orig_w, $slice_height);
                    $thumb_im2 = imagecreatetruecolor($this->orig_w, $slice_height);
                    $thumb_im  = imagecreatetruecolor($this->orig_w, ($this->orig_h - $slice_height));

                    $a =  array(0, 0, $this->orig_w, $slice_height);
                    $b =  array(0, ($this->orig_h - $slice_height), $this->orig_w,  $this->orig_h);

                    $top =  imagecopy($thumb_im1, $this->img, 0, 0, 0, 0, $this->orig_w, $slice_height);
                    $bottom =  imagecopy($thumb_im2, $this->img, 0, 0, 0, ($this->orig_h - $slice_height), $this->orig_w,  $this->orig_h);

                    if ($this->__entropy($thumb_im1) > $this->__entropy($thumb_im2) ) {
                         $cropbox  = array(
                                            'x' => 0,
                                            'y' => 0,
                                            'width' => $this->orig_w,
                                            'height' => $this->orig_h - slice_height
                                        );
                          imagecopy($thumb_im, $this->img, 0, 0, $cropbox ['x'], $cropbox ['y'], $cropbox ['width'], $cropbox ['height']);
                    } else {
                         $cropbox  = array(
                                            'x' => 0,
                                            'y' => $slice_height,
                                            'width' => $this->orig_w,
                                            'height' => $this->orig_h
                                        );
                          imagecopy($thumb_im, $this->img, 0, 0, $cropbox ['x'], $cropbox ['y'], $cropbox ['width'], $cropbox ['height']);
                    }                    
                }
                $this->img = $thumb_im;
                list( $tmp_w, $tmp_h ) =  array(imagesx($this->img), imagesy($this->img));
                $this->orig_w =  $tmp_w;
                $this->orig_h =  $tmp_h;
                $wdiff = $this->orig_w - $this->width;
                $hdiff = $this->orig_h - $this->height;
            }
        }
        $this->img = $thumb_im;
        $this->orig_w = imagesx($this->img);
        $this->orig_h = imagesy($this->img);
    }

    function __entropy($image= null) 
    {
        if (!$image) {
            $image =  $this->img;
        }

        $entropy = _smartcrop_gd_entropy($image);
        return $entropy;
    }
    
}
/**
 * Compute the entropy of an image, defined as -sum(p.*log2(p)).
 *
 * @param  resource $img GD image resource.
 * @return float The entropy of the image.
 */
function _smartcrop_gd_entropy($img) 
{
    $histogram = _smartcrop_gd_histogram($img);
    $histogram_size = array_sum($histogram);
    $entropy = 0;
    foreach ($histogram as $p) {
        if ($p == 0) {
            continue;
        }
        $p = $p / $histogram_size;
        $entropy += $p * log($p, 2);
    }
    return $entropy * -1;
}

/**
 * Compute a histogram of an image.
 *
 * @param  resource $img GD image resource.
 * @return array histogram as an array.
 */
function _smartcrop_gd_histogram($img) 
{
    $histogram = array_fill(0, 768, 0);
    for ($i = 0; $i < imagesx($img); $i++) {
        for ($j = 0; $j < imagesy($img); $j++) {
            $rgb = imagecolorat($img, $i, $j);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            $histogram[$r]++;
            $histogram[$g + 256]++;
            $histogram[$b + 512]++;
        }
    }
    return $histogram;
}


function image_gd_create_tmp(stdClass $image, $width, $height) 
{
    $res = imagecreatetruecolor($width, $height);

    if ($image->info['extension'] == 'gif') {
        // Find out if a transparent color is set, will return -1 if no
        // transparent color has been defined in the image.
        $transparent = imagecolortransparent($image->resource);

        if ($transparent >= 0) {
            // Find out the number of colors in the image palette. It will be 0 for
            // truecolor images.
            $palette_size = imagecolorstotal($image->resource);
            if ($palette_size == 0 || $transparent < $palette_size) {
                // Set the transparent color in the new resource, either if it is a
                // truecolor image or if the transparent color is part of the palette.
                // Since the index of the transparency color is a property of the
                // image rather than of the palette, it is possible that an image
                // could be created with this index set outside the palette size (see
                // http://stackoverflow.com/a/3898007).
                $transparent_color = imagecolorsforindex($image->resource, $transparent);
                $transparent = imagecolorallocate($res, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);

                // Flood with our new transparent color.
                imagefill($res, 0, 0, $transparent);
                imagecolortransparent($res, $transparent);
            }
            else {
                imagefill($res, 0, 0, imagecolorallocate($res, 255, 255, 255));
            }
        }
    }
    elseif ($image->info['extension'] == 'png') {
        imagealphablending($res, false);
        $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127);
        imagefill($res, 0, 0, $transparency);
        imagealphablending($res, true);
        imagesavealpha($res, true);
    }
    else {
        imagefill($res, 0, 0, imagecolorallocate($res, 255, 255, 255));
    }

    return $res;
}

?>
