Если вы планируете «извлекать» данные PNG вручную, рекомендуется оставить браузер открытым в соответствии с официальными спецификациями . Пиксельные данные изображений PNG сжимаются, как объяснено в 10. Сжатие . После распаковки вы получите поток двоичных данных, состоящий из высота прогонов, каждый из которых имеет filter_type + ширина × pixel_data (где ширина и высота прямо определены в блоке IHDR
, и точный формат pixel_data - битовая глубина и альфа - должен быть получен из Цветового типа флаг IHDR
.
Таким образом, шаг 1 должен использовать zlib
для распаковки двоичного фрагмента. После распаковки вы получите 16 × (1 + 16) = 272 байта.
Следующим шагом является итерация по строкам и применение метода фильтрации каждой строки, чтобы (наконец!) Получить список фактических значений в формате, определяемом Color Type.
Каждый из типов фильтров использует в качестве входных данных ранее декодированную строку (номер строки -1 считается всеми нулями), к которой применяется функция с новыми байтами. К счастью, ваше примерное изображение использует только фильтр строк № 0: нет, что самый простой в реализации, поскольку он заменяет только старое значение новым. Для более полного PNG-декодера вам потребуется реализовать все 4 фильтра.
Это приводит к следующему:
elif chunkType == "IDAT":
print(chunkType)
chunkDataBin=zlib.decompress(bytes.fromhex(chunkDataHex))
print (len(chunkDataBin))
# create the initial (empty) row
processRow = [0] * width
for y in range(height):
rowFilter = chunkDataBin[y*(width+1)]
print ("Row Filter: %d; pixel data " % rowFilter, end='')
for x in range(width):
colorIndex = chunkDataBin[y*(width+1)+1+x]
# process filters
# Filter: None
if rowFilter == 0:
processRow[x] = colorIndex
else:
# raise an error for not implemented filters
raise ValueError("Filter type %d is not implemented" % rowFilter)
for x in range(width):
print("%02X " % processRow[x], end='')
print ()
Обработка блока IDAT
, как только вы столкнетесь с ним работает для вашего тестового файла, но в соответствии со спецификациями может быть несколько IDAT
кусков. Правильный способ справиться с этим - сохранить глобальный объект, к которому вы объединяете все встречающиеся куски IDAT
(они также должны быть последовательными). Только после того, как вы объедините их все в один поток, вы можете использовать zlib
для распаковки.