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
Coloque o SWCore na página: CSS no
<head>e JS no fim do<body>. O segundo CSS só é preciso se usar íconeswi-*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
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.<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.
<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">
<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">
<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.
<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">
<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.
<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
| Palavra | O que faz | Exemplo |
|---|---|---|
| Peças (dentro da div) | ||
sw-cropper | Na <div> que junta tudo. | <div sw-cropper> |
sw-cropper-input | No <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-canvas | No <canvas> onde se enquadra. Só aparece quando há foto. | <canvas sw-cropper-canvas></canvas> |
sw-cropper-btn | No botão que corta. Só aparece quando há foto. | <button type="button" sw-cropper-btn> |
| Formato e foto inicial | ||
sw-cropper-ratio | Largura ÷ 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-src | Foto 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-out | Seletor do(s) <img> que recebem o recorte. | sw-cropper-out="#foto" |
sw-cropper-preview | Seletor do elemento que mostra a prévia ao vivo (como imagem de fundo). | sw-cropper-preview="#previa" |
| Envio ao servidor | ||
sw-cropper-upload | Endereç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-tipo | Texto enviado no campo tipo. Padrão avatar. | sw-cropper-tipo="capa" |
sw-cropper-ref | Enviado no campo ref_id — de quem é a foto (id do usuário, do produto). | sw-cropper-ref="42" |
sw-cropper-local | Enviado no campo local — pasta/destino para o seu servidor usar. | sw-cropper-local="perfis" |
| Classes de visual (opcionais) | ||
sw-cropper-stage | Moldura em volta do canvas; só aparece quando há foto. | <div class="sw-cropper-stage"> |
sw-cropper-row | Linha para pôr a prévia e um texto lado a lado. | <div class="sw-cropper-row"> |
sw-cropper-prev | Bolinha de prévia (redonda). is-sqr = canto reto. | <div class="sw-cropper-prev is-sqr"> |
sw-cropper-hint | Texto pequeno de ajuda. | <span class="sw-cropper-hint"> |
sw-cropper-out | No <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.
<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>
<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 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" }
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:readysw:cropper:donee.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:errorok: true…). e.detail.erro traz a mensagem.API (JavaScript)
SW.Cropper.get(el)SW.Cropper.initAll(raiz)[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 íconeswi-*no botão.- Para salvar de verdade: um endereço no seu servidor que receba o
dataUrle 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-srcuma 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.

