J'ai remarqué l'extraction de fichiers PNG à partir de certains fichiers de jeu que l'image se déforme en cours de route. Par exemple, voici quelques PNG extraits du fichier Textures dans Skyrim:
Est-ce une variation inhabituelle sur un format PNG? Quelles modifications devrais-je apporter pour afficher correctement ces fichiers PNG?
file-format
image
James Tauber
la source
la source
Réponses:
Voici les images «restaurées», grâce aux recherches approfondies de tillberg:
Comme prévu, il y a un marqueur de bloc de 5 octets tous les 0x4020 octets environ. Le format semble être le suivant:
Une fois le marqueur lu, les
marker.len
octets suivants forment un bloc qui fait partie du fichier.marker.notlen
est une variable de contrôle telle quemarker.len + marker.notlen == 0xffff
. Le dernier bloc est tel quemarker.tag == 1
.La structure est probablement la suivante. Il existe encore des valeurs inconnues.
Je n'ai pas compris ce qui est à la fin, mais comme les PNG acceptent le rembourrage, ce n'est pas trop dramatique. Cependant, la taille du fichier encodé indique clairement que les 4 derniers octets doivent être ignorés ...
Comme je n'avais pas accès à tous les marqueurs de bloc juste avant le début du fichier, j'ai écrit ce décodeur qui commence à la fin et tente de trouver les marqueurs de bloc. Ce n'est pas du tout robuste mais bon, cela a fonctionné pour vos images de test:
Recherches plus anciennes
Voici ce que vous obtenez en supprimant l'octet
0x4022
de la deuxième image, puis en supprimant l'octet0x8092
:Il ne «répare» pas vraiment les images; Je l'ai fait par essais et erreurs. Cependant, il indique qu'il y a des données inattendues tous les 16384 octets. Je suppose que les images sont regroupées dans une sorte de structure de système de fichiers et que les données inattendues sont simplement des marqueurs de bloc que vous devez supprimer lors de la lecture des données.
Je ne sais pas exactement où sont les marqueurs de bloc et leur taille, mais la taille du bloc elle-même est très certainement de 2 ^ 14 octets.
Il serait utile que vous puissiez également fournir un vidage hexadécimal (quelques dizaines d'octets) de ce qui apparaît juste avant l'image et juste après. Cela donnerait des indications sur le type d'informations stockées au début ou à la fin des blocs.
Bien sûr, il y a aussi la possibilité qu'il y ait un bug dans votre code d'extraction. Si vous utilisez un tampon de 16384 octets pour vos opérations sur les fichiers, je vérifierais d'abord.
la source
Sur la base de la suggestion de Sam, j'ai bifurqué le code de James sur https://github.com/tillberg/skyrim et j'ai réussi à extraire n_letter.png du fichier Skyrim Textures BSA.
La "taille_fichier" donnée par les en-têtes BSA n'est pas la taille réelle du fichier final. Il comprend des informations d'en-tête ainsi que des morceaux aléatoires de données apparemment inutiles dispersées.
Les en-têtes ressemblent à ceci:
Pour supprimer les octets d'en-tête, j'ai fait ceci:
De là, le fichier PNG réel commence. Il est facile de vérifier cela à partir de la séquence de démarrage PNG de 8 octets.
J'ai essayé de comprendre où se trouvaient les octets supplémentaires en lisant les en-têtes PNG et en comparant la longueur passée dans le bloc IDAT à la longueur de données implicite déduite de la mesure du nombre d'octets jusqu'au bloc IEND. (pour plus de détails, consultez le fichier bsa.py sur github)
Les tailles données par les morceaux dans n_letter.png sont:
Lorsque j'ai mesuré la distance réelle entre le bloc IDAT et le bloc IEND après celui-ci (en comptant les octets à l'aide de string.find () en Python), j'ai constaté que la longueur IDAT réelle impliquée était de 60640 octets - il y avait 15 octets supplémentaires .
En général, la plupart des fichiers "lettre" avaient 5 octets supplémentaires présents pour chaque 16 Ko de taille totale de fichier. Par exemple, o_letter.png, à environ 73 Ko, avait 20 octets supplémentaires. Les fichiers plus volumineux, comme les gribouillis obscurs, suivaient généralement le même schéma, bien que certains aient des quantités étranges ajoutées (52 octets, 12 octets ou 32 octets). Aucune idée de ce qui se passe là-bas.
Pour le fichier n_letter.png, j'ai pu trouver les décalages corrects (principalement par essais et erreurs) pour supprimer les segments de 5 octets.
Les cinq segments d'octets supprimés sont:
Pour ce que ça vaut, j'ai inclus les cinq derniers octets du segment inconnu de 12 octets en raison de certaines similitudes avec les autres séquences.
Il s'avère qu'ils ne sont pas tout à fait tous les 16 Ko, mais à des intervalles de ~ 0x4030 octets.
Pour éviter d'obtenir des correspondances proches mais pas parfaites dans les indices ci-dessus, j'ai également testé la décompression zlib du bloc IDAT à partir du PNG résultant, et cela passe.
la source
En fait, les 5 octets intermittents font partie de la compression zlib.
Comme détaillé sur http://drj11.wordpress.com/2007/11/20/a-use-for-uncompressed-pngs/ ,
.. donc un 00 indique un bloc 'suivant' (pas un bloc de fin), et les 4 octets suivants sont la longueur du bloc et son inverse.
[Modifier] Une source plus fiable est bien sûr la RFC 1951 (Deflate Compressed Data Format Specification), section 3.2.4.
la source
Est-il possible que vous lisiez les données du fichier en mode texte (où les fins de ligne qui apparaissent dans les données PNG sont éventuellement altérées) plutôt qu'en mode binaire?
la source
libpng
lire les PNG Skyrim? En d'autres termes, s'agit-il simplement d'un bug dans votre chargeur PNG?