Ler um PNG de verdade
Assinatura, chunks, tamanho em big-endian e o CRC de cada um — o formato inteiro, sem biblioteca de imagem.
Um PNG é uma assinatura de 8 bytes seguida de chunks: tamanho (u32, big-endian), tipo (4 letras), dados, e um CRC-32 do tipo mais os dados. O primeiro chunk é sempre IHDR, com largura, altura e profundidade de cor. Montamos um cabeçalho de verdade e o lemos de volta, conferindo o CRC:
dataforge
adopt Arcane.Estrutura as Est
adopt Arcane.Bytes as Bytes
steady ASSINATURA := Bytes.de_hex("89504e470d0a1a0a")
Ihdr := Est.definir("Ihdr", [["largura", "u32"], ["altura", "u32"], ["profundidade", "u8"],
["cor", "u8"], ["compressao", "u8"], ["filtro", "u8"], ["entrelace", "u8"]], "rede", yes)
action chunk(tipo, dados):
corpo := Bytes.concatenar(Bytes.de_texto(tipo), dados)
yield Bytes.escrever(">").escrever("u32", len(dados)).escrever_bytes(corpo).escrever("u32", Est.crc32(corpo)).finalizar()
dados := Ihdr({"largura": 640, "altura": 480, "profundidade": 8, "cor": 6}).bytes()
png := Bytes.concatenar(ASSINATURA, chunk("IHDR", dados))
// ── ler ──
assert Bytes.fatiar(png, 0, 8) is ASSINATURA
l := Bytes.ler(Bytes.fatiar(png, 8), ">")
tamanho := l.ler("u32")
tipo := l.ler_texto(4)
corpo := l.ler_bytes(tamanho)
crc := l.ler("u32")
assert tipo is "IHDR" and tamanho is 13
assert crc is Est.crc32(corpo, Est.crc32(Bytes.de_texto(tipo))) // CRC em duas partes
assert Ihdr.ler(corpo)["largura"] is 640- A assinatura primeiro. Ela tem um
\r\ne um\nde propósito: um arquivo que passou por conversão de fim de linha tem a assinatura estragada, e o erro aparece aqui — e não como uma imagem corrompida. - O CRC antes de confiar. Um chunk com CRC errado é recusado antes de os dados serem interpretados.
- `crc32(dados, inicial)` continua uma conta. O CRC do PNG é do tipo mais os dados; calcular em duas partes evita concatenar os dois só para conferir.