PIL - 在内存中保存文件?

PIL - saving file in memory?

我只想打开文件夹中的图像文件,如果它们不是 jpeg,则将它们转换为 jpeg。唯一的问题是我需要将文件保存在内存中,而不是归档。原因是,实际上我正在从 tfrecod 文件(tensorflow 数据文件格式)中读取图像,从中提取图像,检查文件格式,如果不是 jpeg,则转换为 jpeg,然后在正确解码后写回 tfrecord 文件.因为 tensorflow object detection api 不接受除 jpeg 之外的任何图像格式。无论如何,这就是我需要它的原因。

为了能够做到这一点,我需要将文件保存在内存中。所以这是我的代码:

for counter, filename_with_path in enumerate(filenames):
    e = next(iter(tf.data.TFRecordDataset([filename_with_path])))
    example = tf.train.Example()
    example.ParseFromString(e.numpy())
    parsed = example.features.feature
    image_raw = parsed['image/encoded'].bytes_list.value[0]

    # After this point is important
    stream = BytesIO(image_raw)
    image = Image.open(stream) # Image is pillow image
    stream.close()

    if image.format != 'JPEG':
        tempFile = BytesIO()
        image.convert('RGB')
        image.save(tempFile, format="JPEG")

        newStream = BytesIO(tempFile)
        img = Image.open(newStream)
        newStream.close()

        print(filename, image.format)
        print(filename, img.format)

当我运行这个的时候,我得到ValueError: I/O operation on closed file.在线

image.save(tempFile, format="JPEG")

知道为什么会出错吗?我将此视为写入内存文件的建议方式:How to write PNG image to string with the PIL?

错误不是关于 tempFile,而是关于 stream。在完成 image 之前,您不应该执行 stream.close()。这是一个惰性API,因此它可以更有效地处理大图像。

for counter, filename_with_path in enumerate(filenames):
    ...

    stream = BytesIO(image_raw)
    image = Image.open(stream) # Image is pillow image
    # remove this line:
    # stream.close()

    if image.format != 'JPEG':
        tempFile = BytesIO()
        image.convert('RGB')
        image.save(tempFile, format="JPEG")

        # this wants bytes, not another BytesIO object, so read it
        newStream = BytesIO(tempFile.read())
        img = Image.open(newStream)
        # same thing, don't close until you are done with img
        # newStream.close()

        print(filename, image.format)
        print(filename, img.format)

来自枕头的Image.open docs

This is a lazy operation; this function identifies the file, but the file remains open and the actual image data is not read from the file until you try to process the data (or call the load() method).