Mir ist aufgefallen, dass beim Extrahieren von PNGs aus einigen Spieledateien das Bild teilweise verzerrt wird. Hier sind zum Beispiel einige PNGs, die aus der Textures-Datei in Skyrim extrahiert wurden:
Ist dies eine ungewöhnliche Variation eines PNG-Formats? Welche Änderungen müsste ich vornehmen, um solche PNGs korrekt anzuzeigen?
file-format
image
James Tauber
quelle
quelle
Antworten:
Hier sind die "restaurierten" Bilder, dank der weiteren Recherche von tillberg:
Wie erwartet gibt es alle ca. 0x4020 Bytes einen 5-Byte-Block-Marker . Das Format scheint wie folgt zu sein:
Nachdem der Marker gelesen wurde, bilden die nächsten
marker.len
Bytes einen Block, der Teil der Datei ist.marker.notlen
ist eine Regelgröße, so dassmarker.len + marker.notlen == 0xffff
. Der letzte Block ist so, dassmarker.tag == 1
.Die Struktur ist wahrscheinlich wie folgt. Es gibt noch unbekannte Werte.
Ich habe nicht herausgefunden, was am Ende ist, aber da PNGs das Auffüllen akzeptieren, ist es nicht zu dramatisch. Die verschlüsselte Dateigröße zeigt jedoch deutlich an, dass die letzten 4 Bytes ignoriert werden sollten ...
Da ich kurz vor Beginn der Datei nicht auf alle Blockmarkierungen zugreifen konnte, habe ich diesen Decoder geschrieben, der am Ende beginnt und versucht, die Blockmarkierungen zu finden. Es ist überhaupt nicht robust, aber gut, es hat für Ihre Testbilder funktioniert:
Ältere Forschung
Dies erhalten Sie, wenn Sie das Byte
0x4022
aus dem zweiten Image entfernen und dann das Byte entfernen0x8092
:Die Bilder werden nicht wirklich „repariert“. Ich habe das durch Ausprobieren gemacht. Es wird jedoch darauf hingewiesen, dass alle 16384 Byte unerwartete Daten vorliegen. Ich vermute, dass die Bilder in einer Art Dateisystemstruktur gepackt sind und die unerwarteten Daten einfach Blockmarkierungen sind , die Sie beim Lesen der Daten entfernen sollten.
Ich weiß nicht genau, wo sich die Blockmarkierungen befinden und wie groß sie sind, aber die Blockgröße selbst beträgt mit Sicherheit 2 ^ 14 Bytes.
Es wäre hilfreich, wenn Sie auch einen hexadezimalen Speicherauszug (ein paar Dutzend Bytes) dessen bereitstellen könnten, was direkt vor dem Bild und direkt danach angezeigt wird. Dies würde Hinweise darauf geben, welche Informationen am Anfang oder Ende der Blöcke gespeichert sind.
Natürlich gibt es auch die Möglichkeit, dass Ihr Extraktionscode einen Fehler enthält. Wenn Sie einen Puffer von 16384 Bytes für Ihre Dateioperationen verwenden, würde ich zuerst dort überprüfen.
quelle
Auf Sams Vorschlag hin gab ich den Code von James unter https://github.com/tillberg/skyrim heraus und konnte n_letter.png erfolgreich aus der Skyrim Textures BSA-Datei extrahieren.
Die von den BSA-Headern angegebene "file_size" ist nicht die tatsächliche endgültige Dateigröße. Es enthält einige Header-Informationen sowie einige zufällige Datenblöcke, die überflüssig wirken und verstreut sind.
Die Überschriften sehen ungefähr so aus:
So entfernen Sie die Header-Bytes:
Von dort aus startet die eigentliche PNG-Datei. Das lässt sich anhand der 8-Byte-Startsequenz von PNG leicht überprüfen.
Ich versuchte herauszufinden, wo sich die zusätzlichen Bytes befanden, indem ich die PNG-Header las und die im IDAT-Block übergebene Länge mit der implizierten Datenlänge verglich, die aus der Messung der Anzahl der Bytes bis zum IEND-Block abgeleitet wurde. (Details dazu finden Sie in der Datei bsa.py bei github)
Die durch die Chunks in n_letter.png angegebenen Größen sind:
Als ich den tatsächlichen Abstand zwischen dem IDAT-Chunk und dem darauf folgenden IEND-Chunk gemessen habe (indem ich die Bytes mit string.find () in Python gezählt habe), stellte ich fest, dass die tatsächliche implizierte IDAT-Länge 60640 Bytes betrug - es gab zusätzliche 15 Bytes darin .
Im Allgemeinen enthielten die meisten "Brief" -Dateien 5 zusätzliche Bytes pro 16 KB Gesamtdateigröße. Zum Beispiel hatte o_letter.png bei ca. 73 KB zusätzliche 20 Bytes. Größere Dateien, wie die arkanen Kritzeleien, folgten größtenteils demselben Muster, obwohl bei einigen ungerade Mengen hinzugefügt wurden (52 Bytes, 12 Bytes oder 32 Bytes). Keine Ahnung was da los ist.
Für die Datei n_letter.png konnte ich die richtigen Offsets (meist durch Ausprobieren) finden, um die 5-Byte-Segmente zu entfernen.
Die entfernten fünf Bytesegmente sind:
Für das, was es wert ist, habe ich die letzten fünf Bytes des unbekannten 12-Byte-Segments aufgenommen, da es Ähnlichkeiten mit den anderen Sequenzen gibt.
Es stellt sich heraus, dass sie nicht alle 16 KB groß sind, sondern in Intervallen von ~ 0x4030 Byte.
Um zu verhindern, dass die oben genannten Indizes nahe beieinander liegen, habe ich auch die Zlib-Dekomprimierung des IDAT-Chunks aus dem resultierenden PNG getestet.
quelle
Tatsächlich sind die intermittierenden 5 Bytes Teil der Zlib-Komprimierung.
Wie unter http://drj11.wordpress.com/2007/11/20/a-use-for-uncompressed-pngs/ beschrieben ,
.. so zeigt eine 00 einen 'nächsten' Block an (kein endender), und die 4 nächsten Bytes sind die Blocklänge und ihre Inverse.
[Bearbeiten] Eine zuverlässigere Quelle ist natürlich RFC 1951 (Deflate Compressed Data Format Specification), Abschnitt 3.2.4.
quelle
Ist es möglich, dass Sie die Daten aus der Datei in einem Textmodus lesen (in dem Zeilenenden, die in den PNG-Daten erscheinen, möglicherweise unkenntlich gemacht werden), anstatt in einem Binärmodus?
quelle
libpng
den Skyrim-PNGs? Mit anderen Worten, ist es nur ein Fehler in Ihrem PNG-Loader?