Construa uma Ferramenta de Corte de Imagem Usando HTML5

JavaScriptBeginner
Pratique Agora

Introdução

Este projeto irá guiá-lo através do processo de criação de uma ferramenta simples de corte de imagens. No final, você terá uma aplicação interativa que permite aos usuários carregar, exibir e cortar imagens.

👀 Pré-visualização

Demonstração da ferramenta de corte de imagem

🎯 Tarefas

Neste projeto, você aprenderá:

  • Como criar a estrutura HTML para a ferramenta de corte de imagem
  • Como estilizar a página web usando CSS para torná-la visualmente atraente
  • Como inicializar variáveis e event listeners (ouvintes de eventos) usando JavaScript para lidar com as interações do usuário
  • Como lidar com o carregamento e exibição de imagens usando a API FileReader em JavaScript
  • Como implementar o mecanismo de corte usando a API Canvas em JavaScript
  • Como salvar a imagem cortada e exibir o resultado

🏆 Conquistas

Após concluir este projeto, você será capaz de:

  • Compreender as tags (etiquetas) e a estrutura HTML
  • Aplicar propriedades e seletores CSS de forma eficaz
  • Utilizar a sintaxe JavaScript, variáveis e event listeners
  • Aproveitar a API FileReader em JavaScript para lidar com uploads (carregamentos) de arquivos
  • Implementar a manipulação de imagens usando a API Canvas em JavaScript

Definir a Estrutura HTML

Requisitos:

  • Conhecimento de tags (etiquetas) e estrutura HTML.

Funcionalidade:

  • Projetar uma interface para permitir que os usuários carreguem uma imagem e acionem o processo de corte.

Incorpore o código HTML em seu index.html.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>HTML5 Crop Image</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <input type="file" name="file" id="post_file" />

    <button id="save_button">SAVE</button>
    <div id="label">
      <canvas id="get_image"></canvas>
      <p>
        <canvas id="cover_box"></canvas>
        <canvas id="edit_pic"></canvas>
      </p>
    </div>
    <p>
      <span id="show_edit"></span>
      <span id="show_pic"><img src="" /></span>
    </p>
    <script type="text/javascript" src="main.js"></script>
  </body>
</html>

As três tags <canvas> mencionadas acima são usadas para processar conteúdo relacionado a imagens. O tratamento detalhado será fornecido no código js (JavaScript) subsequente. Os elementos com o id show_edit e o id show_pic são para visualizar a imagem e ver o resultado final da geração da imagem.

✨ Verificar Solução e Praticar

Estilizar a Página Web

Requisitos:

  • Familiaridade com propriedades e seletores CSS.

Funcionalidade:

  • Estilizar os elementos HTML para tornar a interface amigável e visualmente atraente.

Incorpore o CSS em seu style.css.

body {
  background-color: #f6f6f6;
  margin: 0;
  padding: 20px;
  text-align: center;
}

#label {
  border: 1px solid #ccc;
  background-color: #fff;
  text-align: center;
  height: 300px;
  width: 300px;
  margin: 20px auto;
  position: relative;
}

#get_image {
  position: absolute;
}

#edit_pic {
  position: absolute;
  display: none;
  background: #000;
}

#cover_box {
  position: absolute;
  z-index: 9999;
  display: none;
  top: 0px;
  left: 0px;
}

#show_edit {
  margin: 0 auto;
  display: inline-block;
}

#show_pic {
  height: 100px;
  width: 100px;
  border: 2px solid #000;
  overflow: hidden;
  margin: 0 auto;
  display: inline-block;
}

canvas {
  position: absolute;
  top: 0;
  left: 0;
}

#save_button {
  padding: 8px 16px;
  background-color: #3498db;
  color: #fff;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  transition: background-color 0.2s;
}

#save_button:hover {
  background-color: #2980b9;
}

input[type="file"] {
  margin-bottom: 20px;
}
✨ Verificar Solução e Praticar

Inicializar Variáveis e Event Listeners

Requisitos:

  • Compreensão fundamental da sintaxe JavaScript, variáveis e event listeners (ouvintes de eventos).

Funcionalidade:

  • Inicializar propriedades e configurações para a ferramenta de corte. Adicionar um event listener (ouvinte de evento) para processar a imagem carregada.

Em main.js, escreva o código para inicializar as propriedades da ferramenta de corte e configurar os event listeners (ouvintes de eventos).

var postFile = {
  init: function () {
    var t = this;
    t.regional = document.getElementById("label");
    t.getImage = document.getElementById("get_image");
    t.editPic = document.getElementById("edit_pic");
    t.editBox = document.getElementById("cover_box");
    t.px = 0; //background image x
    t.py = 0; //background image y
    t.sx = 15; //crop area x
    t.sy = 15; //crop area y
    t.sHeight = 150; //crop area height
    t.sWidth = 150; //crop area width
    document
      .getElementById("post_file")
      .addEventListener("change", t.handleFiles, false);
  }
};

Todas as nossas funções e variáveis são encapsuladas dentro do objeto postFile. A função init mencionada acima define principalmente alguns valores iniciais.

t.px = 0;
t.py = 0;
t.sx = 15;
t.sy = 15;
t.sHeight = 100;
t.sWidth = 100;

As variáveis t.px e t.py representam as coordenadas da imagem de fundo na área de visualização em tempo real; t.sx, t.sy, t.sHeight e t.sWidth representam as coordenadas x, y e a largura e altura da imagem, respectivamente.

Também obtemos vários elementos que operaremos mais tarde através de document.getElementById.

document
  .getElementById("post_file")
  .addEventListener("change", t.handleFiles, false);

Estamos ouvindo o evento change do formulário input com o id post_file para processar os arquivos carregados pelo usuário. Aqui, delegamos isso à função handleFiles. Então, em seguida, implementaremos a função handleFiles.

✨ Verificar Solução e Praticar

Gerenciar Upload e Exibição de Imagens

Requisitos:

  • Conhecimento básico da API FileReader em JavaScript.

Funcionalidade:

  • Garantir que, quando os usuários carregam uma imagem, ela seja processada, lida e exibida corretamente na tela.

Expanda seu main.js com as funções para processar e exibir a imagem carregada.

  1. Para implementar a função handleFiles

    Aqui, estamos usando a API File do HTML5. Primeiro, invocando new FileReader(), instanciamos um objeto FileReader chamado oFReader. Em seguida, chamamos seu método readAsDataURL() para ler o conteúdo do arquivo e convertê-lo em um formato codificado em base64.

    Finalmente, quando o arquivo é totalmente lido e carregado, processamos a imagem que lemos usando postFile.paintImage(oFREvent.target.result). Em termos simples, estamos redesenhando os dados da imagem que lemos no navegador.

handleFiles: function () {
        var fileList = this.files[0];
        var oFReader = new FileReader();
        oFReader.readAsDataURL(fileList);
        oFReader.onload = function (oFREvent) {
            postFile.paintImage(oFREvent.target.result);
        };
},
  1. Para implementar a função paintImage

    A etapa mais crucial aqui é desenhar a imagem de acordo com o tamanho do contêiner usando canvas. Na etapa anterior, usando o FileReader da API File, já obtivemos a URL da imagem que queremos carregar (o valor de oFREvent.target.result). A próxima etapa é usar canvas para desenhar esta imagem. Primeiro, usamos getImage.getContext para obter o conteúdo 2d de <canvas id="get_image"></canvas>, que pode ser simplesmente entendido como o conteúdo da imagem. Depois disso, usamos new Image() para criar um elemento <img> e definir seu valor de atributo src.

paintImage: function (url) {
        var t = this;
        var createCanvas = t.getImage.getContext("2d");
        var img = new Image();
        img.src = url;
        img.onload = function () {
            if (
                img.width < t.regional.offsetWidth &&
                img.height < t.regional.offsetHeight
            ) {
                t.imgWidth = img.width;
                t.imgHeight = img.height;
            } else {
                var pWidth = img.width / (img.height / t.regional.offsetHeight);
                var pHeight = img.height / (img.width / t.regional.offsetWidth);
                t.imgWidth = img.width > img.height ? t.regional.offsetWidth : pWidth;
                t.imgHeight =
                    img.height > img.width ? t.regional.offsetHeight : pHeight;
            }
            t.px = (t.regional.offsetWidth - t.imgWidth) / 2 + "px";
            t.py = (t.regional.offsetHeight - t.imgHeight) / 2 + "px";

            t.getImage.height = t.imgHeight;
            t.getImage.width = t.imgWidth;
            t.getImage.style.left = t.px;
            t.getImage.style.top = t.py;

            createCanvas.drawImage(img, 0, 0, t.imgWidth, t.imgHeight);
            t.imgUrl = t.getImage.toDataURL();
            t.cutImage();
            t.drag();
        };
},

Dentro da função img.onload, nosso objetivo principal é redesenhar a imagem em seu tamanho original, mantendo suas proporções, e é por isso que temos uma condição if. Em última análise, usamos a linha de código createCanvas.drawImage(img,0,0,t.imgWidth,t.imgHeight); para realmente renderizar a imagem.

✨ Verificar Solução e Praticar

Implementar o Mecanismo de Corte (Cropping)

Requisitos:

  • Familiaridade com a API Canvas em JavaScript para desenho e manipulação de imagens.

Funcionalidade:

  • Adicionar uma região de corte na imagem exibida e tornar essa região arrastável. Isso oferece aos usuários a flexibilidade de selecionar a área desejada para cortar.

Adicione os métodos relevantes em main.js.

  1. Crie um método cutImage

    O método cutImage é principalmente responsável por duas tarefas: uma é criar uma camada de máscara, e a outra é usar a propriedade CSS background para fornecer uma visualização em tempo real da área de corte selecionada.

cutImage: function () {
        var t = this;

        t.editBox.height = t.imgHeight;
        t.editBox.width = t.imgWidth;
        t.editBox.style.display = "block";
        t.editBox.style.left = t.px;
        t.editBox.style.top = t.py;

        var cover = t.editBox.getContext("2d");
        cover.fillStyle = "rgba(0, 0, 0, 0.5)";
        cover.fillRect(0, 0, t.imgWidth, t.imgHeight);
        cover.clearRect(t.sx, t.sy, t.sHeight, t.sWidth);

        document.getElementById("show_edit").style.background =
            "url(" + t.imgUrl + ")" + -t.sx + "px " + -t.sy + "px no-repeat";
        document.getElementById("show_edit").style.height = t.sHeight + "px";
        document.getElementById("show_edit").style.width = t.sWidth + "px";
},
  1. Crie um método drag
drag: function () {
        var t = this;
        var draging = false;
        var startX = 0;
        var startY = 0;

        document.getElementById("cover_box").onmousemove = function (e) {
            var pageX = e.pageX - (t.regional.offsetLeft + this.offsetLeft);
            var pageY = e.pageY - (t.regional.offsetTop + this.offsetTop);

            if (
                pageX > t.sx &&
                pageX < t.sx + t.sWidth &&
                pageY > t.sy &&
                pageY < t.sy + t.sHeight
            ) {
                this.style.cursor = "move";

                this.onmousedown = function () {
                    draging = true;

                    t.ex = t.sx;
                    t.ey = t.sy;

                    startX = e.pageX - (t.regional.offsetLeft + this.offsetLeft);
                    startY = e.pageY - (t.regional.offsetTop + this.offsetTop);
                };
                window.onmouseup = function () {
                    draging = false;
                };

                if (draging) {
                    if (t.ex + (pageX - startX) < 0) {
                        t.sx = 0;
                    } else if (t.ex + (pageX - startX) + t.sWidth > t.imgWidth) {
                        t.sx = t.imgWidth - t.sWidth;
                    } else {
                        t.sx = t.ex + (pageX - startX);
                    }

                    if (t.ey + (pageY - startY) < 0) {
                        t.sy = 0;
                    } else if (t.ey + (pageY - startY) + t.sHeight > t.imgHeight) {
                        t.sy = t.imgHeight - t.sHeight;
                    } else {
                        t.sy = t.ey + (pageY - startY);
                    }

                    t.cutImage();
                }
            } else {
                this.style.cursor = "auto";
            }
        };
},

Para entender este método, você precisa entender os seguintes pontos-chave:

var pageX = e.pageX - (t.regional.offsetLeft + this.offsetLeft);
var pageY = e.pageY - (t.regional.offsetTop + this.offsetTop);

Com as duas linhas de código acima, obtemos a distância entre o mouse e a imagem de fundo. e.pageX representa a distância do mouse para a borda esquerda do navegador, e t.regional.offsetLeft + this.offsetLeft calcula a distância da imagem para a borda esquerda do navegador. Da mesma forma, a distância superior pode ser deduzida.

 if ( pageX > t.sx && pageX < t.sx + t.sWidth && pageY > t.sy && pageY < t.sy + t.sHeight )

Tendo entendido a distância entre o mouse e a imagem de fundo, isso deve ser fácil de entender: ele determina se o mouse está dentro da região da imagem.

t.ex = t.sx;
t.ey = t.sy;

startX = e.pageX - (t.regional.offsetLeft + this.offsetLeft);
startY = e.pageY - (t.regional.offsetTop + this.offsetTop);

Esses dois trechos de código valem a pena destacar. As duas primeiras linhas registram as coordenadas da última captura de tela (ou, se não houve uma anterior, então as coordenadas iniciais); as duas linhas seguintes registram as coordenadas quando o mouse é pressionado. Você pode inspecionar esses valores separadamente usando console.log().

if (draging) {
  if (t.ex + (pageX - startX) < 0) {
    t.sx = 0;
  } else if (t.ex + (pageX - startX) + t.sWidth > t.imgWidth) {
    t.sx = t.imgWidth - t.sWidth;
  } else {
    t.sx = t.ex + (pageX - startX);
  }

  if (t.ey + (pageY - startY) < 0) {
    t.sy = 0;
  } else if (t.ey + (pageY - startY) + t.sHeight > t.imgHeight) {
    t.sy = t.imgHeight - t.sHeight;
  } else {
    t.sy = t.ey + (pageY - startY);
  }

  t.cutImage();
}

O código acima essencialmente diz: se estamos no meio do arrastar, precisamos atualizar os valores de t.sx e t.sy em tempo real com base nas mudanças de coordenadas e chamar o método cutImage para fornecer uma visualização ao vivo.

As coordenadas da área de corte durante o movimento = última posição registrada + (posição atual do mouse - posição quando o mouse foi pressionado)

✨ Verificar Solução e Praticar

Salvar a Imagem Cortada

Requisitos:

  • Conhecimento de como usar canvas para extrair e exibir dados de imagem.

Funcionalidade:

  • Após cortar a área desejada da imagem, permitir que os usuários salvem esta região cortada, exibindo o resultado na tela.

Melhore a função de inicialização em main.js para lidar com a salvamento da imagem cortada.

var postFile = {
  init: function () {
    // ...
    document.getElementById("save_button").onclick = function () {
      t.editPic.height = t.sHeight;
      t.editPic.width = t.sWidth;
      var ctx = t.editPic.getContext("2d");
      var images = new Image();
      images.src = t.imgUrl;

      images.onload = function () {
        ctx.drawImage(
          images,
          t.sx,
          t.sy,
          t.sHeight,
          t.sWidth,
          0,
          0,
          t.sHeight,
          t.sWidth
        );
        document.getElementById("show_pic").getElementsByTagName("img")[0].src =
          t.editPic.toDataURL();
      };
    };
  }
};
postFile.init();

Semelhante à implementação do método paintImage, primeiro ouvimos o evento de clique no botão salvar. Em seguida, usamos o método drawImage para renderizar a região da imagem selecionada. Finalmente, empregamos o método toDataURL para converter a imagem em um formato codificado em base64. Este valor é então atribuído ao atributo src da img sob show_pic. Desta forma, o corte e salvamento da imagem são concluídos.

✨ Verificar Solução e Praticar

Testar a Ferramenta

  • Abra index.html em um navegador web.
    open web
  • Carregue uma imagem e teste a funcionalidade de corte.
  • O efeito da página é o seguinte:
    image cropping tool demo
✨ Verificar Solução e Praticar

Resumo

Parabéns! Você construiu uma ferramenta básica de corte de imagem usando HTML5 e JavaScript. Esta base pode ser utilizada para funcionalidades mais avançadas ou outras tarefas de manipulação de imagem. Pratique aprimorando a ferramenta ou explorando outros projetos de desenvolvimento web!