<?php

/**
 * Goweb Sitemanager 5 Framework
 *
 * Classe de redimensionamento de imagens
 *
 * @version    5.1.4
 * @category   Goweb
 * @package    Goweb_Image
 * @author     I&D <dev@goweb.pt>, Pedro Pinto <ppinto@goweb.pt>
 * @copyright  2010 (c) Goweb (http://www.goweb.pt)
 */

/**
 * Classe de redimensionamento de imagens
 *
 * @version    5.1.4
 * @category   Goweb
 * @package    Goweb_Image
 * @author     I&D <dev@goweb.pt>, Pedro Pinto <ppinto@goweb.pt>
 * @copyright  2010 (c) Goweb (http://www.goweb.pt)
 */
class Goweb_Image_Resize {

    /**
     * Array com os tipos de imagens suportados
     * 
     * @var  array
     */
    protected $supportedImageTypes = array('gif', 'jpg', 'jpeg', 'pjpeg', 'png');
    
    /**
     * Nome da imagem origem
     * 
     * @var  string
     */
    protected $sourceImage = null;

    /**
     * Array com os atributos da imagem origem
     * 
     * @var  array
     */
    protected $sourceImageAttributes = array();

    /**
     * O resource da imagem origem
     * 
     * @var  resource
     */
    protected $sourceImageHandle;

    /**
     * Nome da imagem destino
     * 
     * @var  string
     */
    protected $targetImage;

    /**
     * Array com os atributos da imagem origem
     * 
     * @var  array
     */    
    protected $targetImageAttributes;

    /**
     * O resource da imagem origem
     * 
     * @var  resource
     */
    protected $targetImageHandle;

    /**
     * Constructor
     *
     * @throws  Goweb_Exception  No caso da GD 2.0 n&atilde;o estiver instalada
     */
    public function __constructor() {
        if (!function_exists('imagecopyresized')) {
            throw new Goweb_Exception('&Eacute; necess&aacute;rio GD 2.0 para efectuar manipula&ccedil;&otilde;es com imagens.');
        }
    }

    /**
     * Processa as imagens do tipo GIF.
     * 
     * @return  bool  Retorna TRI se houve sucesso
     */
    protected function _processGifImage() {
        if (!(imagetypes() & IMG_GIF)) {
            return false;
        }
        
        $this->sourceImageHandle = imagecreatefromgif($this->sourceImage);
        //$this->_processImage();
        $this->targetImageHandle = imagecreatetruecolor($this->targetImageAttributes['width'],  $this->targetImageAttributes['height']);
        $trnprt_indx = imagecolortransparent($this->sourceImageHandle);

        if ($trnprt_indx >= 0) {
            $transparent_color = @imagecolorsforindex($this->sourceImageHandle, $trnprt_indx);
            $transparency = @imagecolorallocate($this->targetImageHandle, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
            imagefill($this->targetImageHandle, 0, 0, $transparency);
            imagecolortransparent($this->targetImageHandle, $transparency);
        }
        imagecopyresampled($this->targetImageHandle, $this->sourceImageHandle, 0, 0, 0, 0, $this->targetImageAttributes['width'], $this->targetImageAttributes['height'], $this->sourceImageAttributes['width'], $this->sourceImageAttributes['height']);
        
        // escreve o ficheiro para o disco
        $this->targetImageAttributes['quality'] /= 10;
        if ($this->targetImageAttributes['quality']>9) $this->targetImageAttributes['quality'] = 9;        
        imagegif($this->targetImageHandle, $this->targetImage); // write file to disk
        
        return true;
    }
    
    /**
     * Processa as imagens do tipo JPEG.
     * 
     * @return  bool  Retorna TRI se houve sucesso
     */
    protected function _processJpgImage() {
        if (!(imagetypes() & IMG_JPEG)) {
            return false;
        }
        
        $this->sourceImageHandle = imagecreatefromjpeg($this->sourceImage);
        $this->_processImage();
        
        // escreve o ficheiro para o disco
        if ($this->targetImageAttributes['quality'] > -1) { // verifica a qualidade
            return imagejpeg($this->targetImageHandle,
                             $this->targetImage,
                             $this->targetImageAttributes['quality']);
        }
        return imagejpeg($this->targetImageHandle, $this->targetImage);
    }

    /**
     * Processa as imagens do tipo PNG.
     * 
     * @return  bool  Retorna TRI se houve sucesso
     */    
    protected function _processPngImage() {
        if (!(imagetypes() & IMG_PNG)) {
            return false;
        }
        
        $this->sourceImageHandle = @imagecreatefrompng($this->sourceImage);
        $this->targetImageHandle = imagecreatetruecolor($this->targetImageAttributes['width'],  $this->targetImageAttributes['height']);
        $trnprt_indx = imagecolortransparent($this->sourceImageHandle);

        if ($trnprt_indx >= 0) {
            $transparent_color = imagecolorsforindex($this->sourceImageHandle, $trnprt_indx);
            $transparency = imagecolorallocate($this->targetImageHandle, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
            imagefill($this->targetImageHandle, 0, 0, $transparency);
            imagecolortransparent($this->targetImageHandle, $transparency);
        } else {
            imagealphablending($this->targetImageHandle, false);
            $color = imagecolorallocatealpha($this->targetImageHandle, 0, 0, 0, 127);
            imagefill($this->targetImageHandle, 0, 0, $color);
            imagesavealpha($this->targetImageHandle, true);
        }

        imagecopyresampled($this->targetImageHandle, $this->sourceImageHandle, 0, 0, 0, 0, $this->targetImageAttributes['width'], $this->targetImageAttributes['height'], $this->sourceImageAttributes['width'], $this->sourceImageAttributes['height']);
        
        // escreve o ficheiro para o disco
        $this->targetImageAttributes['quality'] /= 10;
        if ($this->targetImageAttributes['quality']>9) $this->targetImageAttributes['quality'] = 9;
        if ($this->targetImageAttributes['quality'] > -1) { // verifica a qualidade
            return imagepng($this->targetImageHandle,
                             $this->targetImage,
                             $this->targetImageAttributes['quality']);
        }
        return imagepng($this->targetImageHandle, $this->targetImage);       
    }

    /**
     * Processa a imagem.
     */
    protected function _processImage() {
        if (function_exists('ImageCreateTrueColor')){
            $this->targetImageHandle = ImageCreateTrueColor($this->targetImageAttributes['width'],
                                                            $this->targetImageAttributes['height']);
        } else {
            $this->targetImageHandle = ImageCreate($this->targetImageAttributes['width'],
                                                   $this->targetImageAttributes['height']);
        }

        if (function_exists('ImageCopyResampled')) {
        	if( $this->targetImageAttributes['m_sizeX'] > 0 ||  $this->targetImageAttributes['m_sizeY'] > 0){
        		ImageCopyResampled($this->targetImageHandle, $this->sourceImageHandle, 0, 0, 0, 0,
                               $this->targetImageAttributes['m_sizeX'], $this->targetImageAttributes['m_sizeX'],
                               $this->sourceImageAttributes['width'], $this->sourceImageAttributes['height']);         
        	}
        	else           
            	ImageCopyResampled($this->targetImageHandle, $this->sourceImageHandle, 0, 0, 0, 0,
                               $this->targetImageAttributes['width'], $this->targetImageAttributes['height'],
                               $this->sourceImageAttributes['width'], $this->sourceImageAttributes['height']);
                               
        } else {
            ImageCopyResized($this->targetImageHandle, $this->sourceImageHandle, 0, 0, 0, 0,
                             $this->targetImageAttributes['width'], $this->targetImageAttributes['height'],
                             $this->sourceImageAttributes['width'], $this->sourceImageAttributes['height']);
        }
    }

    /**
     * Define os atributos para a imagem origem.
     *
     * @throws  Goweb_Exception  No caso do tipo de imagem n&atilde;o for suportado
     */
    protected function _setSourceImageAttributes() {
        $arrayAttributes = getimagesize($this->sourceImage);
        $this->sourceImageAttributes = array('width' => $arrayAttributes[0],
                                             'height' => $arrayAttributes[1],
                                             'channels' => (array_key_exists('channels', $arrayAttributes)) ? $arrayAttributes['channels'] : null,
                                             'mime' => explode('/', $arrayAttributes['mime']));

        if (!in_array($this->sourceImageAttributes['mime'][1], $this->supportedImageTypes)) {
            throw new Goweb_Exception('O formato <b>'.$this->sourceImageAttributes['mime'][1].'</b> n&atilde;o e suportado.');
        }
    }

    /**
     * Define os atributos para a imagem destino.
     *
     * @param  int  $width    Largura da imagem
     * @param  int  $height   Altura da imagem
     * @param  int  $quality  A qualidade da imagem (1..100)
     * @param  int  $corte_x  x-coordinate of destination point
     * @param  int  $corte_y  y-coordinate of destination point
     * @param  int  $m_sizeX  y-coordinate of destination point
     * @param  int  $m_sizeY  y-coordinate of destination point
     */
    protected function _setTargetImageAttributes($width, $height, $quality = -1, $corte_x = 0, $corte_y = 0, $m_sizeX = 0, $m_sizeY = 0) {
        $this->targetImageAttributes = array('width' => $width, 'height' => $height, 'quality' => $quality, 'corte_x' => $corte_x, 'corte_y' => $corte_y, 'm_sizeX' => $m_sizeX, 'm_sizeY' => $m_sizeY);
    }

    /**
     * Efectua o redimensionamento consoante o tipo de imagem.
     */
    protected function _resize() {
        switch ($this->sourceImageAttributes['mime'][1]) {
         case 'gif':
             return $this->_processGifImage();
             break;
         case 'jpg':
         case 'jpeg':
         case 'pjpeg':
             return $this->_processJpgImage();
             break;
         case 'png':
             return $this->_processPngImage();
             break;
        }               
    }

    /**
     * Efectua o redimensionamento da imagem.
     * 
     * @param   string  $sourceImage        Caminho completo para imagem origem
     * @param   string  $targetImage        Caminho completo para imagem destino
     * @param   int     $widthTargetImage   Largura da imagem destino
     * @param   int     $heightTargerImage  Altura da imagem destino
     * @param   int     $quality            Qualidade da imagem (1..100)
     * @return  bool                        Retorna TRUE se houve sucesso
     */
    public function resize($sourceImage, $targetImage, $widthTargetImage, $heightTargetImage, $quality = -1, $type_resize = "") {
        switch ($type_resize){
        	case 'resize':
        		$this->sourceImage = $sourceImage;
		        $this->targetImage = $targetImage;
		        $this->_setSourceImageAttributes();
		        $this->_setTargetImageAttributes($widthTargetImage, $heightTargetImage, $quality);
        		return $this->_resize();
        		break;
        	case 'crop':
        		return $this->crop($sourceImage, $targetImage, $widthTargetImage, $heightTargetImage, $quality);
        		break;
        	case 'resizeMaintainRatio':
        	default:
			return $this->resizeMaintainRatio($sourceImage, $targetImage, $widthTargetImage, $heightTargetImage, $quality);
        }

    }

    
    /**
     * Efectua o crop da imagem.
     * 
     * @param   string  $sourceImage        Caminho completo para imagem origem
     * @param   string  $targetImage        Caminho completo para imagem destino
     * @param   int     $widthTargetImage   Largura da imagem destino
     * @param   int     $heightTargerImage  Altura da imagem destino
     * @param   int     $quality            Qualidade da imagem (1..100)
     * @return  bool                        Retorna TRUE se houve sucesso
     */
    public function crop($sourceImage, $targetImage, $widthTargetImage, $heightTargetImage, $quality = -1) {
        $this->sourceImage = $sourceImage;
        $this->targetImage = $targetImage;
        $this->_setSourceImageAttributes();

        $imageSourceSize = getimagesize($this->sourceImage);


        $d_largura = $imageSourceSize[0] / 2 - $widthTargetImage / 2;
		$d_altura = $imageSourceSize[1] / 2 - $heightTargetImage / 2;
					
		// vamos redimensionar pelo que tiver d_.. mais pequeno
					
		if($d_altura < $d_largura){ // redimensionamento pela largura				
			$altura_final = $heightTargetImage;
			$largura_final  = $imageSourceSize[0] * $altura_final / $imageSourceSize[1];		
			$corte_x = $largura_final / 2 - $widthTargetImage / 2;
			$corte_y = 0;
		}else{// redimensionamento pela altura
			$largura_final  = $widthTargetImage; 					
			$altura_final = $imageSourceSize[1] * $largura_final / $imageSourceSize[0];
			$corte_x = 0;
			$corte_y = $altura_final / 2 - $heightTargetImage / 2;
		}			
			
		// faz o redimensionamento para o tamanho que melhor se adapte ao thumbnail final
			
		$m_sizeX = round($largura_final);
		$m_sizeY = round($altura_final);
        
		/*        
        //imageantialias($imagem,true);			
		imagecopyresampled($imagem, $im, 0,0, 0,0, $m_sizeX, $m_sizeY, $size[0], $size[1]);
					
		// agora vamos fazer o corte do thumbnail
		//imagecopy($img, $imagem, 0,  0, $corte_x, $corte_y, $largura, $altura);
		imagecopy($img, $imagem, 0,  0, $corte_x, 0, $largura, $altura);
        */
		
        $this->_setTargetImageAttributes($widthTargetImage, $heightTargetImage, $quality, $corte_x, $corte_y, $m_sizeX, $m_sizeY);
        return $this->_resize();
    }
    
    /**
     * Efectua o redimensionamento da imagem, mantendo a relacao largura/altura.
     * 
     * @param   string  $sourceImage        Caminho completo para imagem origem
     * @param   string  $targetImage        Caminho completo para imagem destino
     * @param   int     $widthTargetImage   Largura da imagem destino
     * @param   int     $heightTargerImage  Altura da imagem destino
     * @param   int     $quality            Qualidade da imagem (1..100)
     * @return  bool                        Retorna TRUE se houve sucesso
     */
    public function resizeMaintainRatio($sourceImage, $targetImage, $widthTargetImage, $heightTargetImage, $quality = -1) {
        $this->sourceImage = $sourceImage;
        $this->targetImage = $targetImage;
        $this->_setSourceImageAttributes();

        $imageSourceSize = getimagesize($this->sourceImage);
        $scale = min($widthTargetImage / $imageSourceSize[0], $heightTargetImage / $imageSourceSize[1]);
        if ($scale >= 1) {
            $scale = 1;
        }
        $widthTargetImage = floor($scale * $imageSourceSize[0]);
        $heightTargetImage = floor($scale * $imageSourceSize[1]);

        $this->_setTargetImageAttributes($widthTargetImage, $heightTargetImage, $quality);
        return $this->_resize();
    }
}