4

PNG de 100 mm no navegador: pixels, DPI e o chunk pHYs são coisas diferentes

Uma imagem pode abrir corretamente no navegador e entrar no software de gravação com um tamanho físico inesperado. Pixels, densidade e milímetros são três informações diferentes.

Sou o mantenedor do RasterGo, uma ferramenta de preparação de fotos no navegador. Ao implementar a exportação PNG, separei o redimensionamento real da gravação dos metadados. Compartilho aqui o raciocínio e um exemplo que dá para reproduzir sem usar meu site. Texto preparado com assistência de IA e conferido contra a implementação e a especificação.

1. Primeiro decida quantos pixels você precisa

Para uma largura física e uma densidade escolhidas:

function tamanhoRaster(larguraMm, dpi) {
  if (!Number.isFinite(larguraMm) || larguraMm <= 0 ||
      !Number.isFinite(dpi) || dpi <= 0) {
    throw new Error('Largura e DPI devem ser positivos.');
  }
  const larguraPx = Math.round(larguraMm / 25.4 * dpi);
  return {
    larguraPx,
    pixelsPorMetro: Math.round(dpi / 0.0254),
    larguraEfetivaMm: larguraPx / dpi * 25.4
  };
}
console.log(tamanhoRaster(100, 254));
// 1000 px, 10000 pixels/metro, 100 mm
console.log(tamanhoRaster(80, 300));
// 945 px, 11811 pixels/metro, aproximadamente 80,01 mm

O arredondamento é necessário porque não existe meia coluna de pixels. A largura efetiva retornada é calculada com o DPI solicitado; usar a densidade inteira gravada no PNG pode acrescentar uma pequena diferença de arredondamento.

Isso não escolhe a densidade ideal para sua máquina ou material. É apenas a conversão geométrica. A resolução da foto original continua sendo um limite: aumentar pixels não recupera detalhe perdido.

2. O tamanho físico precisa de outra informação

O chunk pHYs do PNG, definido pelo W3C, guarda dois inteiros de quatro bytes para a densidade horizontal e vertical, mais um byte para a unidade. Com unidade 1, os valores são pixels por metro; com unidade 0, só há proporção dos pixels, sem tamanho físico definido.

No caso de 254 DPI, usamos 10000 pixels por metro nos dois eixos. Uma largura de 1000 pixels corresponde então a 100 mm. Sem pHYs, o arquivo ainda tem 1000 pixels de largura, mas não declara essa dimensão física.

Na exportação, minha implementação valida os chunks e seus CRCs, escreve um único pHYs e substitui o anterior, quando existe. Alterar esse metadado sozinho não redimensiona o bitmap e não melhora a nitidez.

3. A ordem do processamento importa

Para preparar uma foto em preto e branco, uso esta sequência:

  1. Recortar mantendo a composição desejada.
  2. Redimensionar para os pixels finais.
  3. Ajustar tons e aplicar o dithering.
  4. Exportar o PNG com a densidade correspondente.
  5. Conferir a largura em milímetros no programa que vai importar o arquivo.

Redimensionar depois do dithering pode alterar o padrão de pontos. Também convém conferir se o programa de destino vai aplicar outro dithering e se o preto ou o branco corresponde à área gravada. Não é uma recomendação universal de potência, velocidade ou configuração de máquina.

4. Um arquivo para inspecionar

Disponibilizei um PNG de exemplo de 100 mm a 300 DPI: 1181 × 1181 pixels, pHYs de 11811 pixels/metro, aproximadamente 99,99 mm de largura. O arquivo foi verificado digitalmente em 8 de outubro de 2026. O retrato é sintético; não é foto de cliente nem prova de uma gravação física.

No guia de tamanho e importação estão os passos para reproduzir esse exemplo. O editor RasterGo permite preparar e baixar um PNG individual gratuitamente, com processamento da foto no navegador. Atualização em 17/10/2026, às 15:18 UTC: o Batch Pack está disponível por US$4,90 em pagamento único, sem assinatura, para lotes de até 50 fotos e exportação ZIP. É preciso entrar na conta para comprar e restaurar a compra. O PNG individual deste exercício continua gratuito, sem conta; não é preciso comprar nada para reproduzir o tutorial.

Se você implementa exportação de imagem, vale testar separadamente: quantidade de pixels, presença e CRC do pHYs, densidade nos dois eixos e tamanho mostrado pelo importador. Uma imagem bonita na tela, sozinha, não valida esses quatro pontos.

Carregando publicação patrocinada...
1

Eu tenho interesse em 'implementação de formatos de imagem' mas tenho receio de ser muito complicado. Eu também levo alguns projetos na área e penso em produzir algo como 'tutorial como gerar pngs a partir de código'

4

Para começar esse tutorial, eu separaria duas tarefas: gerar uma imagem PNG e implementar o formato PNG. A primeira pode ser bem pequena; a segunda envolve assinatura, chunks, CRC, compressão e filtros.

Um primeiro exercício no navegador, sem implementar um codificador:

const canvas = document.createElement('canvas');
canvas.width = 1000;
canvas.height = 1000;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, 1000, 1000);
ctx.fillStyle = '#000';
ctx.fillRect(100, 100, 800, 800);
canvas.toBlob(blob => {
  if (!blob) throw new Error('PNG não gerado');
  console.log(blob.type, blob.size);
}, 'image/png');

Depois eu acrescentaria a inspeção dos chunks e só então a escrita de pHYs, sem recomprimir IDAT. O PNG do canvas, sozinho, não garante o tamanho físico desejado. A especificação é PNG, W3C.

Sou o mantenedor do RasterGo. Deixei um arquivo sintético para comparar: 1181×1181 pixels, 11811 pixels/metro, cerca de 100 mm. Dá para inspecionar o arquivo sem conta ou pagamento; isso é validação digital, não um teste de gravação física. Assim o tutorial pode evoluir por etapas e cada etapa tem uma saída verificável.

Texto preparado com assistência de IA, com divulgação da autoria do projeto.