<?php
/**
 * This file is part of Image Resizer & Optimizer with GD plugin for MyBB.
 * Based on Cipher's Image Resizer plugin <ferry@cipher.demon.nl>
 *
 * Author Cipher <ferry@cipher.demon.nl>
 * Author MT Jordan <mtjo62@gmail.com>
 *
 * Copyright (C) 2007-2009 Cipher <ferry@cipher.demon.nl>
 * Copyright (C) 2010-2011 openSource Partners
 * Copyright (C) 2012 Omar Gonzalez <inu.admin@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

class resizeImage
{
   /**
     * Binary safe string
     *
     * @access private
     * @var    str
     */
   private $imgStr;

   /**
     * Constructor
     *
     * @access public
     * @param  str $src
     * @param  int $maxWidth
     * @param  int $maxSize
     * @param  int $animSize
     * @return void
     */
   public function __construct($src, $maxwidth, $newwidth, $maxsize, $animwidth, $animsize)
   {
		$imginfo = false;
		if(function_exists('getimagesize'))
		{
			$imginfo = getimagesize($src);
		}

        if(!$imginfo)
		{
			exit;
		}

        $this->imgstring = file_get_contents($src);
        $imgtype = 'process_'.$imginfo[2];

		if(!method_exists($this, $imgtype))
		{
			exit;
		}

		$this->$imgtype($src, $imginfo, $maxwidth, $this->setwidth($src, $imginfo, $maxwidth, $newwidth, $animwidth), $maxsize, $animwidth, $animsize);
    }

    /**
     * Calculate the new images dimensions
     *
     * @access private
     * @param  str   $src
     * @param  array $imgInfo
     * @param  int   $maxWidth
     * @param  int   $newWidth
     * @param  int   $animWidth
     * @return array
     */
    private function setWidth($src, $imginfo, $maxwidth, $newwidth, $animwidth)
    {
        $setWidth = array();

        if($this->gifAnim( $src ) && $imginfo[0] > $animwidth)
        {
            $percentage = $animwidth/$imginfo[0];

            $setWidth[] = $animwidth;
            $setWidth[] = $imginfo[1]*$percentage;
        }
        elseif(!$this->gifAnim($src) && $imginfo[0] > $maxwidth)
        {
            $percentage = $newwidth / $imginfo[0];

            $setWidth[] = $newwidth;
            $setWidth[] = $imginfo[1] * $percentage;
        }
        else
        {
            $setWidth[] = $imginfo[0];
            $setWidth[] = $imginfo[1];
        }

        return $setWidth;
    }

    /**
     * Process GIF image
     *
     * @access private
     * @param  str   $src
     * @param  array $imgInfo
     * @param  int   $newWidth
     * @param  int   $maxSize
     * @param  int   $animSize
     * @return void
     */
    private function process_1($src, $imgInfo, $maxWidth, $newWidth, $maxSize, $animWidth, $animSize)
    {
		$this->send_headers('gif');

        //if animated GIF, test for width > $animWidth and filesize > $animSize, else return w/o processing
		$content = $this->gifAnim($src);
        if($content)
        {
            if($imgInfo[0] < $animWidth && strlen($this->imgstring) < $animSize)
            {
                $fp = fopen($src, 'rb');
                fpassthru($fp);
                exit;
            }
        }

        //if image < $maxWidth and < $maxSize, return w/o processing
        if(!$content && $imgInfo[0] < $maxWidth && strlen($this->imgstring) < $maxSize)
        {
            $fp = fopen( $src, 'rb' );
            fpassthru( $fp );
            exit;
        }

        $thumb = imagecreate($newWidth[0], $newWidth[1]);
        $source = imagecreatefromgif($src);

        $isTrans = $this->isImgTransparent( $source, $imgInfo );
        $rgb = $this( $source );

        if($isTrans)
		{
            imagefill($thumb, 0, 0, imagecolorallocate($thumb, $rgb['r'], $rgb['g'], $rgb['b']));
		}

        imagecopyresampled($thumb, $source, 0, 0, 0, 0,  $newWidth[0], $newWidth[1], $imgInfo[0], $imgInfo[1]);

        if($isTrans)
		{
            $this->setImgTransparent($thumb);
		}

        imagegif($thumb);
        imagedestroy($thumb);
    }

    /**
     * Process JPG image
     *
     * @access private
     * @param  str   $src
     * @param  array $imgInfo
     * @param  int   $maxWidth
     * @param  int   $newWidth
     * @param  int   $maxSize
     * @param  int   $animSize
     * @return void
     */
    private function process_2($src, $imginfo, $maxwidth, $newwidth, $maxSize, $animwidth=null, $animsize=null)
    {
		$this->send_headers('jpg');

        //if image < $maxwidth and < $maxSize, return w/o processing
        if($imginfo[0] < $maxwidth && strlen($this->imgstring) < $maxSize)
        {
            $fp = fopen($src, 'rb');
            fpassthru($fp);
            exit;
        }

        $thumb  = imagecreatetruecolor($newwidth[0], $newwidth[1]);
        $source = imagecreatefromjpeg($src);

        imagecopyresized($thumb, $source, 0, 0, 0, 0,  $newwidth[0], $newwidth[1], $imginfo[0], $imginfo[1]);
        imagejpeg($thumb);
        imagedestroy($thumb);
    }

    /**
     * Process PNG image
     *
     * @access private
     * @param  str   $src
     * @param  array $imgInfo
     * @param  int   $maxWidth
     * @param  int   $newWidth
     * @param  int   $maxSize
     * @param  int   $animSize
     * @return void
     */
    private function process_3($src, $imginfo, $maxwidth, $newwidth, $maxsize, $animwidth=null, $animsize=null )
    {
		$this->send_headers('png');

        //if image < $maxwidth and < $maxsize, return w/o processing
        if($imginfo[0] < $maxwidth && strlen($this->imgstring) < $maxsize)
        {
            $fp = fopen( $src, 'rb' );
            fpassthru( $fp );
            exit;
        }

        $thumb   = imagecreatetruecolor($newwidth[0], $newwidth[1]);
        $source  = imagecreatefrompng($src);
        $isTrans = $this->isImgTransparent($source, $imginfo);
		#$rgb     = $this->randomRGB($source);

        if($isTrans)
		{
			#imagefill($thumb, 0, 0, imagecolorallocate($thumb, $rgb['r'], $rgb['g'], $rgb['b']));
            imagefill($thumb, 0, 0, imagecolorallocate($thumb, 255, 255, 255));
		}

        imagecopyresampled($thumb, $source, 0, 0, 0, 0,  $newwidth[0], $newwidth[1], $imginfo[0], $imginfo[1]);

        if($isTrans)
		{
            $this->setImgTransparent($thumb);
		}

        imagetruecolortopalette($thumb, 20, 256);
        imagepng($thumb);
        imagedestroy($thumb);
    }

    /**
     * Determine if GIF/PNG image has transparent index
     *
     * @access private
     * @param  mixed $src
     * @param  array $imgInfo
     * @return bool
     */
    private function isImgTransparent($src, $imgInfo)
    {
        $destID = imagecreatetruecolor($imgInfo[0], $imgInfo[1]);

        imagepalettecopy($destID, $src);
        imagecopyresized($destID, $src, 0, 0, 0, 0, $imgInfo[0], $imgInfo[1], $imgInfo[0], $imgInfo[1]);

        $black = imagecolorat($destID, 0, 0);
        $fill  = imagecolorallocate($destID, 255, 255, 255);

        imagefill($destID, 0, 0, $fill);
        imagecopyresized($destID, $src, 0, 0, 0, 0, $imgInfo[0], $imgInfo[1], $imgInfo[0], $imgInfo[1]);

        $white = imagecolorat($destID, 0, 0);

        imagedestroy($destID);

        if($black != $white && $this->testCorners($src, $imgInfo))
		{
            return true;
		}
		return false;
    }

    /**
     * Check four points to determine if image has consistent transparent index
     *
     * @access private
     * @param  mixed $src
     * @param  array $imgInfo
     * @return bool
     */
    private function testCorners( $src, $imgInfo )
    {
        $pointA = imagecolorat( $src, 0, 0 );
        $pointB = imagecolorat( $src, $imgInfo[0] - 1, 0 );
        $pointC = imagecolorat( $src, 0, $imgInfo[1] - 1 );
        $pointD = imagecolorat( $src, $imgInfo[0] - 1, $imgInfo[1] - 1 );

        if ( $pointA == $pointB && $pointB == $pointC && $pointC == $pointD )
            return true;

        return false;
    }

    /**
     * Determine RGB value not in current image color palette
     *
     * @access private
     * @param  mixed $src
     * @param  array $imgInfo
     * @return bool
     */
    private function randomRGB( $src )
    {
        $total = ((imagecolorstotal($src) <= 0 ) ? 256 : imagecolorstotal($src));
        $red   = (rand() % 255);
        $green = (rand() % 255);
        $blue  = (rand() % 255);

        for($i = 1; $i <= $total; $i++)
        {
            if(imagecolorexact( $src, $red, $green, $blue ) == -1)
            {
                return array('r' => $red,
                             'g' => $green,
                             'b' => $blue
				);
            }
        }
    }

    /**
     * Set processed image background transparent
     *
     * @access private
     * @param  mixed $src
     * @return void
     */
    private function setImgTransparent($src)
    {
        imagecolortransparent($src, imagecolorat($src, 0, 0));
    }

    /**
     * Sends a image to the browser
     *
     * @access private
     * @param  mixed $image
     * @param  mixed $type
     */
    private function send_headers($type)
    {
		defined('TIME_NOW') or define('TIME_NOW', time());
		header('Content-type: image/'.$type.'; charset=UTF-8');
		header('cache-control: must-revalidate');
		header('expires: '.gmdate('D, d M Y H:i:s', TIME_NOW+(60*60)).' GMT');
		if(substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip'))
		{
			ob_start('ob_gzhandler');
		}
		else
		{
			ob_start();
		}
    }

    /**
     * Determine if GIF image is animated
     *
     * @access private
     * @param  str $src
     * @return bool
     */
    private function gifAnim( $src )
    {
        $str_loc = 0;
        $count   = 0;

        //return after we find a 2nd frame
        while($count < 2)
        {
            $where1 = strpos($this->imgstring, "\x00\x21\xF9\x04", $str_loc);

            if($where1 === false)
            {
                break;
            }
            else
            {
                $str_loc = $where1 + 1;
                $where2  = strpos( $this->imgstring, "\x00\x2C", $str_loc );

                if($where2 === false)
                {
                    break;
                }
                else
                {
                    if($where1 + 8 == $where2)
					{
                        ++$count;
					}

                    $str_loc = $where2 + 1;
                }
            }
        }

        if($count > 1)
		{
            return true;
		}
		return false;
    }
}

//create the image resize object
if(!defined('IN_MYBB'))
{
	if(isset($_GET['filename']))
	{
		require_once 'settings.php';
		new resizeImage($_GET['filename'], (int)$settings['image_resizer_maxwidth'], (int)$settings['image_resizer_resizewidth'], (int)$settings['image_resizer_maxsize'],  (int)$settings['image_resizer_animwidth'], (int)$settings['image_resizer_animsize']);
	}
	exit;
}