SWCore
SWCore / Componentes / Recorte de imagem

Recorte de imagem Componentes

A pessoa escolhe uma foto, arrasta o quadro para enquadrar e corta no formato certo (quadrado, 16:9, retrato). Sai uma imagem WebP pronta. <div sw-cropper sw-cropper-ratio='1'>.

O que é

É o "trocar foto de perfil" dos sites: a pessoa escolhe uma imagem, aparece um quadro claro por cima da foto (o resto fica escurecido), ela arrasta o quadro até a parte que quer e clica em Cortar. A foto recortada sai sempre no formato que você definiu — quadrado para avatar, largo para capa, em pé para retrato — e pode ir direto para um <img> da página ou ser enviada ao servidor.

Tudo acontece no navegador, desenhado num <canvas>, sem biblioteca de fora. Dentro da <div sw-cropper> você coloca três peças marcadas por atributo: o campo de escolher arquivo (sw-cropper-input), a tela de recorte (sw-cropper-canvas) e o botão de cortar (sw-cropper-btn). A tela e o botão só aparecem depois que uma foto é carregada. Ao cortar, ele gera um WebP de 800 px de largura e: (a) com sw-cropper-upload="#", coloca o resultado no <img> de sw-cropper-out sem enviar nada; (b) com um endereço, envia para o seu servidor e usa o endereço que ele devolver.

Quando usar

  • Foto de perfil / avatar no cadastro ou na área do cliente — quadrado.
  • Capa de post, banner, imagem de destaque no painel admin — 16:9.
  • Foto de produto ou de profissional no formato certo da vitrine — retrato 3:4 ou quadrado.
  • Sempre que a imagem precisa sair num tamanho padrão, para o site não ficar com fotos desencontradas.

Comece aqui

  1. 1

    Coloque o SWCore na página: CSS no <head> e JS no fim do <body>. O segundo CSS só é preciso se usar ícone swi-* no botão.

    <link rel="stylesheet" href="https://swcore.sanweb.com.br/dist/2.1.0/swcore.min.css">
    <link rel="stylesheet" href="https://swcore.sanweb.com.br/dist/2.1.0/swcore.compl.min.css">
    
    <!-- fim do <body> -->
    <script src="https://swcore.sanweb.com.br/dist/2.1.0/swcore.min.js"></script>
  2. 2

    Monte a div com as três peças e um <img> para o resultado. Clique em Escolher foto, arraste o quadro claro e clique em Cortar.

    Sua foto recortada
    <div sw-cropper sw-cropper-ratio="1" sw-cropper-upload="#" sw-cropper-out="#foto">
      <label sw-btn="pri">
        <i class="swi-image"></i> Escolher foto
        <input type="file" accept="image/*" sw-cropper-input hidden>
      </label>
      <div class="sw-cropper-stage"><canvas sw-cropper-canvas></canvas></div>
      <button type="button" sw-btn="suc" sw-cropper-btn>Cortar</button>
    </div>
    <img id="foto" class="sw-cropper-out is-round" alt="Sua foto recortada">

Todas as variações

Cada quadro abaixo é o componente de verdade, rodando. O código embaixo é exatamente o que está no quadro: copie e cole.

1. Formato do recorte (proporção)

sw-cropper-ratio é a largura dividida pela altura. 1 = quadrado (padrão), 1.7777 = 16:9, 0.75 = 3:4 em pé, 1.3333 = 4:3. Estes quadros já abrem com uma foto (sw-cropper-src): arraste o quadro claro e clique em Cortar.

Recorte quadrado
Quadrado — sw-cropper-ratio="1"
<div sw-cropper sw-cropper-ratio="1" sw-cropper-upload="#"
     sw-cropper-src="/imagens/foto.png" sw-cropper-out="#recorte">
  <div class="sw-cropper-stage"><canvas sw-cropper-canvas></canvas></div>
  <button type="button" sw-btn="suc p" sw-cropper-btn>Cortar</button>
</div>
<img id="recorte" class="sw-cropper-out" alt="Recorte quadrado">
Recorte 16:9
16:9 (capa, banner) — sw-cropper-ratio="1.7777"
<div sw-cropper sw-cropper-ratio="1.7777" sw-cropper-upload="#"
     sw-cropper-src="/imagens/foto.png" sw-cropper-out="#capa">
  <div class="sw-cropper-stage"><canvas sw-cropper-canvas></canvas></div>
  <button type="button" sw-btn="suc p" sw-cropper-btn>Cortar</button>
</div>
<img id="capa" class="sw-cropper-out" alt="Recorte 16:9">
Recorte retrato
Retrato 3:4 — sw-cropper-ratio="0.75"
<div sw-cropper sw-cropper-ratio="0.75" sw-cropper-upload="#"
     sw-cropper-src="/imagens/foto.png" sw-cropper-out="#retrato">
  <div class="sw-cropper-stage"><canvas sw-cropper-canvas></canvas></div>
  <button type="button" sw-btn="suc p" sw-cropper-btn>Cortar</button>
</div>
<img id="retrato" class="sw-cropper-out" alt="Recorte retrato">

2. Prévia ao vivo

sw-cropper-preview aponta para um elemento que mostra o recorte enquanto a pessoa arrasta. A classe sw-cropper-prev deixa esse elemento redondo (tipo avatar); some is-sqr para canto reto. Arraste o quadro e veja a bolinha mudar.

Assim vai ficar sua foto.
Foto de perfil
Prévia redonda — sw-cropper-prev
<div sw-cropper sw-cropper-ratio="1" sw-cropper-upload="#"
     sw-cropper-src="/imagens/foto.png"
     sw-cropper-preview="#previa" sw-cropper-out="#avatar">
  <div class="sw-cropper-row">
    <div id="previa" class="sw-cropper-prev"></div>
    <span class="sw-cropper-hint">Assim vai ficar sua foto.</span>
  </div>
  <div class="sw-cropper-stage"><canvas sw-cropper-canvas></canvas></div>
  <button type="button" sw-btn="suc p" sw-cropper-btn>Usar esta foto</button>
</div>
<img id="avatar" class="sw-cropper-out is-round" alt="Foto de perfil">
Miniatura do produto.
Foto do produto
Prévia quadrada — sw-cropper-prev is-sqr
<div sw-cropper sw-cropper-ratio="1" sw-cropper-upload="#"
     sw-cropper-src="/imagens/foto.png"
     sw-cropper-preview="#miniatura" sw-cropper-out="#produto">
  <div class="sw-cropper-row">
    <div id="miniatura" class="sw-cropper-prev is-sqr"></div>
    <span class="sw-cropper-hint">Miniatura do produto.</span>
  </div>
  <div class="sw-cropper-stage"><canvas sw-cropper-canvas></canvas></div>
  <button type="button" sw-btn="suc p" sw-cropper-btn>Cortar</button>
</div>
<img id="produto" class="sw-cropper-out" alt="Foto do produto">

3. Onde vai o resultado

sw-cropper-out escolhe o(s) <img> que recebem a foto cortada (pode ser mais de um: "#topo, #perfil"). A classe sw-cropper-out deixa o <img> escondido até existir um recorte; com is-round ele aparece redondo, com 96 px.

Avatar do topoFoto grande do perfil
Um recorte em dois lugares (topo + perfil)
<div sw-cropper sw-cropper-ratio="1" sw-cropper-upload="#"
     sw-cropper-src="/imagens/foto.png" sw-cropper-out="#avatar-topo, #foto-perfil">
  <div class="sw-cropper-stage"><canvas sw-cropper-canvas></canvas></div>
  <button type="button" sw-btn="suc p" sw-cropper-btn>Cortar</button>
</div>
<img id="avatar-topo" class="sw-cropper-out is-round" alt="Avatar do topo">
<img id="foto-perfil" class="sw-cropper-out" alt="Foto grande do perfil">

Tabela de opções

PalavraO que fazExemplo
Peças (dentro da div)
sw-cropperNa <div> que junta tudo.<div sw-cropper>
sw-cropper-inputNo <input type="file"> que escolhe a foto. Pode esconder com hidden e pôr dentro de um <label sw-btn>.<input type="file" accept="image/*" sw-cropper-input hidden>
sw-cropper-canvasNo <canvas> onde se enquadra. Só aparece quando há foto.<canvas sw-cropper-canvas></canvas>
sw-cropper-btnNo botão que corta. Só aparece quando há foto.<button type="button" sw-cropper-btn>
Formato e foto inicial
sw-cropper-ratioLargura ÷ altura do recorte. Padrão 1 (quadrado). 0 = formato livre: o quadro nasce com 80% da foto e estica pela alça do canto de baixo à direita.sw-cropper-ratio="1.7777"
sw-cropper-srcFoto que já abre carregada (ex.: a foto atual na tela de editar). Precisa estar no mesmo site.sw-cropper-src="/fotos/atual.jpg"
Resultado
sw-cropper-outSeletor do(s) <img> que recebem o recorte.sw-cropper-out="#foto"
sw-cropper-previewSeletor do elemento que mostra a prévia ao vivo (como imagem de fundo).sw-cropper-preview="#previa"
Envio ao servidor
sw-cropper-uploadEndereço que recebe o recorte. # = não envia, só mostra na página. Sem o atributo, envia para /api/imgs/upload.sw-cropper-upload="/perfil/foto"
sw-cropper-tipoTexto enviado no campo tipo. Padrão avatar.sw-cropper-tipo="capa"
sw-cropper-refEnviado no campo ref_id — de quem é a foto (id do usuário, do produto).sw-cropper-ref="42"
sw-cropper-localEnviado no campo local — pasta/destino para o seu servidor usar.sw-cropper-local="perfis"
Classes de visual (opcionais)
sw-cropper-stageMoldura em volta do canvas; só aparece quando há foto.<div class="sw-cropper-stage">
sw-cropper-rowLinha para pôr a prévia e um texto lado a lado.<div class="sw-cropper-row">
sw-cropper-prevBolinha de prévia (redonda). is-sqr = canto reto.<div class="sw-cropper-prev is-sqr">
sw-cropper-hintTexto pequeno de ajuda.<span class="sw-cropper-hint">
sw-cropper-outNo <img> de resultado: fica escondido até ter recorte. is-round = redondo, 96 px.<img class="sw-cropper-out is-round">

Receitas prontas — usos reais

Situações que aparecem em quase todo site. Copie a que servir.

Trocar foto de perfil (área do cliente) Ao vivo
Foto de perfil
JPG ou PNG. Arraste o quadro para enquadrar o rosto.
<img id="foto-perfil" class="sw-cropper-out is-round" alt="Foto de perfil">

<div sw-cropper sw-cropper-ratio="1"
     sw-cropper-upload="/minha-conta/foto" sw-cropper-tipo="avatar" sw-cropper-ref="42"
     sw-cropper-preview="#previa" sw-cropper-out="#foto-perfil">
  <div class="sw-cropper-row">
    <div id="previa" class="sw-cropper-prev"></div>
    <label sw-btn="pri p">
      <i class="swi-image"></i> Trocar foto
      <input type="file" accept="image/*" sw-cropper-input hidden>
    </label>
  </div>
  <span class="sw-cropper-hint">JPG ou PNG. Arraste o quadro para enquadrar o rosto.</span>
  <div class="sw-cropper-stage"><canvas sw-cropper-canvas></canvas></div>
  <button type="button" sw-btn="suc" sw-cropper-btn>Salvar foto</button>
</div>
Capa do post 16:9 (painel admin) Ao vivo
Capa do post
<div sw-cropper sw-cropper-ratio="1.7777"
     sw-cropper-upload="/admin/posts/capa" sw-cropper-tipo="capa" sw-cropper-local="blog"
     sw-cropper-out="#capa">
  <label sw-btn="out p">
    <i class="swi-image"></i> Escolher capa
    <input type="file" accept="image/*" sw-cropper-input hidden>
  </label>
  <div class="sw-cropper-stage"><canvas sw-cropper-canvas></canvas></div>
  <button type="button" sw-btn="pri p" sw-cropper-btn>Usar como capa</button>
  <img id="capa" class="sw-cropper-out" alt="Capa do post">
</div>
O que o seu servidor recebe e deve responder Referência
// O componente envia (POST, FormData):
//   dataUrl  → a imagem em WebP, como texto "data:image/webp;base64,..."
//   ref_id   → valor de sw-cropper-ref
//   local    → valor de sw-cropper-local
//   tipo     → valor de sw-cropper-tipo
// Cabeçalho X-CSRF-Token com o conteúdo de <meta name="csrf-token">.
//
// O servidor precisa responder JSON assim:
{ "ok": true, "img": "/uploads/perfis/42.webp", "thumb": "/uploads/perfis/42-p.webp", "id": 42 }
// ou, se der erro:
{ "ok": false, "erro": "Imagem muito grande" }
Avisar quando terminou ou deu erro Referência
const recorte = document.querySelector('[sw-cropper]');

recorte.addEventListener('sw:cropper:ready', () => {
  // a foto carregou; já dá para arrastar o quadro
});

recorte.addEventListener('sw:cropper:done', (e) => {
  // e.detail = { url, thumb, id }
  SW.Alert.ok('Foto atualizada!');
});

recorte.addEventListener('sw:cropper:error', (e) => {
  SW.Alert.err('Não deu para enviar: ' + e.detail.erro);
});

Eventos

sw:cropper:ready
A foto carregou e o quadro de recorte apareceu.
sw:cropper:done
O corte terminou. e.detail = { url, thumb, id }. Com sw-cropper-upload="#", url e thumb são a própria imagem (texto data:) e id é "demo"; com envio, vêm os campos img, thumb e id da resposta do servidor.
sw:cropper:error
O envio falhou (servidor fora, resposta sem ok: true…). e.detail.erro traz a mensagem.

API (JavaScript)

SW.Cropper.get(el)
Devolve o objeto interno do recorte ligado àquela div (para depuração).
SW.Cropper.initAll(raiz)
Liga os [sw-cropper] dentro de raiz que ainda não foram ligados. O núcleo já faz sozinho.

Precisa de quê

  • swcore.min.css + swcore.min.js — o recorte.
  • swcore.compl.min.css — só se usar ícone swi-* no botão.
  • Para salvar de verdade: um endereço no seu servidor que receba o dataUrl e responda o JSON da receita.

Cuidados — erros comuns

  • Esquecer sw-cropper-upload="#" quando não há servidor: sem o atributo ele tenta enviar para /api/imgs/upload, falha e o <img> não recebe nada.
  • Esquecer type="button" no botão de cortar dentro de um <form>: o clique envia o formulário.
  • Usar em sw-cropper-src uma foto de outro site (outro domínio): o navegador bloqueia a leitura da imagem e o corte não sai. Use foto do seu próprio site.
  • Esperar que o resultado seja o tamanho original da foto: ele sempre sai com 800 px de largura, em WebP.
  • Esquecer accept="image/*" no input: a pessoa consegue escolher PDF e nada acontece.

O que ele não faz

  • O quadro de recorte tem tamanho fixo (o maior que cabe na foto no formato escolhido): dá para arrastar, mas não para aumentar/diminuir nem dar zoom.
  • Não gira nem espelha a foto.
  • A tela de recorte mostra a foto com no máximo 500 px de largura.