Criando um Redimensionador de Imagens em PHP

Escrito em 15 de maio de 2007 em Desenvolvimento Web,Orientação a Objetos,PHP por Cesar

Muitos sites hoje vistos pela web tem algum álbum de fotos ou algo parecido neles, então neste artigo veremos como fazer um redimensionador de imagens em PHP para que possa ser utilizado para padronizar o tamanho das imagens postadas no mesmo, inclusive podendo colocar uma “marca d’agua” nas imagens para os casos específicos e até rotacioná-las.

Vale lembrar que o PHP, ou melhor, a biblioteca de tratamento de imagens do PHP chamada de GD2, não é e não tem o objetivo de ser um “Photoshop”, mas supre as necessidades básicas para o tratamento de imagens para WEB. Devemos também saber que o resultado do uso desta biblioteca depende muito da imagem que será tratada, e que aumentar uma imagem através da biblioteca pode fazer com que perca significadamente sua qualidade.

Muito bem, para começarmos precisamos que a biblioteca GD2 do PHP esteja “descomentada” no arquivo PHP.INI no caso de usuários Windows, para usuários Linux será necessário recompilar o PHP com a biblioteca.

Com a GD2 habilitada, vamos a classe que será responsável pelo redimensionamento de imagens:

<?php
/**
 * Classe para redimensionamento de imagens com opções para rotacionar e adicionar marca d’agua.
 * 
 * @author Cesar Rodrigo Bagatoli -> e-mail: crbdigo@gmail.com
 * @version 1.0 em 15/05/2007.
 *
 */
class Resize {
    /**
     * Nome da imagem com seu caminho completo, dentro do servidor.
     *
     * @var string
     */
    protected $image;
    /**
     * Tipo da Imagem setado automaticamente (1 = GIF, 2 = JPG, 3 = PNG, 4 = SWF, 5 = PSD, 6 = BMP,
     * 7 = TIFF(intel byte order), 8 = TIFF(motorola byte order), 9 = JPC, 10 = JP2, 11 = JPX, 12 = JB2, 13 = SWC,
     * 14 = IFF, 15 = WBMP, 16 = XBM).
     * Somente serão aceitos os tipos 1, 2 e 3.
     *
     * @var int
     */
    protected $imageType;
    /**
     * Tamanho vertical da imagem original.
     *
     * @var int
     */
    protected $height;
    /**
     * Tamanho horizontal da imagem original.
     *
     * @var int
     */
    protected $width;

    /**
     * Nome da imagem com seu caminho completo no servidor que será feita uma cópia da original, para preservar a original.
     *
     * @var string
     */
    protected $newImage;
    
    /**
     * Novo tamanho vertical da imagem.
     *
     * @var int
     */
    protected $newHeight;

    /**
     * Novo tamanho horizontal da imagem.
     *
     * @var int
     */
    protected $newWidth;

    /**
     * Nome da imagem com seu caminho completo no servidor que será utilizada como marca d’água.
     *
     * @var string
     */
    protected $waterMarkImage;
    
    /**
     * Tipo da imagem da marca d’agua setado automaticamente (1 = GIF, 2 = JPG, 3 = PNG, 4 = SWF, 5 = PSD, 6 = BMP,
     * 7 = TIFF(intel byte order), 8 = TIFF(motorola byte order), 9 = JPC, 10 = JP2, 11 = JPX, 12 = JB2, 13 = SWC,
     * 14 = IFF, 15 = WBMP, 16 = XBM).
     * Somente serão aceitos os tipos 1, 2 e 3.
     *
     * @var int
     */
    protected $waterMarkImageType;
    
    /**
     * Tamanho vertical da marca d’agua.
     *
     * @var int
     */
    protected $waterMarkImageHeight;
    
    /**
     * Tamanho horizontal da marca d’agua.
     *
     * @var int
     */
    protected $waterMarkImageWidth;
    
    /**
     * Posição onde a marca d’agua será colocada.
     * Valores poderão ser ’topLeft’, ’topCenter’, ’topRight’, ’bottomLeft’, ’bottomCenter’, ’bottomRight’ ou ’center’.
     *
     * @var string
     */
    protected $waterMarkPosition = ’bottomRight’;
    
    /**
     * Opacidade da marca d’agua.
     * Valores de 0 a 100.
     *
     * @var integer
     */
    protected $waterMarkOpacity = 50;
    
    /**
     * 1 para redimensionar proporcionalmente a imagem, 0 para permitir distorção.
     *
     * @var int
     */
    protected $proportional = 1;

    /**
     * H para redimensinar proporcionalmente a imagem com base na Horizontal, e V para redimensionar
     * proporcionalmente a imagem com base na Vertical.
     *
     * @var string
     */
    protected $proportionalFlag = ’H';

    /**
     * Numero de graus em que a imagem deverá ser rotacionada.
     * Valor de -360 a 360.
     *
     * @var int
     */
    protected $degrees = 0;

    /**
     * Cor da zona descoberta da imagem após a rotação.
     *
     * @var int
     */
    protected $bgColor = 0;

    /**
     * Construtor
     *
     * @param string $image
     * @access public
     * @return boolean
     */
    public function Resize($image) {
        $this->setImage($image);

        return true;
    }

    /**
     * Seta uma nova imagem para ser tratada e pega as dimensões dela junto com seu tipo.
     *
     * @param string $image
     * @access public
     */
    public function setImage($image) {
        $this->image = $image;

        try {
            $tmp = getimagesize($this->image);
            $this->width  = $tmp[0];
            $this->height  = $tmp[1];
            $this->imageType = $tmp[2];
        }
        catch (Exception $e) {
            throw new Exception(“Não foi possível identificar o tamanho da imagem original.”);
        }
    }

    /**
     * Retorna o caminho e nome da imagem atual.
     *
     * @return string
     * @access public
     */
    public function getImage() {
        return $this->image;
    }

    /**
     * Seta uma imagem para ser criada como cópia da original.
     *
     * @param string $newImage
     * @access public
     */
    public function setNewImage($newImage) {
        $this->newImage = $newImage;
    }

    /**
     * Retorna o caminho e nome da imagem cópia.
     *
     * @return string
     * @access public
     */
    public function getNewImage() {
        return $this->newImage;
    }
    
    /**
     * Seta uma imagem para ser utilizada como marca d’água.
     *
     * @param string $waterMarkImage
     * @access public
     */
    public function setWaterMarkImage($waterMarkImage) {
        $this->waterMarkImage = $waterMarkImage;
    }
    
    /**
     * Retorna o caminho e nome da imagem para marca d’água.
     *
     * @return string
     * @access public
     */
    public function getWaterMarkImage() {
        return $this->waterMarkImage;
    }
    
    /**
     * Seta a posição em que a marca d’agua aparecerá na imagem.
     *
     * @param string $waterMarkPosition
     * @access public
     */
    public function setWaterMarkPosition($waterMarkPosition) {
        if($waterMarkPosition == ’topLeft’ || 
           $waterMarkPosition == ’topCenter’ || 
           $waterMarkPosition == ’topRight’ || 
           $waterMarkPosition == ’bottomLeft’ || 
           $waterMarkPosition == ’bottomCenter’ || 
           $waterMarkPosition == ’bottomRight’ || 
           $waterMarkPosition == ’center’) {
            $this->waterMarkPosition = $waterMarkPosition;
        }
        else {
            throw new Exception(“Posição da marca d’agua é inválida.”);
        }
    }
    
    /**
     * Retorna a posição em que a marca d’agua deve ser colocada.
     *
     * @return string
     * @access public
     */
    public function getWaterMarkPosition() {
        return $this->waterMarkPosition;
    }
    
    /**
     * Seta a opacidade da marca d’agua.
     * Valores de 0 a 100.
     *
     * @param int $waterMarkOpacity
     * @access public
     */
    public function setWaterMarkOpacity($waterMarkOpacity) {
        if($waterMarkOpacity >= 0 && $waterMarkOpacity <= 100) {
            $this->waterMarkOpacity = $waterMarkOpacity;
        }
        else {
            throw new Exception(“Opacidade informada é inválida. Use valores de 0 a 100.”);
        }
    }
    
    /**
     * Retorna a opacidade que a marca d’agua deverá ter.
     *
     * @return int
     * @access public
     */
    public function getWaterMarkOpacity() {
        return $this->waterMarkOpacity;
    }

    /**
     * Seta o tamanho para o qual a imagem (original ou cópia) será redimensionada.
     *
     * @param int $newHeight
     * @param int $newWidth
     * @access public
     */
    public function setNewSize($newHeight, $newWidth) {
        $this->newHeight = $newHeight;
        $this->newWidth = $newWidth;
    }

    /**
     * 1 para redimensionar proporcionalmente a imagem, 0 para permitir distorção.
     *
     * @param int $proportional
     * @access public
     */
    public function setProportional($proportional) {
        $this->proportional = $proportional;
    }

    /**
     * Retorna se é para ser proporcional ou não.
     *
     * @return integer
     * @access public
     */
    public function getProportional() {
        return $this->proportional;
    }

    /**
     * H para redimensinar proporcionalmente a imagem com base na Horizontal, e V para redimensionar
     * proporcionalmente a imagem com base na Vertical.
     *
     * @param string $proportionalFlag
     * @access public
     */
    public function setProportionalFlag($proportionalFlag) {
        $this->proportionalFlag = $proportionalFlag;
    }

    /**
     * Retorna a base pela qual será mantida a proporção de redimensionamento.
     *
     * @return string
     * @access public
     */
    public function getProportionalFlag() {
        return $this->proportionalFlag;
    }
    
    /**
     * Seta quantos graus em que a imagem deverá ser rotacionada.
     * Valor de -360 a 360.
     *
     * @param int $degrees
     * @access public
     */
    public function setDegrees($degrees) {
        if($degrees > 360 || $degrees < -360) {
            throw new Exception(“Ângulo informado incorreto. Valor aceito é de -360 a 360.”);
        }
        $this->degrees = $degrees;
    }
    
    /**
     * Retorna o numero de graus em que a imagem deverá ser rotacionada.
     *
     * @return int
     * @access public
     */
    public function getDegrees() {
        return $this->degrees;
    }
    
    /**
     * Seta a cor de fundo que a zona descoberta da imagem, depois de rotacionada, deverá ter.
     *
     * @param int $bgColor
     * @access public
     */
    public function setBgColor($bgColor) {
        $this->bgColor = $bgColor;
    }
    
    /**
     * Retorna a cor de fundo que a zona descoberta da imagem, depois de rotacionada, deverá ter.
     *
     * @return int
     * @access public
     */
    public function getBgColor() {
        return $this->bgColor;
    }

    /**
     * Faz uma cópia da imagem original e seta ela como $image para ser utilizada preservando a original.
     *
     * @return boolean
     * @access private
     * @uses setImage()
     * @uses getImage()
     * @uses setNewImage()
     * @uses getNewImage()
     */
    private function copyImage() {
        if(!empty($this->image) && !empty($this->newImage)) {
            if(!copy($this->getImage(), $this->getNewImage())) {
                throw new Exception(“Não foi possível copiar o arquivo.”);
            }
            else {
                $this->setImage($this->getNewImage());
                $this->setNewImage(“”);
                return true;
            }
        }
        else {
            throw new Exception(“Erro. Verifique os atributos ’image’ e ’newImage’.”);
        }
    }
    
    /**
     * Verifica se todos os atributos necessários para o redimensionamento da imagem foram informados.
     * 
     * @access private
     */
    private function verifyAttributes() {
        if(empty($this->image)) {
            throw new Exception(“Atributo ’image’ não definido.”);
        }
        if(empty($this->imageType)) {
            throw new Exception(“Atributo ’imageType’ não definido.”);
        }
        if(empty($this->height)) {
            throw new Exception(“Atributo ’height’ não definido.”);
        }
        if(empty($this->width)) {
            throw new Exception(“Atributo ’width’ não definido.”);
        }
        if(empty($this->newHeight)) {
            throw new Exception(“Atributo ’newHeight’ não definido.”);
        }
        if(empty($this->newWidth)) {
            throw new Exception(“Atributo ’newWidth’ não definido.”);
        }
    }

    /**
     * Verifica se todos os atributos necessários para a imagem da marca d’agua foram informados.
     * 
     * @access private
     */
    private function verifyWaterMarkAttributes() {
        if(empty($this->waterMarkImage)) {
            throw new Exception(“Atributo ’waterMarkImage’ não definido.”);
        }
        if(empty($this->waterMarkImageType)) {
            throw new Exception(“Atributo ’waterMarkImageType’ não definido.”);
        }
        if(empty($this->waterMarkImageHeight)) {
            throw new Exception(“Atributo ’waterMarkHeight’ não definido.”);
        }
        if(empty($this->waterMarkImageWidth)) {
            throw new Exception(“Atributo ’waterMarkImageWidth’ não definido.”);
        }
    }

    /**
     * Redimensiona a imagem conforme configurado.
     *
     * @return boolean
     * @access public
     * @uses verifyAttributes()
     * @uses copyImage()
     * @uses getProportional()
     * @uses getProportionalFlag()
     * @uses getImage()
     * @uses getDegrees()
     * @uses getBgColor()
     * @uses getWaterMarkImage()
     * @uses getWaterMarkPosition()
     * @uses verifyWaterMarkAttributes()
     * @uses getWaterMarkOpacity();
     */
    public function make() {
        $this->verifyAttributes();
        
        /**
         * Faz a cópia da imagem caso tenha sido informado um novo nome de arquivo em ’newImage’.
         */
        if(!empty($this->newImage)) {
            $this->copyImage();
        }
        
        /**
         * Calcula a Proporção para o redimencionamento.
         */
        if($this->getProportional() == 1) {
            if($this->getProportionalFlag() == ’H') {
                /**
                 * Calcula o novo tamanho Vertical para ser proporcional.
                 */
                $this->newHeight = round(($this->newWidth * $this->height) / $this->width);
            }
            elseif($this->getProportionalFlag() == ’V') {
                /**
                 * Calcula o novo tamanho Horizontal para ser proporcional.
                 */
                $this->newWidth = round(($this->newHeight * $this->width) / $this->height);
            }
            else {
                throw new Exception(“Valor incorreto no atributo ’proportionalFlag’.”);
            }
        }
        elseif($this->getProportional() != 0) {
            throw new Exception(“Valor incorreto no atributo ’proportional’.”);
        }
        
        switch ($this->imageType) {
            case 1:
                $img    = imagecreatefromgif($this->getImage());
                $newImg = imagecreate($this->newWidth, $this->newHeight);
                break;
            case 2:
                $img    = imagecreatefromjpeg($this->getImage());
                $newImg = imagecreatetruecolor($this->newWidth, $this->newHeight);
                break;
            case 3:
                $img    = imagecreatefrompng($this->getImage());
                $newImg = imagecreatetruecolor($this->newWidth, $this->newHeight);
                break;
            default:
                throw new Exception(“Tipo de imagem informado não é compatível.”);
                break;
        }
        
        try {
            imagecopyresized($newImg, $img, 0, 0, 0, 0, $this->newWidth, $this->newHeight, $this->width, $this->height);
        }
        catch (Exception $e) {
            throw new Exception(“Não foi possível redimensionar a imagem.”);
        }
        
        /**
         * Gira a imagem.
         */
        if($this->getDegrees() != 0) {
            try {
                $newImg = imagerotate($newImg, $this->getDegrees(), $this->getBgColor());
                /**
                 * Pega os novos valores para ’newHeight’ e ’newWidth’.
                 */
                $this->newWidth = imagesx($newImg);
                $this->newHeight = imagesy($newImg);
            }
            catch (Exception $e) {
                throw new Exception(“Não foi possível rotacionar a imagem.”);
            }
        }
        
        /**
         * Adicionar uma marca d’agua na imagem pronta.
         */
        if(!empty($this->waterMarkImage)) {
            try {
                $tmp = getimagesize($this->getWaterMarkImage());
                $this->waterMarkImageWidth  = $tmp[0];
                $this->waterMarkImageHeight = $tmp[1];
                $this->waterMarkImageType   = $tmp[2];
                
                if($this->waterMarkImageHeight > $this->newHeight || 
                   $this->waterMarkImageWidth  > $this->newWidth) {
                    throw new Exception(“Marca d’agua é maior que imagem redimensionada.”);
                }
            }
            catch (Exception $e) {
                throw new Exception(“Não foi possível identificar o tamanho da imagem da marca d’agua.”);
            }
            
            $this->verifyWaterMarkAttributes();
            
            switch ($this->waterMarkImageType) {
                case 1:
                    $markImg = imagecreatefromgif($this->getWaterMarkImage());
                    break;
                case 2:
                    $markImg = imagecreatefromjpeg($this->getWaterMarkImage());
                    break;
                case 3:
                    $markImg = imagecreatefrompng($this->getWaterMarkImage());
                    break;
                default:
                    throw new Exception(“Tipo de imagem da marca d’agua informado não é compatível.”);
                    break;
            }
            
            /**
             * Calcula a área onde será colocada a marca d’agua.
             */
            switch($this->getWaterMarkPosition()) {
                case ’topLeft’:
                    $x = 10;
                    $y = 10;
                    break;
                case ’topCenter’:
                    $x = round(($this->newWidth / 2) - ($this->waterMarkImageWidth / 2));
                    $y = 10;
                    break;
                case ’topRight’:
                    $x = $this->newWidth - $this->waterMarkImageWidth - 10;
                    $y = 10;
                    break;
                case ’bottomLeft’:
                    $x = 10;
                    $y = $this->newHeight - $this->waterMarkImageHeight - 10;
                    break;
                case ’bottomCenter’:
                    $x = round(($this->newWidth / 2) - ($this->waterMarkImageWidth / 2));
                    $y = $this->newHeight - $this->waterMarkImageHeight - 10;
                    break;
                case ’bottomRight’:
                    $x = $this->newWidth - $this->waterMarkImageWidth - 10;
                    $y = $this->newHeight - $this->waterMarkImageHeight - 10;
                    break;
                case ’center’:
                    $x = round(($this->newWidth / 2) - ($this->waterMarkImageWidth / 2));
                    $y = round(($this->newHeight / 2) - ($this->waterMarkImageHeight / 2));
                    break;
                default:
                    $x = 10;
                    $y = 10;
            }
            
            /**
             * Adiciona a marca d’agua na imagem.
             */
            try {
                imagecopymerge($newImg, $markImg, $x, $y, 0, 0, $this->waterMarkImageWidth, $this->waterMarkImageHeight, $this->getWaterMarkOpacity());
            }
            catch (Exception $e) {
                throw new Exception(“Não foi possível adicionar marca d’agua.”);
            }
        }
        
        /**
         * Grava a imagem em arquivo.
         */
        try {
            switch ($this->imageType) {
             case 1:
             imagegif($newImg, $this->getImage());
             break;
             case 2:
             imagejpeg($newImg, $this->getImage(), 90);
             break;
             case 3:
             imagepng($newImg, $this->getImage());
             break;
             default:
                 throw new Exception(“Tipo de imagem informado não é compatível.”);
             break;
            }
        }
        catch (Exception $e) {
            throw new Exception($e);
        }
        
        return true;
    }
}
?>

Veja abaixo como é de facil utilização a classe que acabamos de criar:

try {
    $obj = new Resize(“imagem.jpg”);
    $obj->setNewImage(“novaImagem.jpg”);
    $obj->setWaterMarkImage(“marcaDagua.gif”);
    $obj->setWaterMarkOpacity(50);
    $obj->setWaterMarkPosition(‘bottomCenter’);
    $obj->setProportionalFlag(‘H’);
    $obj->setProportional(1);
    $obj->setDegrees(90);
    $obj->setNewSize(500, 500);
    $obj->make();
}
catch (Exception $e) {
    die($e);
}

Pronto, acabamos tudo que é preciso para redimensionar as imagens em um site PHP.


16 comentários em 'Criando um Redimensionador de Imagens em PHP' »

Assine os comentários usando RSS ou faça um TrackBack para 'Criando um Redimensionador de Imagens em PHP'.

[-]
[+]
Paulo Souza disse,

Em 18 de junho de 2007 às 20:34

Muito bom! Testei aqui e funcionou na boa.

 
[-]
[+]
Everton disse,

Em 19 de junho de 2007 às 19:49

Muito funcional, e com um array de opções!

irado!

 
[-]
[+]
André disse,

Em 15 de julho de 2007 às 18:12

Gostaria de um exemplo de como usar o objeto para redmiensionar a imagem.
Obrigado

 
[-]
[+]
Andre disse,

Em 01 de agosto de 2007 às 14:02

Como uso essas funçoes ….?

[-]
[+]
Cesar disse,

Em 01 de agosto de 2007 às 15:30

Olá amigo, você deve usar programação orientada à objetos. No final do artigo você pode encontrar um exemplo de utilização.
Obrigado.

 
 
[-]
[+]
carlos disse,

Em 13 de setembro de 2007 às 06:11

Mt bom cara, msm mt bom.

Tanks

 
[-]
[+]
Leandro disse,

Em 18 de setembro de 2007 às 15:50

Amigo, ao fazer o exemplo a classe nao gerou a imagem, retornou: Object id #3 Porque?

[-]
[+]
Cesar disse,

Em 18 de setembro de 2007 às 22:11

Olá Leandro, a resposta está no comentário abaixo do seu… feita pelo Adriano.

Espero q resolva.
T+

 
 
[-]
[+]
Adriano disse,

Em 18 de setembro de 2007 às 17:02

preste atenção no que esta fazendo, olhe no exemplo
se você só copiar, vc tem que ter 2 imagens na pasta
a imagem.jpg e a marcadagua.gif.
comente as linhas que não quer usar

Muito bom Cesar, funciona perfeitamente, vai pra minha coleção de bons códigos =]

 
[-]
[+]
Leandro disse,

Em 19 de setembro de 2007 às 17:52

Funcionou blz, mas me diga uma coisa, usei uma marca em png com fundo transparente, na hora que gerou a nova imagem a marca em png ficou com uma tarja preta, estava precisando colocar o png transparente. tem jeito?

[-]
[+]
Cesar disse,

Em 21 de setembro de 2007 às 20:49

Nunca testei com PNG transparente… Com GIF não funcionou?

 
 
[-]
[+]
Aranha digital disse,

Em 14 de julho de 2008 às 11:47

Adorei esse tutorial de redimensionar as fotos

 
[-]
[+]
Eron disse,

Em 27 de novembro de 2008 às 14:36

ótimo mesmo esta classe, porem ao fazer o resize por proporção a imagem ficou um pouco distorcida, não foi aplicado um “anti-alias”

 
[-]
[+]
watson disse,

Em 19 de novembro de 2009 às 01:13

O Valeu ai cara, muito show esse tutorial :P

 
[-]
[+]
Adriano disse,

Em 08 de setembro de 2010 às 16:47

muito bom, funciona muito bem.
parabéns.

 
[-]
[+]
Clvs disse,

Em 24 de setembro de 2010 às 01:38

Daeee galera… ae vai uma dica…

REDIMENCIONA A IMAGEM EM 100PX DE LARGURA E CALCULA A ALTURA PROPORCIONALMENTE.

FÁCIL… SIMPLES…