Como recortar uma foto 3x4 pela norma usando só o navegador (MediaPipe, sem enviar a foto para servidor)
Precisei gerar fotos 3x4, 5x7 de passaporte e a foto 600x600 do DS-160 (visto americano) a partir de selfies. A maioria dos sites pede upload da foto e cobra para tirar a marca d’água. Quis ver se dava para fazer tudo no navegador, sem a foto sair do celular. Deu, e as partes menos óbvias foram estas.
1. A norma fala em altura da cabeça, não em "zoom"
Para foto de documento, o que importa é a altura da cabeça (do queixo ao topo) e a margem acima dela. Alguns valores com fonte oficial:
| Foto | Tamanho | Cabeça | Fonte |
|---|---|---|---|
| 3x4 | 30 x 40 mm | ≈ 30 mm (70–80% da altura), 2,5 mm do topo | orientação OACI publicada pela ANAC |
| Visto EUA | 51 x 51 mm (600x600 px no DS-160, até 240 KB) | 25–35 mm (50–69%) | travel.state.gov |
| Visto Canadá | 35 x 45 mm | 31–36 mm | canada.ca (IRCC) |
| Schengen | 35 x 45 mm | 32–36 mm | Código de Vistos da UE / ICAO 9303 |
Com o queixo e o topo da cabeça em pixels, o recorte sai direto:
function computeCrop({ chinY, crownY, centerX }, spec) {
const pxPerMm = (chinY - crownY) / spec.headTargetMm; // escala da foto original
const w = spec.wMm * pxPerMm, h = spec.hMm * pxPerMm;
return { x: centerX - w / 2, y: crownY - spec.topMm * pxPerMm, w, h };
}
2. Achar o queixo é fácil; achar o topo da cabeça, não
O FaceLandmarker do MediaPipe dá 478 pontos do rosto. O ponto 152 é o queixo, mas o ponto mais alto (10) fica no meio da testa, não no topo do cabelo. O que funcionou:
- Endireitar a imagem pela linha dos olhos (média dos pontos 33/133 e 362/263), porque a inclinação muda tudo.
- Rodar um segmentador de pessoa numa janela em volta da cabeça e pegar a primeira linha, de cima para baixo, em que a máscara cobre uma faixa central do rosto. Esse é o topo do cabelo.
- Para normas que medem até o crânio (Canadá, ICAO), limitar esse topo a algo como
queixo − 1,24 × (queixo − ponto 10). Sem esse limite, cabelo black power ou cacheado volumoso "encolhe" o rosto e a foto é recusada.
3. Segmentação: qualidade × tamanho do download
selfie_segmenter(250 KB): rápido, bom o bastante para o fundo branco liso.selfie_multiclass_256x256(16 MB): separa cabelo, rosto, corpo e roupa, e o contorno de cabelo cacheado fica bem melhor.
Para não travar quem está no 4G, carrego o leve primeiro, mostro o resultado e, se a conexão não for 2g/3g nem saveData, baixo o multiclasse em segundo plano e refaço. Um detalhe: rodar o segmentador na área do recorte (e não na foto inteira) aumenta muito a resolução efetiva da máscara, que tem só 256 px.
4. Para a foto sair do tamanho certo na impressão: DPI no JPEG
canvas.toBlob('image/jpeg') grava 72 dpi (ou nenhum valor), e a gráfica imprime no tamanho errado. Dá para corrigir direto nos bytes do cabeçalho JFIF:
// FFD8 FFE0 len 'JFIF\0' ver(2) units@13 Xdens@14 Ydens@16
b[13] = 1; b[14] = dpi >> 8; b[15] = dpi & 255; b[16] = dpi >> 8; b[17] = dpi & 255;
5. PDF A4 sem biblioteca
Para imprimir em casa, montei um PDF de uma página à mão: o JPEG entra como /DCTDecode, sem recompressão, e cada foto é um cm com largura e altura em pontos (mm × 72 / 25,4). São umas 40 linhas, e não precisa de jsPDF. Numa A4 com margem de 12 mm e espaço de 3 mm cabem 30 fotos 3x4. Na folha 10x15 para revelar cabem 9.
6. Checagens que valem a pena mostrar ao usuário
Os blendshapes do MediaPipe dão eyeBlinkLeft/Right, mouthSmileLeft/Right e jawOpen. Com eles mais duas medidas simples (nariz deslocado do centro dos olhos = rosto virado; diferença de luminância entre as bochechas = luz de lado), dá para avisar "olhos fechados", "sorriso", "rosto virado" e "luz de um lado só" antes de a pessoa imprimir.
Código e dados
Deixei as medidas (com o link oficial de cada uma) em JSON e o motor em JS aberto: https://github.com/MMMystery/foto-documento-specs (código MIT, dados CC BY 4.0). Se alguém tiver a norma oficial de outros documentos (CIN, conselhos de classe, vistos de outros países), aceito issue ou PR.
A ferramenta pronta, que usa esse código, está em https://fotoapta.com/ (grátis e sem marca d’água).
Transparência: sou o autor do FotoApta. O texto foi escrito com ajuda de IA e revisado; os números vêm das fontes oficiais citadas.