为Python3调整工作代码会生成一个空白的PNG



我使用的是这篇文章中的以下代码(几乎没有修改)。这个脚本只是取一个十六进制颜色的数组,并从中写出一个PNG图像。我正试图将其调整为Py3,但出现了问题。

import zlib, struct
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)))
def write_png(buf, width, height):
    # reverse the vertical line order and add null bytes at the start
    width_byte_4 = width * 4
    raw_data = b''.join(b'x00' + buf[span:span + width_byte_4]
                        for span in range((height - 1) * width * 4, -1, - width_byte_4))
    return b''.join([
        b'x89PNGrnx1an',
        png_pack(b'IHDR', struct.pack("!2I5B", width, height, 8, 6, 0, 0, 0)),
        png_pack(b'IDAT', zlib.compress(raw_data, 9)),
        png_pack(b'IEND', b'')])

def saveAsPNG(array, filename):
    import struct
    if any([len(row) != len(array[0]) for row in array]):
        raise ValueError("Array should have elements of equal size")
    #First row becomes top row of image.
    flat = []
    map(flat.extend, reversed(array))
    #Big-endian, unsigned 32-byte integer.
    buf = b''.join([struct.pack('>I', ((0xffFFff & i32)<<8)|(i32>>24) )
                    for i32 in flat])   #Rotate from ARGB to RGBA.
    #print(type(buf))
    data = write_png(buf, len(array[0]), len(array))
    f = open(filename, 'wb')
    f.write(data)
    f.close()

saveAsPNG([[0xffFF0000, 0xffFFFF00],
           [0xff00aa77, 0xff333333]], 'test.png')

它与Python 2.7完美配合,并且在Python 3上运行时不会引发任何错误。然而,生成的图像是空的。。。我搞不清出了什么问题。我试着用starmap代替map,但没有任何改变。我已经检查过bufbytes而不是string,事实确实如此。我真的不知道为什么它不能正确写入文件。有线索吗?

在Python 2中,map返回一个列表。在Python3中,map返回一个映射对象:

print(type(map(flat.extend, reversed(array))))
# <class 'map'>

map对象是一个迭代器。它在迭代之前不会调用flat.extend。由于没有使用任何变量来保存映射对象,因此它将被丢弃,并且flat仍然是一个空列表。

所以你需要:

flat = []
for item in reversed(array):
    flat.extend(item)

或列表理解:

flat = [item for arr in reversed(array) for item in arr]

或itertools.chain.from_interable:

import itertools as IT
flat = IT.chain.from_iterable(reversed(array))

map的副作用不应使用。它应该只用于在Python2中生成列表,或者在Python3中生成迭代器。

在Python 2中,使用map作为副作用是一种不受欢迎的做法。在Python3中,通过使map成为迭代器,在某种程度上"强制"了该策略。

最新更新