Saya perhatikan mengekstraksi PNG dari beberapa file game sehingga gambar menjadi terdistorsi sebagian. Misalnya, berikut adalah beberapa PNG yang diekstrak dari file Tekstur di Skyrim:
Apakah ini beberapa variasi yang tidak biasa pada format PNG? Modifikasi apa yang perlu saya buat untuk melihat PNG dengan benar?
file-format
image
James Tauber
sumber
sumber
Jawaban:
Berikut adalah gambar-gambar yang "dipulihkan", berkat penelitian lebih lanjut tillberg:
Seperti yang diharapkan, ada penanda blok 5 byte setiap sekitar 0x4020 byte. Formatnya tampaknya sebagai berikut:
Setelah marker dibaca,
marker.len
byte berikutnya membentuk blok yang merupakan bagian dari file.marker.notlen
adalah variabel kontrol sedemikian rupa sehinggamarker.len + marker.notlen == 0xffff
. Blok terakhir adalah seperti itumarker.tag == 1
.Strukturnya mungkin sebagai berikut. Masih ada nilai yang tidak diketahui.
Saya belum tahu apa yang ada di akhir, tetapi karena PNG menerima bantalan, itu tidak terlalu dramatis. Namun, ukuran file yang disandikan dengan jelas menunjukkan bahwa 4 byte terakhir harus diabaikan ...
Karena saya tidak memiliki akses ke semua penanda blok tepat sebelum permulaan file, saya menulis dekoder ini yang dimulai pada bagian akhir dan mencoba untuk menemukan penanda blok. Sama sekali tidak kuat, tetapi berfungsi baik untuk gambar uji Anda:
Penelitian yang lebih tua
Inilah yang Anda dapatkan saat menghapus byte
0x4022
dari gambar kedua, kemudian dengan menghapus byte0x8092
:Itu tidak benar-benar "memperbaiki" gambar; Saya melakukan ini dengan coba-coba. Namun, yang diceritakan adalah bahwa ada data yang tidak terduga setiap 16384 byte. Dugaan saya adalah bahwa gambar-gambar tersebut dikemas dalam semacam struktur sistem file dan data yang tak terduga hanyalah blokir penanda yang harus Anda hapus ketika membaca data.
Saya tidak tahu di mana tepatnya marka blok dan ukurannya, tetapi ukuran blok itu sendiri sudah pasti 2 ^ 14 byte.
Ini akan membantu jika Anda juga bisa memberikan hex dump (beberapa lusin byte) dari apa yang muncul tepat sebelum gambar dan setelahnya. Ini akan memberi petunjuk tentang jenis informasi apa yang disimpan di awal atau di akhir blok.
Tentu saja ada juga kemungkinan ada bug dalam kode ekstraksi Anda. Jika Anda menggunakan buffer 16384 byte untuk operasi file Anda, maka saya akan memeriksa dulu di sana.
sumber
Berdasarkan saran Sam, saya memalsukan kode James di https://github.com/tillberg/skyrim dan berhasil mengekstraksi n_letter.png dari file Skyrim Textures BSA.
"File_size" yang diberikan oleh header BSA bukan ukuran file final yang sebenarnya. Ini mencakup beberapa info tajuk serta beberapa potongan acak dari data yang tampaknya tidak berguna yang tersebar di sekitar.
Header terlihat seperti ini:
Untuk menghapus byte header, saya melakukan ini:
Dari sana, file PNG yang sebenarnya dimulai. Sangat mudah untuk memverifikasi itu dari urutan mulai PNG 8-byte.
Saya melanjutkan untuk mencoba mencari tahu di mana byte tambahan berada dengan membaca header PNG dan membandingkan panjang yang dilewatkan dalam potongan IDAT dengan panjang data tersirat yang disimpulkan dari mengukur jumlah byte sampai potongan IEND. (untuk detailnya, lihat file bsa.py di github)
Ukuran yang diberikan oleh chunks di n_letter.png adalah:
Ketika saya mengukur jarak aktual antara potongan IDAT dan potongan IEND setelahnya (dengan menghitung byte menggunakan string.find () dengan Python), saya menemukan bahwa panjang IDAT aktual yang tersirat adalah 60640 byte - ada tambahan 15 byte di sana .
Secara umum, sebagian besar file "letter" memiliki tambahan 5 byte untuk setiap 16KB dari total ukuran file. Misalnya, o_letter.png, sekitar 73KB, memiliki tambahan 20 byte. File yang lebih besar, seperti scribbling misterius, sebagian besar mengikuti pola yang sama, meskipun beberapa memiliki jumlah ganjil yang ditambahkan (52 byte, 12 byte, atau 32 byte). Tidak tahu apa yang terjadi di sana.
Untuk file n_letter.png, saya dapat menemukan offset yang benar (kebanyakan dengan coba-coba) untuk menghapus segmen 5-byte.
Segmen lima byte yang dihapus adalah:
Untuk apa nilainya, saya telah memasukkan lima byte terakhir dari segmen 12-byte yang tidak diketahui karena beberapa kesamaan dengan urutan lainnya.
Ternyata mereka tidak cukup setiap 16KB, tetapi pada interval ~ 0x4030 byte.
Untuk menjaga agar tidak mendapatkan kecocokan yang dekat tetapi tidak sempurna dalam indeks di atas, saya juga menguji dekompresi zlib dari potongan IDAT dari PNG yang dihasilkan, dan itu lolos.
sumber
Sebenarnya, 5 byte intermiten adalah bagian dari kompresi zlib.
Seperti yang dijelaskan pada http://drj11.wordpress.com/2007/11/20/a-use-for-uncompressed-pngs/ ,
.. jadi 00 menunjukkan blok 'berikutnya' (bukan yang berakhir), dan 4 byte berikutnya adalah panjang blok dan kebalikannya.
[Sunting] Sumber yang lebih andal tentu saja adalah RFC 1951 (Spesifikasi Format Data yang Dikosongkan), bagian 3.2.4.
sumber
Apakah mungkin Anda membaca data dari file dalam mode teks (di mana ujung baris yang muncul dalam data PNG mungkin hancur) daripada dalam mode biner?
sumber
libpng
membaca PNG Skyrim? Dengan kata lain, apakah itu hanya bug di PNG loader Anda?