Если вы не загружаете png или что-то еще, формат ведет себя довольно разумно, просто напишите его. Тогда ваш код не нуждается в PIL или какой-либо головной боли при различных операциях импорта и импорта при импорте и т. Д.
import struct
import zlib
from math import ceil
def write_png_1bit(buf, width, height, stride=None):
if stride is None:
stride = int(ceil(width / 8))
raw_data = b"".join(
b'\x00' + buf[span:span + stride] for span in range(0, (height - 1) * stride, stride))
def png_pack(png_tag, data):
chunk_head = png_tag + data
return struct.pack("!I", len(data)) + chunk_head + struct.pack("!I", 0xFFFFFFFF & zlib.crc32(chunk_head))
return b"".join([
b'\x89PNG\r\n\x1a\n',
png_pack(b'IHDR', struct.pack("!2I5B", width, height, 1, 0, 0, 0, 0)),
png_pack(b'IDAT', zlib.compress(raw_data, 9)),
png_pack(b'IEND', b'')])
Адаптировано из:
http://code.activestate.com/recipes/577443-write-a-png-image-in-native-python/ (MIT)
, прочитав спецификацию png:
https://www.w3.org/TR/PNG-Chunks.html
Имейте в виду, что 1-битные данные из buf должны записываться слева направо, как спецификация png, в обычном режиме без чередования (который мы объявили). И избыточные данные дополняют последний бит, если он существует, и шаг - это количество байтов, необходимое для кодирования строки сканирования. Кроме того, если вы хотите, чтобы эти 1 бит имели цвета палитры, вам нужно написать блок PLTE и переключить тип на 3, а не на 0. И т. Д.