【问题标题】:Adapting working code for Python 3 produces a blank PNG为 Python 3 调整工作代码会生成一个空白 PNG
【发布时间】:2015-07-01 10:56:19
【问题描述】:

我正在使用来自this post 的以下代码(几乎没有修改)。该脚本只需要一个十六进制颜色数组并从中写入一个 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'\x89PNG\r\n\x1a\n',
        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,它是。我真的不知道为什么它不能正确写入文件。 有什么线索吗?

【问题讨论】:

    标签: arrays python-3.x png


    【解决方案1】:

    在 Python2 中,map 返回一个列表。在 Python3 中,map returns a map object:

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

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

    所以你需要:

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

    list comprehension:

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

    itertools.chain.from_iterable:

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

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

    在 Python2 中,使用 map 作为其副作用是一种不受欢迎的做法。在 Python3 中,通过使 map 成为迭代器,该策略在某种程度上是“强制执行的”。

    【讨论】:

    • 非常感谢!我知道我错过了一些微不足道的东西。下次一定会记住地图的。
    猜你喜欢
    • 1970-01-01
    • 2017-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    • 2014-07-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多