Zauważyłem, że wyodrębniając PNG z niektórych plików gry, obraz ulega częściowemu zniekształceniu. Na przykład oto kilka plików PNG wyodrębnionych z pliku tekstur w Skyrim:
Czy to jakaś niezwykła odmiana formatu PNG? Jakie modyfikacje należy wprowadzić, aby prawidłowo wyświetlać takie pliki PNG?
file-format
image
James Tauber
źródło
źródło
Odpowiedzi:
Oto „przywrócone” obrazy, dzięki dalszym badaniom tillberga:
Zgodnie z oczekiwaniami 5-bajtowy znacznik bloku co około 0x4020 bajtów. Format wygląda następująco:
Po odczytaniu znacznika następne
marker.len
bajty tworzą blok, który jest częścią pliku.marker.notlen
jest zmienną kontrolną taką, żemarker.len + marker.notlen == 0xffff
. Ostatni blok jest taki, żemarker.tag == 1
.Struktura jest prawdopodobnie następująca. Nadal istnieją nieznane wartości.
Nie zorientowałem się, co jest na końcu, ale ponieważ PNG akceptują padding, nie jest to zbyt dramatyczne. Jednak zakodowany rozmiar pliku wyraźnie wskazuje, że ostatnie 4 bajty należy zignorować ...
Ponieważ nie miałem dostępu do wszystkich znaczników bloków tuż przed początkiem pliku, napisałem ten dekoder, który zaczyna się na końcu i próbuje znaleźć znaczniki bloków. To wcale nie jest solidne, ale dobrze, zadziałało dla twoich zdjęć testowych:
Starsze badania
Oto, co dostajesz, usuwając bajt
0x4022
z drugiego obrazu, a następnie usuwając bajt0x8092
:Tak naprawdę nie „naprawia” obrazów; Zrobiłem to metodą prób i błędów. Mówi jednak, że co 16384 bajtów występują nieoczekiwane dane. Domyślam się, że obrazy są spakowane w jakąś strukturę systemu plików, a nieoczekiwane dane to po prostu znaczniki bloków , które należy usunąć podczas odczytywania danych.
Nie wiem, gdzie dokładnie są znaczniki bloku i ich rozmiar, ale sam rozmiar bloku z pewnością wynosi 2 ^ 14 bajtów.
Byłoby pomocne, gdybyś mógł również dostarczyć zrzut heksadecymalny (kilkadziesiąt bajtów) tego, co pojawia się tuż przed obrazem i zaraz po nim. Dałoby to wskazówki na temat tego, jakie informacje są przechowywane na początku lub na końcu bloków.
Oczywiście istnieje również możliwość, że w kodzie ekstrakcyjnym występuje błąd. Jeśli używasz bufora 16384 bajtów do operacji na plikach, najpierw bym tam sprawdził.
źródło
W oparciu o sugestię Sama rozwidliłem kod Jamesa na https://github.com/tillberg/skyrim i udało mi się wyodrębnić n_letter.png z pliku BSA Skyrim Textures.
„Rozmiar_pliku” podany przez nagłówki BSA nie jest rzeczywistym końcowym rozmiarem pliku. Zawiera pewne informacje nagłówka, a także losowe porcje niepotrzebnych danych, które są rozproszone.
Nagłówki wyglądają mniej więcej tak:
Aby usunąć bajty nagłówka, zrobiłem to:
Stamtąd zaczyna się rzeczywisty plik PNG. Łatwo jest sprawdzić, czy z 8-bajtowej sekwencji startowej PNG.
Próbowałem dowiedzieć się, gdzie znajdują się dodatkowe bajty, czytając nagłówki PNG i porównując długość przekazaną w porcji IDAT z implikowaną długością danych wyprowadzoną z pomiaru liczby bajtów do porcji IEND. (szczegółowe informacje na ten temat można znaleźć w pliku bsa.py na github)
Rozmiary podane przez porcje w n_letter.png to:
Kiedy zmierzyłem rzeczywistą odległość między porcją IDAT a porcją IEND po niej (zliczając bajty za pomocą string.find () w Pythonie), stwierdziłem, że rzeczywista sugerowana długość IDAT wynosiła 60640 bajtów - było tam dodatkowych 15 bajtów .
Ogólnie rzecz biorąc, większość plików „listowych” zawiera dodatkowe 5 bajtów na każde 16 KB całkowitego rozmiaru pliku. Na przykład o_letter.png, o wielkości około 73 KB, miał dodatkowe 20 bajtów. Większe pliki, takie jak tajemne bazgroły, przeważnie miały ten sam wzór, chociaż niektóre miały dodane nieparzyste ilości (52 bajty, 12 bajtów lub 32 bajty). Nie mam pojęcia, co się tam dzieje.
W przypadku pliku n_letter.png udało mi się znaleźć prawidłowe przesunięcia (głównie metodą prób i błędów), w których można usunąć segmenty 5-bajtowe.
Pięć usuniętych segmentów bajtowych to:
Dla tego, co jest warte, dołączyłem ostatnie pięć bajtów nieznanego 12-bajtowego segmentu ze względu na pewne podobieństwo z innymi sekwencjami.
Okazuje się, że nie są one co 16 KB, ale w odstępach ~ 0x4030 bajtów.
Aby uchronić się przed uzyskiwaniem bliskich, ale nie idealnych dopasowań w powyższych wskaźnikach, przetestowałem również dekompresję zlib fragmentu IDAT z wynikowego PNG i przechodzi.
źródło
W rzeczywistości przerywane 5 bajtów jest częścią kompresji zlib.
Jak szczegółowo opisano na http://drj11.wordpress.com/2007/11/20/a-use-for-uncompressed-pngs/ ,
.. więc 00 oznacza „następny” blok (nie końcowy), a 4 kolejne bajty to długość bloku i jego odwrotność.
[Edytuj] Bardziej niezawodnym źródłem jest oczywiście RFC 1951 (Deflate Compressed Data Format Specification), sekcja 3.2.4.
źródło
Czy to możliwe, że czytasz dane z pliku w trybie tekstowym (gdzie zakończenia linii, które pojawiają się w danych PNG, są prawdopodobnie zniekształcone) zamiast w trybie binarnym?
źródło
libpng
czytanie plików PNG Skyrim? Innymi słowy, czy to tylko błąd w twoim programie ładującym PNG?