Recortando imagens com jCrop e CodeIgniter

Recortar imagens para torná-las compatíveis com o layout onde elas serão exibidas é um recurso muito utilizado hoje em dia, e esse tutorial vai ter mostrar como fazer isso de maneira bem simples.

Passo 1 – Montando o ambiente

Para esse tutorial será necessário o download do CodeIgniter, do jQuery e do jCrop.

CodeIgniter

Você pode fazer o download e instalação do CodeIgniter seguindo nossos tutoriais:

jQuery

Você pode fazer o download do arquivo no site (http://jquery.com/), salvá-lo em ‘assets/js’ e fazer a chamada dele no HTML apontando para o esse arquivo salvo em ‘assets/js’.

Ou então pode apenas fazer a chamada do jQuery no HTML usando o link direto do CDN do jQuery (https://code.jquery.com/jquery-1.12.3.min.js).

O importante é que ele seja chamado na sua página, pois o jCrop precisa dele pra funcionar.

jCrop

Faça o download do jCrop (http://deepliquid.com/content/Jcrop_Download.html) e após concluí-lo descompacte os arquivos, localize os diretórios ‘css’ e ‘js’ e copie os arquivos desses diretórios para ‘assets/js’ e ‘assets/css’, respectivamente.

Após esse procedimento, não se esqueça de chamar no HTML tanto o CSS quanto os JavaScripts.

Para arquivos salvos no diretório do projeto:

<!-- jQuery -->
<script src="<?=base_url('assets/js/1.12.2.min.js')?>"></script>

<!-- Plugin jCrop -->
<script src="<?=base_url('assets/js/jquery.Jcrop.js')?>"></script>

Para arquivos usando CDN:

<!-- jQuery -->
<script src="https://code.jquery.com/jquery-1.12.3.min.js"></script>

<!-- Plugin jCrop -->
<script src="<?=base_url('assets/js/jquery.Jcrop.js')?>"></script>

Repare que foi utilizada a função ‘base_url()’ para definir o caminho. Essa função retorna a URL absoluta da aplicação concatenada com o path passado como parâmetro para ela.

Diretórios

Na raiz da aplicação, no mesmo nível de ‘application’, crie um diretório chamado ‘uploads’ com permissão de leitura e escrita, e dentro dele crie um outro diretório chamado ‘crops’, com as mesmas permissões.

Esses diretórios serão utilizados para armazenar as imagens originais gravadas através do processo de upload e as imagens recortadas, gravadas através do processo de recorte.

Passo 2 – Configurações

Vamos precisar configurar o carregamento do helper ‘url’ no arquivo ‘application/config/autoload.php’ e as rotas no arquivo ‘application/config/routes.php’.

Autoload

Abra o arquivo ‘application/config/autoload.php’ e adicione o helper ‘url’ para carregamento automático.

$autoload['helper'] = array('url');

Rotas

Abra o arquivo ‘application/config/routes.php’ e atualize-o conforme o código abaixo:

$route['default_controller'] = 'Base';
$route['recortar'] = 'Base/Recortar';
$route['visualizacao'] = 'Base/Visualizacao';

  • default_controller: definido como Base (que será criado mais adiante)
  • recortar: chama o método Recortar do controller Base, que processará o recorte da imagem
  • visualizacao: chama o método Visualizacao do controller Base, que irá recuperar as informações das imagens e exibí-la na tela

Passo 3 – Criando as views

Vamos criar 2 views, uma para a home e outra para a visualização da imagem recortada e os dados da imagem e do recorte.

Home

Crie um arquivo chamado ‘home.php’ dentro do diretório ‘application/views’ e adicione a ele o código abaixo.

Esse código é apenas o HTML dos elementos principais, você deverá adicionar a ele os cabeçalhos HTML e as chamadas aos arquivo CSS e JavaScript, conforme mostrado mais acima.

<div>
    <div>
        <?php if(isset($error)):?>
            <div><?=$error?></div>
        <?php endif; ?>
        <form action="<?=base_url('recortar')?>" method="POST" enctype="multipart/form-data">
            <div>
                <label>Selecione uma imagem em formato jpg ou png</label>
                <input type="file" name="imagem" id="seleciona-imagem"/>
            </div>
    </div>
    <div>
        <p>Selecione uma imagem para recortar</p>
        <div id="imagem-box">
            <img src="" style="display:none;width:100%;" id="visualizacao_img" />
        </div>
        <input type="hidden" id="x" name="x" />
        <input type="hidden" id="y" name="y" />
        <input type="hidden" id="wcrop" name="wcrop" />
        <input type="hidden" id="hcrop" name="hcrop" />
        <input type="hidden" id="wvisualizacao" name="wvisualizacao" />
        <input type="hidden" id="hvisualizacao" name="hvisualizacao" />
        <input type="hidden" id="woriginal" name="woriginal" />
        <input type="hidden" id="horiginal" name="horiginal" />
        <div>
            <input type="submit" value="Recortar" id="recortar-imagem"/>
        </div>
        </form>
    </div>
</div>

Temos uma view com uma verificação de mensagens de erro logo no início, que será exibida caso seja encontrado algum erro durante o processo de upload e recorte da imagem. Além disso ela possui uma formulário que chama a rota ‘recortar’, que irá processar os dados contidos no formulário, que envia para o controller as informações de tamanho da imagem na área de exibição, posicionamento e tamanho do ponto de corte e tamanho da imagem original.

Visualização

Crie um arquivo chamado ‘visualizacao.php’ dentro do diretório ‘application/views’ e adicione a ele o código abaixo.

Esse código é apenas o HTML dos elementos principais, você deverá adicionar a ele os cabeçalhos HTML e as chamadas aos arquivo CSS e JavaScript, conforme mostrado mais acima.

<div>
    <div>
        <h3>Imagem Recortada</h3>
        <hr />
        <div>
            <img src="<?=$this->session->flashdata('urlImagem')?>"/>
        </div>
        <p><a href="<?=base_url()?>">Nova Imagem</a></p>
    </div>
    <?php if($this->session->flashdata('dadosImagem') == TRUE): ?>
    <div>
        <h3>Informações da Imagem</h3>
        <hr />
        <ul>
            <?php foreach($this->session->flashdata('dadosImagem') as $key => $value): ?>
            <li><strong><?=$key?></strong> => <?=$value?></li>
            <?php endforeach; ?>
        </ul>
        <hr/>
        <h3>Informações do Recorte</h3>
        <hr />
        <ul>
            <?php foreach($this->session->flashdata('dadosCrop') as $key => $value): ?>
            <li><strong><?=$key?></strong> => <?=$value?></li>
            <?php endforeach; ?>
        </ul>
    </div>
    <?php endif; ?>
</div>

Assim como a home, essa é uma view simples, ela exibe a imagem que foi recortada e através de dois loops foreach exibe as informações sobre a imagem recortada e sobre o ponto de corte.

Passo 4 – Criando o controller

O controller é onde fica toda a codificação das operações a serem realizadas. Crie um arquivo chamado ‘Base.php’ em ‘application/controllers’ e adicione o código abaixo:

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Base extends CI_Controller {

    // Classe construtora
    public function __construct(){
        parent::__construct();
        // Carrega as libraries necessárias: session, upload e image_lib
        $this->load->library(['session','upload','image_lib']);
    }

    // Acionando para exibir a home
    public function Index()
    {
        // Carrega a view da home
        $this->load->view('home');
    }

    // Acionado após o recorte da imagem
    public function Visualizacao()
    {
        // Exibe a view com os dados da imagem recortada
        $this->load->view('visualizacao');
    }

    // Executa o processo de recorte da imagem
    public function Recortar(){

        // Configurações para o upload da imagem
        // Diretório para gravar a imagem
        $configUpload['upload_path']   = './uploads/';
        // Tipos de imagem permitidos
        $configUpload['allowed_types'] = 'jpg|png';
        // Usar nome de arquivo aleatório, ignorando o nome original do arquivo
        $configUpload['encrypt_name']  = TRUE;

        // Aplica as configurações para a library upload
        $this->upload->initialize($configUpload);

        // Verifica se o upload foi efetuado ou não
        // Em caso de erro carrega a home exibindo as mensagens
        // Em caso de sucesso faz o processo de recorte
        if ( ! $this->upload->do_upload('imagem'))
        {
            // Recupera as mensagens de erro e envia o usuário para a home
            $data= array('error' => $this->upload->display_errors());
            $this->load->view('home',$data);
        }
        else
        {
            // Recupera os dados da imagem
            $dadosImagem = $this->upload->data();

            // Calcula os tamanhos de ponto de corte e posição
            // de forma proporcional em relação ao tamanho da
            // imagem original
            $tamanhos = $this->CalculaPercetual($this->input->post());

            // Define as configurações para o recorte da imagem
            // Biblioteca a ser utilizada
            $configCrop['image_library'] = 'gd2';
            //Path da imagem a ser recortada
            $configCrop['source_image']  = $dadosImagem['full_path'];
            // Diretório onde a imagem recortada será gravada
            $configCrop['new_image']     = './uploads/crops/';
            // Proporção
            $configCrop['maintain_ratio']= FALSE;
            // Qualidade da imagem
            $configCrop['quality']             = 100;
            // Tamanho do recorte
            $configCrop['width']         = $tamanhos['wcrop'];
            $configCrop['height']        = $tamanhos['hcrop'];
            // Ponto de corte (eixos x e y)
            $configCrop['x_axis']        = $tamanhos['x'];
            $configCrop['y_axis']        = $tamanhos['y'];

            // Aplica as configurações para a library image_lib
            $this->image_lib->initialize($configCrop);

            // Verifica se o recorte foi efetuado ou não
            // Em caso de erro carrega a home exibindo as mensagens
            // Em caso de sucesso envia o usuário para a tela
            // de visualização do recorte
            if ( ! $this->image_lib->crop())
            {
                // Recupera as mensagens de erro e envia o usuário para a home
                $data = array('error' => $this->image_lib->display_errors());
                $this->load->view('home',$data);
            }
            else
            {
                // Define a URL da imagem gerada após o recorte
                $urlImagem = base_url('uploads/crops/'.$dadosImagem['file_name']);

                // Grava a informação na sessão
                $this->session->set_flashdata('urlImagem', $urlImagem);

                // Grava os dados da imagem recortada na sessão
                $this->session->set_flashdata('dadosImagem', $dadosImagem);

                // Grava os dados da imagem original na sessão
                $this->session->set_flashdata('dadosCrop', $tamanhos);

                // Redireciona o usuário para a tela de visualização dos dados
                redirect('visualizacao');
            }
        }
    }

    // Método privado responsável por calcular os tamanhos de forma proporcional
    private function CalculaPercetual($dimensoes){
        // Verifica se a largura da imagem original é
        // maior que a da área de recorte, se for calcula o tamanho proporcional
        if($dimensoes['woriginal'] > $dimensoes['wvisualizacao']){
            $percentual = $dimensoes['woriginal'] / $dimensoes['wvisualizacao'];

            $dimensoes['x'] = round($dimensoes['x'] * $percentual);
            $dimensoes['y'] = round($dimensoes['y'] * $percentual);
            $dimensoes['wcrop'] = round($dimensoes['wcrop'] * $percentual);
            $dimensoes['hcrop'] = round($dimensoes['hcrop'] * $percentual);
        }

        // Retorna os valores a serem utilizados no processo de recorte da imagem
        return $dimensoes;
    }
}

Agora todas as operações a serem realizadas no servidor já foram codificadas, falta apenas fazer a codificação do JavaScript para que o jCrop funcione.

Passo 5 – Código JavaScript para o jCrop

Crie um arquivo chamado ‘scripts.js’ no diretório ‘assets/js’ que deverá ter sido criado na raiz do projeto – no mesmo nível de ‘application’ – no primeiro passo desse tutorial.

Coloque o código abaixo no arquivo:

$(document).ready(function(){

  // Ao selecionar uma imagem, ela é exibida
  // sem a necessidade de envio para o servidor
  // através e um upload
  $("#seleciona-imagem").change(function(){
    if (this.files && this.files[0]) {
        var reader = new FileReader();

        // Define o que será executado após o carregamento da imagem
        reader.onload = function (e) {
            // Passa para os elementos no DOM as informações
            // sobre a imagem a ser exibida e os textos
            $('#visualizacao_img').attr('src', e.target.result);
            $('#visualizacao_img').removeClass('hidden');
            $('#recortar-imagem').removeClass('hidden');
            $('#texto-informativo').html('Arraste o cursor sobre a imagem para selecionar a área de corte.');
            $('#texto-informativo').removeClass('alert-info').addClass('alert-success');

            // Ativa o recurso de recorte
            $('#visualizacao_img').Jcrop({
              aspectRatio: 1,
              onSelect: atualizaCoordenadas,
              onChange: atualizaCoordenadas
            });

            // Calcula o tamanho da imagem
            defineTamanhoImagem(e.target.result,$('#visualizacao_img'));
        }

        // Carrega a imagem e chama o 'reader.onload'
        reader.readAsDataURL(this.files[0]);
    }
  });

  // Ao tentar clicar o botão recortar
  // verifica se foi definida alguma área de corte
  $('#recortar-imagem').click(function(){
    if (parseInt($('#wcrop').val())) return true;
    alert('Selecione a área de corte para continuar.');
    return false;
  });
})

// Faz a atualização das coordenadas em relação ao ponto de corte
// cada vez que esse é modificado
// É chamado nos eventos onSelect e onChange do jCrop
function atualizaCoordenadas(c)
{
  $('#x').val(c.x);
  $('#y').val(c.y);
  $('#wcrop').val(c.w);
  $('#hcrop').val(c.h);
};

// Faz a verificação e define o tamanho da imagem original
// e da imagem na área de visualização para o recorte
function defineTamanhoImagem(imgOriginal, imgVisualizacao) {
  var image = new Image();
  image.src = imgOriginal;

  image.onload = function() {
    $('#wvisualizacao').val(imgVisualizacao.width());
    $('#hvisualizacao').val(imgVisualizacao.height());
    $('#woriginal').val(this.width);
    $('#horiginal').val(this.height);
  };
}

Não se esqueça de atualizar as views adicionando a chamada a esse novo arquivo JavaScript, conforme mostrado no primeiro passo.

Pronto! A codificação para o recorte de imagens usando jCrop e CodeIgniter está pronta e você já pode aplicar em seus projetos.

Bons Estudos!!!

 

Download do código-fonte no githubDemo Online