Я заметил, что из некоторых игровых файлов извлекаются файлы PNG, из-за которых изображение становится частично искаженным. Например, вот несколько PNG, извлеченных из файла Textures в Skyrim:
Это какой-то необычный вариант в формате PNG? Какие изменения мне нужно будет сделать, чтобы правильно просматривать такие PNG?
file-format
image
Джеймс Таубер
источник
источник
Ответы:
Вот «восстановленные» изображения, благодаря дальнейшим исследованиям Тильберга:
Как и ожидалось, 5-байтовый маркер блока примерно каждые 0x4020 байт. Формат выглядит следующим образом:
После считывания маркера следующие
marker.len
байты образуют блок, который является частью файла.marker.notlen
контрольная переменная такая, чтоmarker.len + marker.notlen == 0xffff
. Последний блок таков, чтоmarker.tag == 1
.Структура, вероятно, следующая. Есть еще неизвестные значения.
Я не понял, что в конце, но, так как PNG допускают заполнение, это не слишком драматично. Однако размер закодированного файла ясно указывает на то, что последние 4 байта следует игнорировать ...
Поскольку у меня не было доступа ко всем маркерам блоков непосредственно перед началом файла, я написал этот декодер, который запускается в конце и пытается найти маркеры блоков. Это совсем не надежно, но хорошо, это работает для ваших тестовых изображений:
Старые исследования
Вот что вы получаете, удаляя байт
0x4022
из второго изображения, затем удаляя байт0x8092
:Это действительно не «восстанавливает» изображения; Я сделал это методом проб и ошибок. Однако, это говорит о том, что каждые 16384 байта появляются непредвиденные данные. Я предполагаю, что изображения упакованы в некую структуру файловой системы, а неожиданные данные - это просто маркеры блоков, которые вы должны удалить при чтении данных.
Я не знаю, где именно находятся маркеры блоков и их размер, но сам размер блока, безусловно, составляет 2 ^ 14 байт.
Было бы полезно, если бы вы также могли предоставить шестнадцатеричный дамп (несколько десятков байт) того, что появляется прямо перед изображением и сразу после него. Это даст подсказки о том, какая информация хранится в начале или конце блоков.
Конечно, есть вероятность того, что в вашем коде извлечения есть ошибка. Если вы используете буфер 16384 байта для файловых операций, я сначала проверил бы там.
источник
По предложению Сэма я разбудил код Джеймса по адресу https://github.com/tillberg/skyrim и смог успешно извлечь n_letter.png из файла BSA Skyrim Textures.
«File_size», заданный заголовками BSA, не является фактическим конечным размером файла. Он включает в себя некоторую информацию заголовка, а также некоторые случайные куски бесполезных данных, разбросанных по всему.
Заголовки выглядят примерно так:
Чтобы удалить байты заголовка, я сделал это:
Оттуда начинается фактический файл PNG. Это легко проверить по 8-байтовой последовательности запуска PNG.
Я попытался выяснить, где расположены дополнительные байты, прочитав заголовки PNG и сравнив длину, переданную в блоке IDAT, с подразумеваемой длиной данных, полученной в результате измерения количества байтов до блока IEND. (подробности смотрите в файле bsa.py на github)
Размеры, указанные кусками в n_letter.png:
Когда я измерил фактическое расстояние между блоком IDAT и блоком IEND после него (подсчитав байты с помощью string.find () в Python), я обнаружил, что фактическая подразумеваемая длина IDAT составляла 60640 байтов - там было еще 15 байтов ,
Как правило, в большинстве «буквенных» файлов присутствуют дополнительные 5 байтов на каждые 16 КБ общего размера файла. Например, o_letter.png, размером около 73 КБ, имеет дополнительные 20 байтов. Большие файлы, такие как тайные каракули, в основном следовали той же схеме, хотя в некоторых добавлялись нечетные суммы (52 байта, 12 байтов или 32 байта). Понятия не имею, что там происходит.
Для файла n_letter.png мне удалось найти правильные смещения (в основном методом проб и ошибок), при которых удаляются 5-байтовые сегменты.
Удалены пять байтовых сегментов:
Что бы это ни стоило, я включил последние пять байтов неизвестного 12-байтового сегмента из-за некоторого сходства с другими последовательностями.
Оказывается, они не совсем каждые 16KB, но с интервалом ~ 0x4030 байтов.
Чтобы не допустить получения близких, но не идеальных совпадений в приведенных выше индексах, я также проверил декомпрессию zlib фрагмента IDAT из полученного PNG, и он прошел.
источник
На самом деле прерывистые 5 байтов являются частью сжатия zlib.
Как подробно описано на http://drj11.wordpress.com/2007/11/20/a-use-for-uncompressed-pngs/ ,
.. таким образом, 00 указывает «следующий» блок (не конечный), а 4 следующих байта - это длина блока и его инверсия.
[Править] Более надежным источником является, конечно, RFC 1951 (Deflate Compressed Data Format Specification), раздел 3.2.4.
источник
Возможно ли, что вы читаете данные из файла в текстовом режиме (где окончания строк, которые появляются в данных PNG, возможно, искажены), а не в двоичном режиме?
источник
libpng
читает PNG Skyrim? Другими словами, это просто ошибка в вашем PNG-загрузчике?