He notado que al extraer PNG de algunos archivos del juego, la imagen se distorsiona a la mitad. Por ejemplo, aquí hay un par de PNG extraídos del archivo de Texturas en Skyrim:
¿Es esta una variación inusual en un formato PNG? ¿Qué modificaciones necesitaría hacer para ver dichos PNG correctamente?
file-format
image
James Tauber
fuente
fuente
Respuestas:
Aquí están las imágenes "restauradas", gracias a la investigación adicional de tillberg:
Como se esperaba, hay un marcador de bloque de 5 bytes cada 0x4020 bytes. El formato parece ser el siguiente:
Una vez que se ha leído el marcador, los siguientes
marker.len
bytes forman un bloque que forma parte del archivo.marker.notlen
es una variable de control de tal manera quemarker.len + marker.notlen == 0xffff
. El último bloque es tal quemarker.tag == 1
.La estructura es probablemente la siguiente. Todavía hay valores desconocidos.
No he descubierto qué hay al final, pero como los PNG aceptan el relleno, no es demasiado dramático. Sin embargo, el tamaño del archivo codificado indica claramente que los últimos 4 bytes deben ignorarse ...
Como no tenía acceso a todos los marcadores de bloque justo antes del comienzo del archivo, escribí este decodificador que comienza al final e intenta encontrar los marcadores de bloque. No es robusto en absoluto, pero bueno, funcionó para sus imágenes de prueba:
Investigación más antigua
Esto es lo que obtienes al eliminar el byte
0x4022
de la segunda imagen, luego al eliminar el byte0x8092
:Realmente no "repara" las imágenes; Lo hice por prueba y error. Sin embargo, lo que dice es que hay datos inesperados cada 16384 bytes. Supongo que las imágenes están empaquetadas en algún tipo de estructura de sistema de archivos y los datos inesperados son simplemente marcadores de bloque que debe eliminar al leer los datos.
No sé exactamente dónde están los marcadores de bloque y su tamaño, pero el tamaño del bloque en sí es ciertamente 2 ^ 14 bytes.
Sería útil si también pudiera proporcionar un volcado hexadecimal (unas pocas docenas de bytes) de lo que aparece justo antes de la imagen y justo después. Esto daría pistas sobre qué tipo de información se almacena al principio o al final de los bloques.
Por supuesto, también existe la posibilidad de que haya un error en su código de extracción. Si está utilizando un búfer de 16384 bytes para sus operaciones de archivo, entonces primero comprobaría allí.
fuente
Basado en la sugerencia de Sam, bifurqué el código de James en https://github.com/tillberg/skyrim y pude extraer con éxito n_letter.png del archivo BSA de Skyrim Textures.
El "tamaño_archivo" dado por los encabezados BSA no es el tamaño real del archivo final. Incluye información de encabezado, así como algunos fragmentos aleatorios de datos aparentemente inútiles dispersos.
Los encabezados se parecen a esto:
Para quitar los bytes del encabezado, hice esto:
A partir de ahí, comienza el archivo PNG real. Es fácil verificar eso desde la secuencia de inicio de 8 bytes de PNG.
Procedí a tratar de averiguar dónde estaban ubicados los bytes adicionales leyendo los encabezados PNG y comparando la longitud pasada en el fragmento IDAT con la longitud de datos implícita deducida de la medición del número de bytes hasta el fragmento IEND. (para obtener más información al respecto, consulte el archivo bsa.py en github)
Los tamaños dados por los fragmentos en n_letter.png son:
Cuando medí la distancia real entre el fragmento IDAT y el fragmento IEND después (contando bytes usando string.find () en Python), descubrí que la longitud real de IDAT implicada era 60640 bytes, había 15 bytes adicionales allí .
En general, la mayoría de los archivos "carta" tenían 5 bytes adicionales presentes por cada 16 KB de tamaño total de archivo. Por ejemplo, o_letter.png, con alrededor de 73 KB, tenía 20 bytes adicionales. Los archivos más grandes, como los garabatos arcanos, en su mayoría seguían el mismo patrón, aunque algunos tenían cantidades extra (52 bytes, 12 bytes o 32 bytes). No tengo idea de lo que está pasando allí.
Para el archivo n_letter.png, pude encontrar las compensaciones correctas (principalmente por prueba y error) en las que eliminar los segmentos de 5 bytes.
Los cinco segmentos de byte eliminados son:
Para lo que vale, he incluido los últimos cinco bytes del segmento desconocido de 12 bytes debido a alguna similitud con las otras secuencias.
Resulta que no son exactamente cada 16 KB, pero a intervalos de ~ 0x4030 bytes.
Para evitar contraer coincidencias cercanas pero no perfectas en los índices anteriores, también probé la descompresión zlib del fragmento IDAT del PNG resultante, y pasa.
fuente
En realidad, los 5 bytes intermitentes son parte de la compresión zlib.
Como se detalla en http://drj11.wordpress.com/2007/11/20/a-use-for-uncompressed-pngs/ ,
.. entonces un 00 indica un bloque 'siguiente' (no uno final), y los 4 bytes siguientes son la longitud del bloque y su inverso.
[Editar] Una fuente más confiable es, por supuesto, RFC 1951 (Deflate Compressed Data Format Specification), sección 3.2.4.
fuente
¿Es posible que esté leyendo los datos del archivo en un modo de texto (donde las terminaciones de línea que aparecen en los datos PNG posiblemente estén destrozadas) en lugar de en un modo binario?
fuente
libpng
leer los PNG de Skyrim? En otras palabras, ¿es solo un error en su cargador PNG?