Alguma vez pretendeu ter um método simples que satisfaça as suas necessidades no que toca ao redimensionamento de imagens em PHP? É para isso que as classes PHP servem – são pedaços de funcionalidade reutilizáveis que chamamos para fazerem o trabalho por nós em background. Vamos então aprender a criar a nossa própria classe, bem construída e acima de tudo expansível. Redimensionar deveria ser rápido e fácil, pelo que tornámos a criação desta função em 11 simples passos! Obrigado aos colegas do NetTuts pela inspiração.

PASSO 1 – PREPARAÇÃO

Para começar, crie uma pasta onde irá trabalhar este tutorial e crie 2 ficheiros: index.php e resize-class-php

PASSO 2 – CHAMANDO O OBJECTO

Para lhe dar uma ideia do que estamos a tentar fazer, vamos começar por criar o código das chamadas de objecto que iremos usar para redimensionar as imagens. Como poderá confirmar ao ler o código, existe bastante lógica no mesmo: abrimos a imagem, definimos as dimensões com as quais a queremos redimensionar e o tipo de redimensionamento. Depois salvamos a imagem, definindo qual o formato e a qualidade desta.

Dando continuidade, abra o seu ficheiro index.php ( pode abrir com um editor de texto como o Bloco de Notas ou Text Wrangler ) e adicione o seguinte trecho de código. Depois, guarde e feche o seu ficheiro index.php.

// *** Include the class
include("resize-class.php");

// *** 1) Initialize / load image
$resizeObj = new resize('sample.jpg');

// *** 2) Resize image (options: exact, portrait, landscape, auto, crop)
$resizeObj -> resizeImage(150, 100, 'crop');

// *** 3) Save image
$resizeObj -> saveImage('sample-resized.gif', 100);

PASSO 3 – ESTRUTURA DA CLASSE

É a Programação Orientada a Objectos (OOP) que torna isto possível. Veja uma classe como um padrão onde pode integrar dados, ou por outras palavras, esconder dados. Podemos depois reutilizar esta classe vezes sem conta sem a necessidade de termos de reescrever o código. Para isso, apenas terá de chamar os métodos apropriados, como fizemos no Passo 2. Uma vez estando o padrão criado, criamos os objectos.

A função construct, conhecida como Construtor, é um método especial que é chamado pela classe quando se cria um novo objecto. Isto torna-nos possível criar alguma inicialização, como vamos ver no próximo passo.

Vamos começar por criar a nossa classe de redimensionamento. Abra o ficheiro resize-class.php e insira o seguinte trecho de código. De notar que antes de construct() são dois underscores.

Class resize  
{  
    // *** Class variables  

    public function __construct()  
    {  

    }  
}

PASSO 4 – O CONSTRUTOR

Vamos modificar o método demonstrado no passo anterior. Antes de mais, vamos indicar qual o nome do ficheiro e directoria da imagem a ser redimensionada. Chamemos a esta variável $fileName.

Iremos necessitar de abrir o ficheiro indicado com PHP, para que este possa ler a imagem. Isto irá ser feito através da função openImage, que irá ser abordada mais à frente. Para já, é necessário guardar o código como uma variável da classe. Uma variável de classe é apenas uma variável, mas atribuída especificamente a uma classe. Vamos então adicionar uma variável introduzida no Passo 3: “private $image;”.

Definindo a variável como privada, estará a definir que aquela variável só irá ser acedida pela sua classe. A partir daqui, podemos chamar a imagem aberta, conhecida como fonte (resource), que iremos fazer mais tarde quando redimensionarmos.

Vamos também introduzir as variáveis da altura e largura da imagem.

Class resize  
{  
    // *** Class variables  
    private $image;  
    private $width;  
    private $height;  

    function __construct($fileName)  
    {  
        // *** Open up the file  
        $this->image = $this->openImage($fileName);  

        // *** Get width and height  
        $this->width  = imagesx($this->image);  
        $this->height = imagesy($this->image);  
    }  
}

Os métodos “imagesx” e “imagesy” são funções que fazem parte da livraria GD. Elas retornam a largura e altura da imagem, respectivamente. Altere o seu código para condizer com o acima.

PASSO 5 – ABRINDO A IMAGEM

No passo anterior, chamámos o método “openImage”. Neste passo vamos criar esse método. Queremos que o script faça o nosso trabalho, portanto dependendo do ficheiro que irá ser trabalhado, o script deverá determinar qual a função da livraria GD que irá chamar para abrir a imagem. Isto é alcançado facilmente, comparando a extensão do ficheiro com uma declaração do switch.

Neste passo, passamos no ficheiro que pretendemos dimensionar e devolvemos esse ficheiro fonte.

private function openImage($file)  
{  
    // *** Get extension  
    $extension = strtolower(strrchr($file, '.'));  

    switch($extension)  
    {  
        case '.jpg':  
        case '.jpeg':  
            $img = @imagecreatefromjpeg($file);  
            break;  
        case '.gif':  
            $img = @imagecreatefromgif($file);  
            break;  
        case '.png':  
            $img = @imagecreatefrompng($file);  
            break;  
        default:  
            $img = false;  
            break;  
    }  
    return $img;  
}

PASSO 6 – COMO REDIMENSIONAR

É aqui que a magia acontece. No próximo passo, vamos criar um método público que vamos chamar para fazer o redimensionamento – então faz sentido que sejam fornecidos dados como largura e altura da imagem, bem como informação de como queremos que a imagem seja redimensionada.

Irá haver alturas em que gostaria de redimensionar uma imagem para um tamanho exacto, e irá ser incluído. Mas por outro lado, haverão também alturas em que terá de redimensionar centenas de imagens e cada imagem tem um aspecto dimensional diferente. Redimensionar estas imagens de forma igual, iria criar sérios problemas de distorção na maioria delas. Se dermos uma olhadela ás nossas opções para evitar distorções, temos:

  • Redimensionar a imagem o mais próximo possível das nossas dimensões, mantendo o aspecto dimensional.
  • Redimensionar a imagem o mais próximo possível das nossas dimensões, e cortar o excedente.

Ambas as opções são viáveis, dependendo das suas necessidades.

Então vamos fazer uma tentativa de conseguir lidar com estas situações. Recapitulando, vamos dar opções para:

  • Redimensionar a imagem com largura e altura exactas. (exact)
  • Redimensionar a largura – será definida uma largura exacta, enquanto que a altura será ajustada de acordo com o aspecto dimensional. (landscape)
  • Redimensionar a altura – será definida uma altura exacta, enquanto que a largura será ajustada dinamicamente. (portrait)
  • Determinar automaticamente as opções 2 e 3. Se irá fazer um ciclo de redimensionamentos numa pasta com imagens de diferentes tamanhos, deixar o script determinar automaticamente como o fazer. (auto)
  • Redimensionar e depois cortar. Tamanho exacto, sem distorção. (crop)

PASSO 7 – FAZER O REDIMENSIONAMENTO

Existem dois passos no método de redimensionamento. O primeiro é determinar a altura e largura adequadas, criando alguns métodos para tal. A largura e altura são devolvidas como uma matriz e definidos nas suas respectivas variáveis. O segundo é o que executa o processo de redimensionamento. Cabe ao leitor ler e conhecer as seguintes funções GD:

Também guardamos a saída do método imagecreatetruecolor como uma variável de classe. Adicione “private $imageResized;” com as outras variáveis de classe.

O redimensionamento é executado por um módulo PHP conhecido como a livraria GD. Muitos dos métodos que estamos a usar estão presentes na livraria GD.

// *** Add to class variables  
private $imageResized;
public function resizeImage($newWidth, $newHeight, $option="auto")  
{  

    // *** Get optimal width and height - based on $option  
    $optionArray = $this->getDimensions($newWidth, $newHeight, strtolower($option));  

    $optimalWidth  = $optionArray['optimalWidth'];  
    $optimalHeight = $optionArray['optimalHeight'];  

    // *** Resample - create image canvas of x, y size  
    $this->imageResized = imagecreatetruecolor($optimalWidth, $optimalHeight);  
    imagecopyresampled($this->imageResized, $this->image, 0, 0, 0, 0, $optimalWidth, $optimalHeight, $this->width, $this->height);  

    // *** if option is 'crop', then crop too  
    if ($option == 'crop') {  
        $this->crop($optimalWidth, $optimalHeight, $newWidth, $newHeight);  
    }  
}

PASSO 8 – A ÁRVORE DE DECISÕES

Quanto mais trabalho fizer agora, menos terá de fazer quando quiser redimensionar. Este método escolhe qual o caminho a percorrer com o objectivo de obter as dimensões de redimensionamento ideais, baseadas na opção de redimensionamento escolhida. Irá ser chamado o método apropriado, o qual iremos criar no próximo passo.

private function getDimensions($newWidth, $newHeight, $option)  
{  

   switch ($option)  
    {  
        case 'exact':  
            $optimalWidth = $newWidth;  
            $optimalHeight= $newHeight;  
            break;  
        case 'portrait':  
            $optimalWidth = $this->getSizeByFixedHeight($newHeight);  
            $optimalHeight= $newHeight;  
            break;  
        case 'landscape':  
            $optimalWidth = $newWidth;  
            $optimalHeight= $this->getSizeByFixedWidth($newWidth);  
            break;  
        case 'auto':  
            $optionArray = $this->getSizeByAuto($newWidth, $newHeight);  
            $optimalWidth = $optionArray['optimalWidth'];  
            $optimalHeight = $optionArray['optimalHeight'];  
            break;  
        case 'crop':  
            $optionArray = $this->getOptimalCrop($newWidth, $newHeight);  
            $optimalWidth = $optionArray['optimalWidth'];  
            $optimalHeight = $optionArray['optimalHeight'];  
            break;  
    }  
    return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight);  
}

PASSO 9 – DIMENSÕES IDEAIS

Já percebemos o que fazem estes quarto métodos. São matemática básica, que calcula o melhor enquadramento.

private function getSizeByFixedHeight($newHeight)  
{  
    $ratio = $this->width / $this->height;  
    $newWidth = $newHeight * $ratio;  
    return $newWidth;  
}  

private function getSizeByFixedWidth($newWidth)  
{  
    $ratio = $this->height / $this->width;  
    $newHeight = $newWidth * $ratio;  
    return $newHeight;  
}  

private function getSizeByAuto($newWidth, $newHeight)  
{  
    if ($this->height < $this->width)  
    // *** Image to be resized is wider (landscape)  
    {  
        $optimalWidth = $newWidth;  
        $optimalHeight= $this->getSizeByFixedWidth($newWidth);  
    }  
    elseif ($this->height > $this->width)  
    // *** Image to be resized is taller (portrait)  
    {  
        $optimalWidth = $this->getSizeByFixedHeight($newHeight);  
        $optimalHeight= $newHeight;  
    }  
    else  
    // *** Image to be resizerd is a square  
    {  
        if ($newHeight < $newWidth) {  
            $optimalWidth = $newWidth;  
            $optimalHeight= $this->getSizeByFixedWidth($newWidth);  
        } else if ($newHeight > $newWidth) {  
            $optimalWidth = $this->getSizeByFixedHeight($newHeight);  
            $optimalHeight= $newHeight;  
        } else {  
            // *** Sqaure being resized to a square  
            $optimalWidth = $newWidth;  
            $optimalHeight= $newHeight;  
        }  
    }  

    return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight);  
}  

private function getOptimalCrop($newWidth, $newHeight)  
{  

    $heightRatio = $this->height / $newHeight;  
    $widthRatio  = $this->width /  $newWidth;  

    if ($heightRatio < $widthRatio) {  
        $optimalRatio = $heightRatio;  
    } else {  
        $optimalRatio = $widthRatio;  
    }  

    $optimalHeight = $this->height / $optimalRatio;  
    $optimalWidth  = $this->width  / $optimalRatio;  

    return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight);  
}

PASSO 10 – CORTAR

Se optou por redimensionar e cortar o excedente, o corte irá ser feito a partir do centro. Este processo de corte é muito similar ao redimensionamento, mas com mais alguns parâmetros.

private function crop($optimalWidth, $optimalHeight, $newWidth, $newHeight)  
{  
    // *** Find center - this will be used for the crop  
    $cropStartX = ( $optimalWidth / 2) - ( $newWidth /2 );  
    $cropStartY = ( $optimalHeight/ 2) - ( $newHeight/2 );  

    $crop = $this->imageResized;  
    //imagedestroy($this->imageResized);  

    // *** Now crop from center to exact requested size  
    $this->imageResized = imagecreatetruecolor($newWidth , $newHeight);  
    imagecopyresampled($this->imageResized, $crop , 0, 0, $cropStartX, $cropStartY, $newWidth, $newHeight , $newWidth, $newHeight);  
}

PASSO 11 – GUARDAR A IMAGEM

Estamos quase a concluír. Agora é altura de guardar a imagem. Passamos a informação sobre a directoria e a qualidade da imagem que irá de 0 a 100, sendo 100 a melhor qualidade, e chamamos o método apropriado. Há alguns aspectos a ter em conta acerca da qualidade: JPG usa qualidade de 0 a 100. GIF não tem definição de qualidade de imagem. PNG tem, sendo uma escala de 0 a 9 com 0 a ser a melhor qualidade. Pode tornar-se um problema uma vez que teremos de nos lembrar destes aspectos quando quisermos guardar uma imagem. Assim, fazemos um pouco de magia e colocamos tudo de forma estandardizada.

public function saveImage($savePath, $imageQuality="100")  
{  
    // *** Get extension  
        $extension = strrchr($savePath, '.');  
        $extension = strtolower($extension);  

    switch($extension)  
    {  
        case '.jpg':  
        case '.jpeg':  
            if (imagetypes() & IMG_JPG) {  
                imagejpeg($this->imageResized, $savePath, $imageQuality);  
            }  
            break;  

        case '.gif':  
            if (imagetypes() & IMG_GIF) {  
                imagegif($this->imageResized, $savePath);  
            }  
            break;  

        case '.png':  
            // *** Scale quality from 0-100 to 0-9  
            $scaleQuality = round(($imageQuality/100) * 9);  

            // *** Invert quality setting as 0 is best, not 9  
            $invertScaleQuality = 9 - $scaleQuality;  

            if (imagetypes() & IMG_PNG) {  
                imagepng($this->imageResized, $savePath, $invertScaleQuality);  
            }  
            break;  

        // ... etc  

        default:  
            // *** No extension - No save.  
            break;  
    }  

    imagedestroy($this->imageResized);  
}

Como descrito no final, é destruída a imagem fonte para libertar alguma memória. Se for usado de forma cíclica, também será boa ideia fazer uma captura e devolver o resultado da última imagem guardada.

Até já!

 

Autor: Diogo Espinha

Blog do Autor | Artigos do Autor:

Workaholic e totalmente viciado em computadores, Internet e desporto motorizado. Adora praticar desporto, é um curioso da programação em PHP, CSS e HTML5 e não dispensa a companhia do seu Mac OSX 86 Snow Leopard!

  • Explorer - Factory Construction & Ship Building Joomla Theme
  • Justice - Attorney and Law Firm Joomla Template
  • OwnFolio - One Page Personal Portfolio / vCard / Resume / Showcase Joomla Template
  • Big Business - Responsive Template
  • Merab - Creative Multipurpose Drupal 8 Theme
  • Fitness Academy Joomla Template
  • Fruition - Business Joomla Template
  • Educate | Education & Courses, Kindergartens Joomla Template
  • Constructive - Contractors Multipurpose Joomla Landing Page Theme
  • Vina Bubox - VirtueMart Joomla Template for Online Stores
  • BizOne - One Page Parallax Drupal Theme
  • LawHouse - Responsive Lawyers Attorneys Joomla Template

Gostou deste artigo? Então torne-se fã do Blog no Facebook!



Comentários dos Alunos


  1. Jonathan [JCM]
    21 de outubro de 2010

    Interessante, mas eu já possuia um script que fazia isto por mim. xD
    O interessante disto é para montar sites de upload de imagens, e evitar que sejam enviadas imagens muito grandes.



    • Diogo Espinha
      28 de outubro de 2010

      Vejo que tem alguns conhecimentos na área, isso é óptimo!

      Quem sabe se não poderia partilhar algumas informações extra sobre o seu script?

      Obrigado pela visita e comentário!

      Abraço



      • Jonathan [JCM]
        29 de outubro de 2010

        Claro, na realidade no meu caso se enquadra mais sendo chamado de “mod”, pois usei em meu fórum phpbb3 uma função que ao ser chamada manda para o host (o mesmo tem que possuir o ImageMagick ativo) uma solicitação de redimensionamento de imagem e retornar a imagem redimensionada.
        Isto é muito útil para exibir os avatares somente em determinadas medidas ou proporções.
        Este seu é um pouco mais complexo por que ele salva a imagem redimensionada, este que utilizo apenas mostra a imagem redimensionada.



        • Diogo Espinha
          29 de outubro de 2010

          Obrigado por partilhar Jonathan!



  2. Celão
    26 de outubro de 2010

    Muito legal e útil.
    É verdade que existem dezenas de conteúdos como esses prontos pela web, mas nada melhor do que um artigo explicando passo-a-passo de cada processo e seus respectivos funcionamentos.

    Parabéns pelo post!



    • Diogo Espinha
      28 de outubro de 2010

      Muito obrigado Celão. De facto foi um ponto que teve bastante importância durante a criação do artigo, explicar passo-a-passo como fazer seguir esse tutorial, é algo que não é comum na maioria dos tutoriais espalhados pela Web.

      Abraço!



      • Celão
        29 de outubro de 2010

        Diogo,

        Valeu pela resposta e sucesso com o blog. Vou acompanhar de perto a partir de agora!

        Abs



  3. Sérgio Coutiy
    29 de setembro de 2011

    Caro amigo Diogo, eu estou tentando compreender como elaborar um script de redimensionamento de imagem, e em tudo que li até agora, o seu código me pareceu ter uma lógica estrutural, no entanto não entendi qual a disposição do código na explicação que faz acima. Estou já a alguns dias tentando fazer o meu código funcionar. De forma eficaz, espero não estar incomodando; se puder, já que disponibiliza o código aqui no site escolacriatividade me enviar no meu email um previa do escript, se puder fico agradecido, caso não possa entenderei, fico no aguardo e estudando! Valeu a té.


RSS
Twitter
Facebook
Comentários
ASSINANTES
SEGUIDORES
FÃS
COMENTÁRIOS
7794

Subscrever Newsletter
Subscreva a Newsletter:



Aplicativos Android, iPhone e Muito Mais!




Assine a Escola Criatividade Assine a Newsletter da Escola Criatividade Escola Criatividade no Twitter Escola Criatividade no Facebook Escola Criatividade no Youtube Escola Criatividade no Google Buzz