Eu notei que extrair PNGs de alguns arquivos de jogo nos quais a imagem fica distorcida parcialmente. Por exemplo, aqui estão alguns PNGs extraídos do arquivo Textures no Skyrim:
É alguma variação incomum em um formato PNG? Que modificações eu precisaria fazer para visualizar adequadamente esses PNGs?
file-format
image
James Tauber
fonte
fonte
Respostas:
Aqui estão as imagens "restauradas", graças às pesquisas adicionais de tillberg:
Como esperado, há um marcador de bloco de 5 bytes a cada 0x4020 bytes. O formato parece ser o seguinte:
Após a leitura do marcador, os próximos
marker.len
bytes formam um bloco que faz parte do arquivo.marker.notlen
é uma variável de controle tal quemarker.len + marker.notlen == 0xffff
. O último bloco é tal quemarker.tag == 1
.A estrutura é provavelmente a seguinte. Ainda existem valores desconhecidos.
Ainda não descobri o que há no final, mas como os PNGs aceitam o preenchimento, não é muito dramático. No entanto, o tamanho do arquivo codificado indica claramente que os últimos 4 bytes devem ser ignorados ...
Como não tinha acesso a todos os marcadores de bloco imediatamente antes do início do arquivo, escrevi esse decodificador que inicia no final e tenta encontrar os marcadores de bloco. Não é robusto, mas funciona bem para as imagens de teste:
Pesquisa mais antiga
É isso que você obtém ao remover o byte
0x4022
da segunda imagem e, em seguida, ao remover o byte0x8092
:Realmente não "repara" as imagens; Eu fiz isso por tentativa e erro. No entanto, o que diz é que há dados inesperados a cada 16384 bytes. Meu palpite é que as imagens são compactadas em algum tipo de estrutura do sistema de arquivos e os dados inesperados são simplesmente marcadores de blocos que você deve remover ao ler os dados.
Não sei exatamente onde estão os marcadores de bloco e seu tamanho, mas o tamanho do bloco em si é certamente 2 ^ 14 bytes.
Ajudaria se você também pudesse fornecer um dump hexadecimal (algumas dezenas de bytes) do que aparece logo antes da imagem e logo depois. Isso daria dicas sobre que tipo de informação é armazenada no início ou no final dos blocos.
Claro que também existe a possibilidade de que haja um erro no seu código de extração. Se você estiver usando um buffer de 16384 bytes para suas operações de arquivo, eu primeiro verificaria lá.
fonte
Com base na sugestão de Sam, peguei o código de James em https://github.com/tillberg/skyrim e consegui extrair com sucesso o n_letter.png do arquivo BSA do Skyrim Textures.
O "tamanho_do_arquivo" fornecido pelos cabeçalhos da BSA não é o tamanho final real do arquivo. Ele inclui algumas informações de cabeçalho, bem como alguns blocos aleatórios de dados aparentemente inúteis espalhados.
Os cabeçalhos são mais ou menos assim:
Para retirar os bytes do cabeçalho, fiz o seguinte:
A partir daí, o arquivo PNG real é iniciado. É fácil verificar isso na sequência de início de 8 bytes do PNG.
Eu tentei descobrir onde os bytes extras estavam localizados lendo os cabeçalhos PNG e comparando o comprimento passado no pedaço IDAT com o comprimento implícito dos dados deduzido da medição do número de bytes até o pedaço IEND. (para detalhes, confira o arquivo bsa.py no github)
Os tamanhos fornecidos pelos blocos em n_letter.png são:
Quando medi a distância real entre o pedaço IDAT e o pedaço IEND depois dele (contando bytes usando string.find () em Python), descobri que o comprimento real do IDAT implícito era 60640 bytes - havia 15 bytes extras lá .
Em geral, a maioria dos arquivos "letter" tinha 5 bytes extras presentes para cada 16 KB do tamanho total do arquivo. Por exemplo, o_letter.png, com cerca de 73 KB, tinha mais 20 bytes. Arquivos maiores, como os rabiscos arcanos, geralmente seguiam o mesmo padrão, embora alguns tivessem valores ímpares adicionados (52 bytes, 12 bytes ou 32 bytes). Não faço ideia do que está acontecendo lá.
Para o arquivo n_letter.png, consegui encontrar as compensações corretas (principalmente por tentativa e erro) nas quais remover os segmentos de 5 bytes.
Os segmentos de cinco bytes removidos são:
Quanto vale a pena, incluí os últimos cinco bytes do segmento desconhecido de 12 bytes por causa de alguma semelhança com as outras seqüências.
Acontece que eles não são bem a cada 16 KB, mas a intervalos de ~ 0x4030 bytes.
Para me impedir de obter correspondências quase perfeitas nos índices acima, também testei a descompressão zlib do pedaço IDAT do PNG resultante e ele passa.
fonte
Na verdade, os 5 bytes intermitentes fazem parte da compactação zlib.
Conforme detalhado em http://drj11.wordpress.com/2007/11/20/a-use-for-uncompressed-pngs/ ,
.. então um 00 indica um bloco 'próximo' (não um final) e os 4 bytes seguintes são o comprimento do bloco e seu inverso.
[Editar] Uma fonte mais confiável é, obviamente, a RFC 1951 (Deflate Compressed Data Format Specification), seção 3.2.4.
fonte
É possível que você esteja lendo os dados do arquivo no modo de texto (onde as terminações de linha que aparecem nos dados PNG são possivelmente mutiladas) em vez de no modo binário?
fonte
libpng
lê os PNG Skyrim? Em outras palavras, é apenas um bug no seu carregador PNG?